# LANGUAGE LambdaCase , QuasiQuotes , OverloadedStrings #
module PrimOpArraySpec where

import qualified Data.Text as Text
import qualified Data.Map as Map
import qualified Data.Set as Set
import Data.List (sort)
import Data.IORef
import Test.Hspec
import Test.QuickCheck
import System.IO
import Text.Show.Pretty (pPrint, ppShow)
import Text.PrettyPrint.ANSI.Leijen

import Lambda.TH
import Lambda.ControlFlowAnalysisM
import Grin.Pretty (PP(..))

runTests :: IO ()
runTests = hspec spec

spec :: Spec
spec = do
  ----------------------------
  usedRules <- runIO $ newIORef (Set.empty :: Set.Set [Text.Text])

  let filterAndSort keys m = fmap sort $ Map.restrictKeys m (Set.fromList keys)

      sameAs :: Show a => a -> a -> IO ()
      sameAs a b = (PP (ppShow a)) `shouldBe` (PP (ppShow b))

      toArrOp = filterAndSort ["NodeOrigin", "ExternalOrigin", "TagValue", "Array"]
      addUsedM a = modifyIORef usedRules (\x -> mappend x . Set.fromList . head . Map.elems . filterAndSort ["Used"] $ a)
      printUsedM = readIORef usedRules >>= pPrint

  ----------------------------

   primop effectful 
     + " newArray # " : : T_Int64 - > % a - > { " State # " % s } - > { " GHC.Prim . Unit # " { " MutableArray # " % s % a } } 

   primop pure 
     - " sameMutableArray # " : : { " MutableArray # " % s % a } - > { " MutableArray # " % s % a } - > T_Int64 

   primop effectful 
     + " readArray # "   : : { " MutableArray # " % s % a } - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . Unit # " % a } 
     + " writeArray # " : : { " MutableArray # " % s % a } - > T_Int64 - > % a - > { " State # " % s } - > { " GHC.Prim . ( # # ) " } 

   primop pure 
     - " sizeofArray # "         : : { " Array # " % a } - > T_Int64 
     - " sizeofMutableArray # " : : { " MutableArray # " % s % a } - > T_Int64 
     + " indexArray # "          : : { " Array # " % a } - > T_Int64 - > { " GHC.Prim . Unit # " % a } 

   primop effectful 
     + " unsafeFreezeArray # " : : { " MutableArray # " % s % a } - > { " State # " % s } - > { " GHC.Prim . Unit # " { " Array # " % a } } 
     + " unsafeThawArray # "    : : { " Array # " % a } - > { " State # " % s } - > { " GHC.Prim . Unit # " { " MutableArray # " % s % a } } 
     + " copyArray # "          : : { " Array # " % a } - > T_Int64 - > { " MutableArray # " % s % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . ( # # ) " } 
     + " copyMutableArray # "   : : { " MutableArray # " % s % a } - > T_Int64 - > { " MutableArray # " % s % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . ( # # ) " } 
     + " cloneArray # "         : : { " Array # " % a } - > T_Int64 - > T_Int64 - > { " Array # " % a } 
     + " cloneMutableArray # " : : { " MutableArray # " % s % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . Unit # " { " MutableArray # " % s % a } } 
     + " freezeArray # "        : : { " MutableArray # " % s % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . Unit # " { " Array # " % a } } 
     + " thawArray # "          : : { " Array # " % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . Unit # " { " MutableArray # " % s % a } } 
     + " casArray # "           : : { " MutableArray # " % s % a } - > T_Int64 - > % a - > % a - > { " State # " % s } - > { " GHC.Prim . ( # , # ) " T_Int64 % a } 

   Small Arrays 

   primop effectful 
     + " newSmallArray # " : : T_Int64 - > % a - > { " State # " % s } - > { " GHC.Prim . Unit # " { " SmallMutableArray # " % s % a } } 

   primop pure 
     - " sameSmallMutableArray # " : : { " SmallMutableArray # " % s % a } - > { " SmallMutableArray # " % s % a } - > T_Int64 

   primop effectful 
     + " readSmallArray # "   : : { " SmallMutableArray # " % s % a } - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . Unit # " % a } 
     + " writeSmallArray # " : : { " SmallMutableArray # " % s % a } - > T_Int64 - > % a - > { " State # " % s } - > { " GHC.Prim . ( # # ) " } 

   primop pure 
     - " sizeofSmallArray # "         : : { " SmallArray # " % a } - > T_Int64 
     - " sizeofSmallMutableArray # " : : { " SmallMutableArray # " % s % a } - > T_Int64 
     + " indexSmallArray # "          : : { " SmallArray # " % a } - > T_Int64 - > { " GHC.Prim . Unit # " % a } 

   primop effectful 
     + " unsafeFreezeSmallArray # " : : { " SmallMutableArray # " % s % a } - > { " State # " % s } - > { " GHC.Prim . Unit # " { " SmallArray # " % a } } 
     + " unsafeThawSmallArray # "    : : { " SmallArray # " % a } - > { " State # " % s } - > { " GHC.Prim . Unit # " { " SmallMutableArray # " % s % a } } 
     + " copySmallArray # "          : : { " SmallArray # " % a } - > T_Int64 - > { " SmallMutableArray # " % s % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . ( # # ) " } 
     + " copySmallMutableArray # "   : : { " SmallMutableArray # " % s % a } - > T_Int64 - > { " SmallMutableArray # " % s % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . ( # # ) " } 
     + " cloneSmallArray # "         : : { " SmallArray # " % a } - > T_Int64 - > T_Int64 - > { " SmallArray # " % a } 
     + " cloneSmallMutableArray # " : : { " SmallMutableArray # " % s % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . Unit # " { " SmallMutableArray # " % s % a } } 
     + " freezeSmallArray # "        : : { " SmallMutableArray # " % s % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . Unit # " { " SmallArray # " % a } } 
     + " thawSmallArray # "          : : { " SmallArray # " % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . Unit # " { " SmallMutableArray # " % s % a } } 
     + " casSmallArray # "           : : { " SmallMutableArray # " % s % a } - > T_Int64 - > % a - > % a - > { " State # " % s } - > { " GHC.Prim . ( # , # ) " T_Int64 % a } 

  primop effectful
    + "newArray#" :: T_Int64 -> %a -> {"State#" %s} -> {"GHC.Prim.Unit#" {"MutableArray#" %s %a}}

  primop pure
    - "sameMutableArray#" :: {"MutableArray#" %s %a} -> {"MutableArray#" %s %a} -> T_Int64

  primop effectful
    + "readArray#"  :: {"MutableArray#" %s %a} -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.Unit#" %a}
    + "writeArray#" :: {"MutableArray#" %s %a} -> T_Int64 -> %a -> {"State#" %s} -> {"GHC.Prim.(##)"}

  primop pure
    - "sizeofArray#"        :: {"Array#" %a} -> T_Int64
    - "sizeofMutableArray#" :: {"MutableArray#" %s %a} -> T_Int64
    + "indexArray#"         :: {"Array#" %a} -> T_Int64 -> {"GHC.Prim.Unit#" %a}

  primop effectful
    + "unsafeFreezeArray#" :: {"MutableArray#" %s %a} -> {"State#" %s} -> {"GHC.Prim.Unit#" {"Array#" %a}}
    + "unsafeThawArray#"   :: {"Array#" %a} -> {"State#" %s} -> {"GHC.Prim.Unit#" {"MutableArray#" %s %a}}
    + "copyArray#"         :: {"Array#" %a} -> T_Int64 -> {"MutableArray#" %s %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.(##)"}
    + "copyMutableArray#"  :: {"MutableArray#" %s %a} -> T_Int64 -> {"MutableArray#" %s %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.(##)"}
    + "cloneArray#"        :: {"Array#" %a} -> T_Int64 -> T_Int64 -> {"Array#" %a}
    + "cloneMutableArray#" :: {"MutableArray#" %s %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.Unit#" {"MutableArray#" %s %a}}
    + "freezeArray#"       :: {"MutableArray#" %s %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.Unit#" {"Array#" %a}}
    + "thawArray#"         :: {"Array#" %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.Unit#" {"MutableArray#" %s %a}}
    + "casArray#"          :: {"MutableArray#" %s %a} -> T_Int64 -> %a -> %a -> {"State#" %s} -> {"GHC.Prim.(#,#)" T_Int64 %a}

  Small Arrays

  primop effectful
    + "newSmallArray#" :: T_Int64 -> %a -> {"State#" %s} -> {"GHC.Prim.Unit#" {"SmallMutableArray#" %s %a}}

  primop pure
    - "sameSmallMutableArray#" :: {"SmallMutableArray#" %s %a} -> {"SmallMutableArray#" %s %a} -> T_Int64

  primop effectful
    + "readSmallArray#"  :: {"SmallMutableArray#" %s %a} -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.Unit#" %a}
    + "writeSmallArray#" :: {"SmallMutableArray#" %s %a} -> T_Int64 -> %a -> {"State#" %s} -> {"GHC.Prim.(##)"}

  primop pure
    - "sizeofSmallArray#"        :: {"SmallArray#" %a} -> T_Int64
    - "sizeofSmallMutableArray#" :: {"SmallMutableArray#" %s %a} -> T_Int64
    + "indexSmallArray#"         :: {"SmallArray#" %a} -> T_Int64 -> {"GHC.Prim.Unit#" %a}

  primop effectful
    + "unsafeFreezeSmallArray#" :: {"SmallMutableArray#" %s %a} -> {"State#" %s} -> {"GHC.Prim.Unit#" {"SmallArray#" %a}}
    + "unsafeThawSmallArray#"   :: {"SmallArray#" %a} -> {"State#" %s} -> {"GHC.Prim.Unit#" {"SmallMutableArray#" %s %a}}
    + "copySmallArray#"         :: {"SmallArray#" %a} -> T_Int64 -> {"SmallMutableArray#" %s %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.(##)"}
    + "copySmallMutableArray#"  :: {"SmallMutableArray#" %s %a} -> T_Int64 -> {"SmallMutableArray#" %s %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.(##)"}
    + "cloneSmallArray#"        :: {"SmallArray#" %a} -> T_Int64 -> T_Int64 -> {"SmallArray#" %a}
    + "cloneSmallMutableArray#" :: {"SmallMutableArray#" %s %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.Unit#" {"SmallMutableArray#" %s %a}}
    + "freezeSmallArray#"       :: {"SmallMutableArray#" %s %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.Unit#" {"SmallArray#" %a}}
    + "thawSmallArray#"         :: {"SmallArray#" %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.Unit#" {"SmallMutableArray#" %s %a}}
    + "casSmallArray#"          :: {"SmallMutableArray#" %s %a} -> T_Int64 -> %a -> %a -> {"State#" %s} -> {"GHC.Prim.(#,#)" T_Int64 %a}
-}
  describe "GHC Array PrimOps" $ do

    it "newArray#" $ do
      cfa <- controlFlowAnalysisM ["main"] [prog|
          primop effectful
            "newArray#" :: (T_Int64) @ t.106 -> %a.6 -> {"State#" %s.2} @ t.107 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.2 %a.6} @ t.109} @ t.108
          main =
            letS
              v00 = #T_Int64 10
              v01 = [Tup0]
              v02 = #T_Token "RealWorld"
              v03 = "newArray#" $ v00 v01 v02
              v05 = case v03 of
                ("GHC.Prim.Unit#" v04) @ a00 ->
                  v04
            v05
        |]
      addUsedM cfa
      toArrOp cfa `sameAs` Map.fromList
        [ ( "Array" , [ [ "v03" , "t.109" , "v01" ] ] )
        , ( "ExternalOrigin"
          , [ [ "a00" , "v03" , "t.108" ]
            , [ "v03" , "v03" , "t.108" ]
            , [ "v04" , "v03" , "t.109" ]
            , [ "v05" , "v03" , "t.109" ]
            ]
          )
        , ( "NodeOrigin"
          , [ [ "v00" , "v00" ]
            , [ "v01" , "v01" ]
            , [ "v02" , "v02" ]
            ]
          )
        , ( "TagValue"
          , [ [ "a00" , "GHC.Prim.Unit#" ]
            , [ "v00" , "lit:T_Int64" ]
            , [ "v01" , "Tup0" ]
            , [ "v02" , "lit:T_Token \"RealWorld\"" ]
            , [ "v03" , "GHC.Prim.Unit#" ]
            , [ "v04" , "MutableArray#" ]
            , [ "v05" , "MutableArray#" ]
            ]
          )
        ]

    it "readArray#" $ do
      cfa <- controlFlowAnalysisM ["main"] [prog|
          primop effectful
            "newArray#" :: (T_Int64) @ t.106 -> %a.6 -> {"State#" %s.2} @ t.107 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.2 %a.6} @ t.109} @ t.108
            "readArray#" :: {"MutableArray#" %s.21 %a.11} @ t.243 -> (T_Int64) @ t.244 -> {"State#" %s.21} @ t.245 -> {"GHC.Prim.Unit#" %a.11} @ t.246
          main =
            letS
              v00 = #T_Int64 10
              v01 = [Tup0]
              v02 = #T_Token "RealWorld"
              v03 = "newArray#" $ v00 v01 v02
              v09 = case v03 of
                ("GHC.Prim.Unit#" v04) @ a00 ->
                  letS
                    v05 = #T_Int64 0
                    v06 = "readArray#" $ v04 v05 v02
                    v08 = case v06 of
                      ("GHC.Prim.Unit#" v07) @ a01 ->
                        v07
                  v08
            v09
        |]
      addUsedM cfa
      toArrOp cfa `sameAs` Map.fromList
        [ ( "Array" , [ [ "v03" , "t.109" , "v01" ] ] )
        , ( "ExternalOrigin"
          , [ [ "a00" , "v03" , "t.108" ]
            , [ "a01" , "v06" , "t.246" ]
            , [ "v03" , "v03" , "t.108" ]
            , [ "v04" , "v03" , "t.109" ]
            , [ "v06" , "v06" , "t.246" ]
            , [ "v07" , "v06" , "a.11" ]
            , [ "v08" , "v06" , "a.11" ]
            , [ "v09" , "v06" , "a.11" ]
            ]
          )
        , ( "NodeOrigin"
          , [ [ "v00" , "v00" ]
            , [ "v01" , "v01" ]
            , [ "v02" , "v02" ]
            , [ "v05" , "v05" ]
            , [ "v07" , "v01" ]
            , [ "v08" , "v01" ]
            , [ "v09" , "v01" ]
            ]
          )
        , ( "TagValue"
          , [ [ "a00" , "GHC.Prim.Unit#" ]
            , [ "a01" , "GHC.Prim.Unit#" ]
            , [ "v00" , "lit:T_Int64" ]
            , [ "v01" , "Tup0" ]
            , [ "v02" , "lit:T_Token \"RealWorld\"" ]
            , [ "v03" , "GHC.Prim.Unit#" ]
            , [ "v04" , "MutableArray#" ]
            , [ "v05" , "lit:T_Int64" ]
            , [ "v06" , "GHC.Prim.Unit#" ]
            , [ "v07" , "Tup0" ]
            , [ "v08" , "Tup0" ]
            , [ "v09" , "Tup0" ]
            ]
          )
        ]

    it "writeArray#" $ do
      cfa <- controlFlowAnalysisM ["main"] [prog|
          primop effectful
            "newArray#"   :: (T_Int64) @ t.106 -> %a.6 -> {"State#" %s.2} @ t.107 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.2 %a.6} @ t.109} @ t.108
            "writeArray#" :: {"MutableArray#" %s.4 %a.9} @ t.115 -> (T_Int64) @ t.116 -> %a.9 -> {"State#" %s.4} @ t.117 -> {"GHC.Prim.(##)"} @ t.118
          main =
            letS
              v00 = #T_Int64 10
              v01 = [Tup0]
              v02 = #T_Token "RealWorld"
              v03 = "newArray#" $ v00 v01 v02
              v09 = case v03 of
                ("GHC.Prim.Unit#" v04) @ a00 ->
                  letS
                    v05 = #T_Int64 0
                    v06 = [C1]
                    v07 = v06
                    v08 = "writeArray#" $ v04 v05 v07 v02
                  v08
            v09
        |]
      addUsedM cfa
      toArrOp cfa `sameAs` Map.fromList
        [ ( "Array"
          , [ [ "v03" , "t.109" , "v01" ]
            , [ "v03" , "t.109" , "v07" ]
            ]
          )
        , ( "ExternalOrigin"
          , [ [ "a00" , "v03" , "t.108" ]
            , [ "v03" , "v03" , "t.108" ]
            , [ "v04" , "v03" , "t.109" ]
            , [ "v08" , "v08" , "t.118" ]
            , [ "v09" , "v08" , "t.118" ]
            ]
          )
        , ( "NodeOrigin"
          , [ [ "v00" , "v00" ]
            , [ "v01" , "v01" ]
            , [ "v02" , "v02" ]
            , [ "v05" , "v05" ]
            , [ "v06" , "v06" ]
            , [ "v07" , "v06" ]
            ]
          )
        , ( "TagValue"
          , [ [ "a00" , "GHC.Prim.Unit#" ]
            , [ "v00" , "lit:T_Int64" ]
            , [ "v01" , "Tup0" ]
            , [ "v02" , "lit:T_Token \"RealWorld\"" ]
            , [ "v03" , "GHC.Prim.Unit#" ]
            , [ "v04" , "MutableArray#" ]
            , [ "v05" , "lit:T_Int64" ]
            , [ "v06" , "C1" ]
            , [ "v07" , "C1" ]
            , [ "v08" , "GHC.Prim.(##)" ]
            , [ "v09" , "GHC.Prim.(##)" ]
            ]
          )
        ]

    it "unsafeFreezeArray#" $ do
      cfa <- controlFlowAnalysisM ["main"] [prog|
          primop effectful
            "newArray#"           :: (T_Int64) @ t.00 -> %a.01 -> {"State#" %s.02} @ t.03 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.02 %a.01} @ t.04} @ t.05
            "unsafeFreezeArray#"  :: {"MutableArray#" %s.10 %a.11} @ t.12 -> {"State#" %s.10} @ t.13 -> {"GHC.Prim.Unit#" {"Array#" %a.11} @ t.14} @ t.15
          main =
            letS
              v00 = #T_Int64 10
              v01 = [Tup0]
              v02 = #T_Token "RealWorld"
              v03 = "newArray#" $ v00 v01 v02
              v08 = case v03 of
                ("GHC.Prim.Unit#" v04) @ a00 ->
                  letS
                    v05 = "unsafeFreezeArray#" $ v04 v02
                    v07 = case v05 of
                      ("GHC.Prim.Unit#" v06) @ a01 ->
                        v06
                  v07
            v08
        |]
      addUsedM cfa
      toArrOp cfa `sameAs` Map.fromList
        [ ( "Array"
          , [ [ "v03" , "t.04" , "v01" ]
            ]
          )
        , ( "ExternalOrigin"
          , [ [ "a00" , "v03" , "t.05" ]
            , [ "a01" , "v05" , "t.15" ]
            , [ "v03" , "v03" , "t.05" ]
            , [ "v04" , "v03" , "t.04" ]
            , [ "v05" , "v05" , "t.15" ]
            , [ "v06" , "v03" , "t.04" ]
            , [ "v06" , "v05" , "t.14" ]
            , [ "v07" , "v03" , "t.04" ]
            , [ "v07" , "v05" , "t.14" ]
            , [ "v08" , "v03" , "t.04" ]
            , [ "v08" , "v05" , "t.14" ]
            ]
          )
        , ( "NodeOrigin"
          , [ [ "v00" , "v00" ]
            , [ "v01" , "v01" ]
            , [ "v02" , "v02" ]
            ]
          )
        , ( "TagValue"
          , [ [ "a00" , "GHC.Prim.Unit#" ]
            , [ "a01" , "GHC.Prim.Unit#" ]
            , [ "v00" , "lit:T_Int64" ]
            , [ "v01" , "Tup0" ]
            , [ "v02" , "lit:T_Token \"RealWorld\"" ]
            , [ "v03" , "GHC.Prim.Unit#" ]
            , [ "v04" , "MutableArray#" ]
            , [ "v05" , "GHC.Prim.Unit#" ]
            , [ "v06" , "Array#" ]
            , [ "v06" , "MutableArray#" ]
            , [ "v07" , "Array#" ]
            , [ "v07" , "MutableArray#" ]
            , [ "v08" , "Array#" ]
            , [ "v08" , "MutableArray#" ]
            ]
          )
        ]

    it "copyMutableArray#" $ do
      cfa <- controlFlowAnalysisM ["main"] [prog|
          primop effectful
            "newArray#"         :: (T_Int64) @ t.00 -> %a.01 -> {"State#" %s.02} @ t.03 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.02 %a.01} @ t.04} @ t.05
            "copyMutableArray#" :: {"MutableArray#" %s.10 %a.11} @ t.12 -> (T_Int64) @ t.13 -> {"MutableArray#" %s.10 %a.11} @ t.14 -> (T_Int64) @ t.15 -> (T_Int64) @ t.16 -> {"State#" %s.10} @ t.17 -> {"GHC.Prim.(##)"} @ t.18
          main =
            letS
              v00 = #T_Int64 10
              v01 = [Tup0]
              v02 = #T_Token "RealWorld"
              v03 = "newArray#" $ v00 v01 v02
              v11 = case v03 of
                ("GHC.Prim.Unit#" v04) @ a00 ->
                  letS
                    v05 = [C1]
                    v06 = "newArray#" $ v00 v05 v02
                    v10 = case v06 of
                      ("GHC.Prim.Unit#" v07) @ a01 ->
                        letS
                          v08 = #T_Int64 0
                          v09 = "copyMutableArray#" $ v04 v08 v07 v08 v00 v02
                        v09
                  v10
            v11
        |]
      addUsedM cfa
      toArrOp cfa `sameAs` Map.fromList
        [ ( "Array"
          , [ [ "v03" , "t.04" , "v01" ]
            , [ "v06" , "t.04" , "v01" ]
            , [ "v06" , "t.04" , "v05" ]
            ]
          )
        , ( "ExternalOrigin"
          , [ [ "a00" , "v03" , "t.05" ]
            , [ "a01" , "v06" , "t.05" ]
            , [ "v03" , "v03" , "t.05" ]
            , [ "v04" , "v03" , "t.04" ]
            , [ "v06" , "v06" , "t.05" ]
            , [ "v07" , "v06" , "t.04" ]
            , [ "v09" , "v09" , "t.18" ]
            , [ "v10" , "v09" , "t.18" ]
            , [ "v11" , "v09" , "t.18" ]
            ]
          )
        , ( "NodeOrigin"
          , [ [ "v00" , "v00" ]
            , [ "v01" , "v01" ]
            , [ "v02" , "v02" ]
            , [ "v05" , "v05" ]
            , [ "v08" , "v08" ]
            ]
          )
        , ( "TagValue"
          , [ [ "a00" , "GHC.Prim.Unit#" ]
            , [ "a01" , "GHC.Prim.Unit#" ]
            , [ "v00" , "lit:T_Int64" ]
            , [ "v01" , "Tup0" ]
            , [ "v02" , "lit:T_Token \"RealWorld\"" ]
            , [ "v03" , "GHC.Prim.Unit#" ]
            , [ "v04" , "MutableArray#" ]
            , [ "v05" , "C1" ]
            , [ "v06" , "GHC.Prim.Unit#" ]
            , [ "v07" , "MutableArray#" ]
            , [ "v08" , "lit:T_Int64" ]
            , [ "v09" , "GHC.Prim.(##)" ]
            , [ "v10" , "GHC.Prim.(##)" ]
            , [ "v11" , "GHC.Prim.(##)" ]
            ]
          )
        ]

    it "cloneArray#" $ do
      cfa <- controlFlowAnalysisM ["main"] [prog|
          primop effectful
            "newArray#"           :: (T_Int64) @ t.00 -> %a.01 -> {"State#" %s.02} @ t.03 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.02 %a.01} @ t.04} @ t.05
            "unsafeFreezeArray#"  :: {"MutableArray#" %s.10 %a.11} @ t.12 -> {"State#" %s.10} @ t.13 -> {"GHC.Prim.Unit#" {"Array#" %a.11} @ t.14} @ t.15
            "cloneArray#"         :: {"Array#" %a.20} @ t.21 -> (T_Int64) @ t.22 -> (T_Int64) @ t.23 -> {"Array#" %a.20} @ t.24
          main =
            letS
              v00 = #T_Int64 10
              v01 = [Tup0]
              v02 = #T_Token "RealWorld"
              v03 = "newArray#" $ v00 v01 v02
              v10 = case v03 of
                ("GHC.Prim.Unit#" v04) @ a00 ->
                  letS
                    v05 = "unsafeFreezeArray#" $ v04 v02
                    v09 = case v05 of
                      ("GHC.Prim.Unit#" v06) @ a01 ->
                        letS
                          v07 = #T_Int64 0
                          v08 = "cloneArray#" $ v06 v07 v00
                        v08
                  v09
            v10
        |]
      addUsedM cfa
      toArrOp cfa `sameAs` Map.fromList
        [ ( "Array"
          , [ [ "v03" , "t.04" , "v01" ]
            , [ "v08" , "t.24" , "v01" ]
            ]
          )
        , ( "ExternalOrigin"
          , [ [ "a00" , "v03" , "t.05" ]
            , [ "a01" , "v05" , "t.15" ]
            , [ "v03" , "v03" , "t.05" ]
            , [ "v04" , "v03" , "t.04" ]
            , [ "v05" , "v05" , "t.15" ]
            , [ "v06" , "v03" , "t.04" ]
            , [ "v06" , "v05" , "t.14" ]
            , [ "v08" , "v08" , "t.24" ]
            , [ "v09" , "v08" , "t.24" ]
            , [ "v10" , "v08" , "t.24" ]
            ]
          )
        , ( "NodeOrigin"
          , [ [ "v00" , "v00" ]
            , [ "v01" , "v01" ]
            , [ "v02" , "v02" ]
            , [ "v07" , "v07" ]
            ]
          )
        , ( "TagValue"
          , [ [ "a00" , "GHC.Prim.Unit#" ]
            , [ "a01" , "GHC.Prim.Unit#" ]
            , [ "v00" , "lit:T_Int64" ]
            , [ "v01" , "Tup0" ]
            , [ "v02" , "lit:T_Token \"RealWorld\"" ]
            , [ "v03" , "GHC.Prim.Unit#" ]
            , [ "v04" , "MutableArray#" ]
            , [ "v05" , "GHC.Prim.Unit#" ]
            , [ "v06" , "Array#" ]
            , [ "v06" , "MutableArray#" ]
            , [ "v07" , "lit:T_Int64" ]
            , [ "v08" , "Array#" ]
            , [ "v09" , "Array#" ]
            , [ "v10" , "Array#" ]
            ]
          )
        ]

    it "cloneMutableArray#" $ do
      cfa <- controlFlowAnalysisM ["main"] [prog|
          primop effectful
            "newArray#"          :: (T_Int64) @ t.00 -> %a.01 -> {"State#" %s.02} @ t.03 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.02 %a.01} @ t.04} @ t.05
            "cloneMutableArray#" :: {"MutableArray#" %s.10 %a.11} @ t.12 -> (T_Int64) @ t.13 -> (T_Int64) @ t.14 -> {"State#" %s.10} @ t.15 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.10 %a.11} @ t.16} @ t.17
          main =
            letS
              v00 = #T_Int64 10
              v01 = [Tup0]
              v02 = #T_Token "RealWorld"
              v03 = "newArray#" $ v00 v01 v02
              v09 = case v03 of
                ("GHC.Prim.Unit#" v04) @ a00 ->
                  letS
                    v05 = #T_Int64 0
                    v06 = "cloneMutableArray#" $ v04 v05 v00 v02
                    v08 = case v06 of
                      ("GHC.Prim.Unit#" v07) @ a01 ->
                        v07
                  v08
            v09
        |]
      addUsedM cfa
      toArrOp cfa `sameAs` Map.fromList
        [ ( "Array"
          , [ [ "v03" , "t.04" , "v01" ]
            , [ "v06" , "t.16" , "v01" ]
            ]
          )
        , ( "ExternalOrigin"
          , [ [ "a00" , "v03" , "t.05" ]
            , [ "a01" , "v06" , "t.17" ]
            , [ "v03" , "v03" , "t.05" ]
            , [ "v04" , "v03" , "t.04" ]
            , [ "v06" , "v06" , "t.17" ]
            , [ "v07" , "v06" , "t.16" ]
            , [ "v08" , "v06" , "t.16" ]
            , [ "v09" , "v06" , "t.16" ]
            ]
          )
        , ( "NodeOrigin"
          , [ [ "v00" , "v00" ]
            , [ "v01" , "v01" ]
            , [ "v02" , "v02" ]
            , [ "v05" , "v05" ]
            ]
          )
        , ( "TagValue"
          , [ [ "a00" , "GHC.Prim.Unit#" ]
            , [ "a01" , "GHC.Prim.Unit#" ]
            , [ "v00" , "lit:T_Int64" ]
            , [ "v01" , "Tup0" ]
            , [ "v02" , "lit:T_Token \"RealWorld\"" ]
            , [ "v03" , "GHC.Prim.Unit#" ]
            , [ "v04" , "MutableArray#" ]
            , [ "v05" , "lit:T_Int64" ]
            , [ "v06" , "GHC.Prim.Unit#" ]
            , [ "v07" , "MutableArray#" ]
            , [ "v08" , "MutableArray#" ]
            , [ "v09" , "MutableArray#" ]
            ]
          )
        ]

    it "casArray#" $ do
      cfa <- controlFlowAnalysisM ["main"] [prog|
          primop effectful
            "newArray#" :: (T_Int64) @ t.00 -> %a.01 -> {"State#" %s.02} @ t.03 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.02 %a.01} @ t.04} @ t.05
            "casArray#" :: {"MutableArray#" %s.10 %a.11} @ t.12 -> (T_Int64) @ t.13 -> %a.11 -> %a.11 -> {"State#" %s.10} @ t.14 -> {"GHC.Prim.(#,#)" (T_Int64) @ t.15 %a.11} @ t.16
          main =
            letS
              v00 = #T_Int64 10
              v01 = [Tup0]
              v02 = #T_Token "RealWorld"
              v03 = "newArray#" $ v00 v01 v02
              v11 = case v03 of
                ("GHC.Prim.Unit#" v04) @ a00 ->
                  letS
                    v05 = #T_Int64 0
                    v06 = [C1]
                    v07 = "casArray#" $ v04 v05 v01 v06 v02
                    v10 = case v07 of
                      ("GHC.Prim.(#,#)" v08 v09) @ a01 ->
                        v08
                  v10
            v11
        |]
      addUsedM cfa
      toArrOp cfa `sameAs` Map.fromList
        [ ( "Array"
          , [ [ "v03" , "t.04" , "v01" ]
            , [ "v03" , "t.04" , "v06" ]
            ]
          )
        , ( "ExternalOrigin"
          , [ [ "a00" , "v03" , "t.05" ]
            , [ "a01" , "v07" , "t.16" ]
            , [ "v03" , "v03" , "t.05" ]
            , [ "v04" , "v03" , "t.04" ]
            , [ "v07" , "v07" , "t.16" ]
            , [ "v08" , "v07" , "t.15" ]
            , [ "v09" , "v07" , "a.11" ]
            , [ "v10" , "v07" , "t.15" ]
            , [ "v11" , "v07" , "t.15" ]
            ]
          )
        , ( "NodeOrigin"
          , [ [ "v00" , "v00" ]
            , [ "v01" , "v01" ]
            , [ "v02" , "v02" ]
            , [ "v05" , "v05" ]
            , [ "v06" , "v06" ]
            , [ "v09" , "v01" ]
            , [ "v09" , "v06" ]
            ]
          )
        , ( "TagValue"
          , [ [ "a00" , "GHC.Prim.Unit#" ]
            , [ "a01" , "GHC.Prim.(#,#)" ]
            , [ "v00" , "lit:T_Int64" ]
            , [ "v01" , "Tup0" ]
            , [ "v02" , "lit:T_Token \"RealWorld\"" ]
            , [ "v03" , "GHC.Prim.Unit#" ]
            , [ "v04" , "MutableArray#" ]
            , [ "v05" , "lit:T_Int64" ]
            , [ "v06" , "C1" ]
            , [ "v07" , "GHC.Prim.(#,#)" ]
            , [ "v08" , "lit:T_Int64" ]
            , [ "v09" , "C1" ]
            , [ "v09" , "Tup0" ]
            , [ "v10" , "lit:T_Int64" ]
            , [ "v11" , "lit:T_Int64" ]
            ]
          )
        ]

  describe "Coverage" $ do
    it "Used Rules" $ do
      printUsedM

--------------------------
--------------------------
# LANGUAGE LambdaCase , QuasiQuotes , OverloadedStrings #
module PrimOpArraySpec where

import qualified Data.Text as Text
import qualified Data.Map as Map
import qualified Data.Set as Set
import Data.List (sort)
import Data.IORef
import Test.Hspec
import Test.QuickCheck
import System.IO
import Text.Show.Pretty (pPrint, ppShow)
import Text.PrettyPrint.ANSI.Leijen

import Lambda.TH
import Lambda.ControlFlowAnalysisM
import Grin.Pretty (PP(..))

runTests :: IO ()
runTests = hspec spec

spec :: Spec
spec = do
  usedRules <- runIO $ newIORef (Set.empty :: Set.Set [Text.Text])

  let filterAndSort keys m = fmap sort $ Map.restrictKeys m (Set.fromList keys)

      sameAs :: Show a => a -> a -> IO ()
      sameAs a b = (PP (ppShow a)) `shouldBe` (PP (ppShow b))

      toArrOp = filterAndSort ["NodeOrigin", "ExternalOrigin", "TagValue", "Array"]
      addUsedM a = modifyIORef usedRules (\x -> mappend x . Set.fromList . head . Map.elems . filterAndSort ["Used"] $ a)
      printUsedM = readIORef usedRules >>= pPrint


   primop effectful 
     + " newArray # " : : T_Int64 - > % a - > { " State # " % s } - > { " GHC.Prim . Unit # " { " MutableArray # " % s % a } } 

   primop pure 
     - " sameMutableArray # " : : { " MutableArray # " % s % a } - > { " MutableArray # " % s % a } - > T_Int64 

   primop effectful 
     + " readArray # "   : : { " MutableArray # " % s % a } - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . Unit # " % a } 
     + " writeArray # " : : { " MutableArray # " % s % a } - > T_Int64 - > % a - > { " State # " % s } - > { " GHC.Prim . ( # # ) " } 

   primop pure 
     - " sizeofArray # "         : : { " Array # " % a } - > T_Int64 
     - " sizeofMutableArray # " : : { " MutableArray # " % s % a } - > T_Int64 
     + " indexArray # "          : : { " Array # " % a } - > T_Int64 - > { " GHC.Prim . Unit # " % a } 

   primop effectful 
     + " unsafeFreezeArray # " : : { " MutableArray # " % s % a } - > { " State # " % s } - > { " GHC.Prim . Unit # " { " Array # " % a } } 
     + " unsafeThawArray # "    : : { " Array # " % a } - > { " State # " % s } - > { " GHC.Prim . Unit # " { " MutableArray # " % s % a } } 
     + " copyArray # "          : : { " Array # " % a } - > T_Int64 - > { " MutableArray # " % s % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . ( # # ) " } 
     + " copyMutableArray # "   : : { " MutableArray # " % s % a } - > T_Int64 - > { " MutableArray # " % s % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . ( # # ) " } 
     + " cloneArray # "         : : { " Array # " % a } - > T_Int64 - > T_Int64 - > { " Array # " % a } 
     + " cloneMutableArray # " : : { " MutableArray # " % s % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . Unit # " { " MutableArray # " % s % a } } 
     + " freezeArray # "        : : { " MutableArray # " % s % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . Unit # " { " Array # " % a } } 
     + " thawArray # "          : : { " Array # " % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . Unit # " { " MutableArray # " % s % a } } 
     + " casArray # "           : : { " MutableArray # " % s % a } - > T_Int64 - > % a - > % a - > { " State # " % s } - > { " GHC.Prim . ( # , # ) " T_Int64 % a } 

   Small Arrays 

   primop effectful 
     + " newSmallArray # " : : T_Int64 - > % a - > { " State # " % s } - > { " GHC.Prim . Unit # " { " SmallMutableArray # " % s % a } } 

   primop pure 
     - " sameSmallMutableArray # " : : { " SmallMutableArray # " % s % a } - > { " SmallMutableArray # " % s % a } - > T_Int64 

   primop effectful 
     + " readSmallArray # "   : : { " SmallMutableArray # " % s % a } - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . Unit # " % a } 
     + " writeSmallArray # " : : { " SmallMutableArray # " % s % a } - > T_Int64 - > % a - > { " State # " % s } - > { " GHC.Prim . ( # # ) " } 

   primop pure 
     - " sizeofSmallArray # "         : : { " SmallArray # " % a } - > T_Int64 
     - " sizeofSmallMutableArray # " : : { " SmallMutableArray # " % s % a } - > T_Int64 
     + " indexSmallArray # "          : : { " SmallArray # " % a } - > T_Int64 - > { " GHC.Prim . Unit # " % a } 

   primop effectful 
     + " unsafeFreezeSmallArray # " : : { " SmallMutableArray # " % s % a } - > { " State # " % s } - > { " GHC.Prim . Unit # " { " SmallArray # " % a } } 
     + " unsafeThawSmallArray # "    : : { " SmallArray # " % a } - > { " State # " % s } - > { " GHC.Prim . Unit # " { " SmallMutableArray # " % s % a } } 
     + " copySmallArray # "          : : { " SmallArray # " % a } - > T_Int64 - > { " SmallMutableArray # " % s % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . ( # # ) " } 
     + " copySmallMutableArray # "   : : { " SmallMutableArray # " % s % a } - > T_Int64 - > { " SmallMutableArray # " % s % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . ( # # ) " } 
     + " cloneSmallArray # "         : : { " SmallArray # " % a } - > T_Int64 - > T_Int64 - > { " SmallArray # " % a } 
     + " cloneSmallMutableArray # " : : { " SmallMutableArray # " % s % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . Unit # " { " SmallMutableArray # " % s % a } } 
     + " freezeSmallArray # "        : : { " SmallMutableArray # " % s % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . Unit # " { " SmallArray # " % a } } 
     + " thawSmallArray # "          : : { " SmallArray # " % a } - > T_Int64 - > T_Int64 - > { " State # " % s } - > { " GHC.Prim . Unit # " { " SmallMutableArray # " % s % a } } 
     + " casSmallArray # "           : : { " SmallMutableArray # " % s % a } - > T_Int64 - > % a - > % a - > { " State # " % s } - > { " GHC.Prim . ( # , # ) " T_Int64 % a } 

  primop effectful
    + "newArray#" :: T_Int64 -> %a -> {"State#" %s} -> {"GHC.Prim.Unit#" {"MutableArray#" %s %a}}

  primop pure
    - "sameMutableArray#" :: {"MutableArray#" %s %a} -> {"MutableArray#" %s %a} -> T_Int64

  primop effectful
    + "readArray#"  :: {"MutableArray#" %s %a} -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.Unit#" %a}
    + "writeArray#" :: {"MutableArray#" %s %a} -> T_Int64 -> %a -> {"State#" %s} -> {"GHC.Prim.(##)"}

  primop pure
    - "sizeofArray#"        :: {"Array#" %a} -> T_Int64
    - "sizeofMutableArray#" :: {"MutableArray#" %s %a} -> T_Int64
    + "indexArray#"         :: {"Array#" %a} -> T_Int64 -> {"GHC.Prim.Unit#" %a}

  primop effectful
    + "unsafeFreezeArray#" :: {"MutableArray#" %s %a} -> {"State#" %s} -> {"GHC.Prim.Unit#" {"Array#" %a}}
    + "unsafeThawArray#"   :: {"Array#" %a} -> {"State#" %s} -> {"GHC.Prim.Unit#" {"MutableArray#" %s %a}}
    + "copyArray#"         :: {"Array#" %a} -> T_Int64 -> {"MutableArray#" %s %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.(##)"}
    + "copyMutableArray#"  :: {"MutableArray#" %s %a} -> T_Int64 -> {"MutableArray#" %s %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.(##)"}
    + "cloneArray#"        :: {"Array#" %a} -> T_Int64 -> T_Int64 -> {"Array#" %a}
    + "cloneMutableArray#" :: {"MutableArray#" %s %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.Unit#" {"MutableArray#" %s %a}}
    + "freezeArray#"       :: {"MutableArray#" %s %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.Unit#" {"Array#" %a}}
    + "thawArray#"         :: {"Array#" %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.Unit#" {"MutableArray#" %s %a}}
    + "casArray#"          :: {"MutableArray#" %s %a} -> T_Int64 -> %a -> %a -> {"State#" %s} -> {"GHC.Prim.(#,#)" T_Int64 %a}

  Small Arrays

  primop effectful
    + "newSmallArray#" :: T_Int64 -> %a -> {"State#" %s} -> {"GHC.Prim.Unit#" {"SmallMutableArray#" %s %a}}

  primop pure
    - "sameSmallMutableArray#" :: {"SmallMutableArray#" %s %a} -> {"SmallMutableArray#" %s %a} -> T_Int64

  primop effectful
    + "readSmallArray#"  :: {"SmallMutableArray#" %s %a} -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.Unit#" %a}
    + "writeSmallArray#" :: {"SmallMutableArray#" %s %a} -> T_Int64 -> %a -> {"State#" %s} -> {"GHC.Prim.(##)"}

  primop pure
    - "sizeofSmallArray#"        :: {"SmallArray#" %a} -> T_Int64
    - "sizeofSmallMutableArray#" :: {"SmallMutableArray#" %s %a} -> T_Int64
    + "indexSmallArray#"         :: {"SmallArray#" %a} -> T_Int64 -> {"GHC.Prim.Unit#" %a}

  primop effectful
    + "unsafeFreezeSmallArray#" :: {"SmallMutableArray#" %s %a} -> {"State#" %s} -> {"GHC.Prim.Unit#" {"SmallArray#" %a}}
    + "unsafeThawSmallArray#"   :: {"SmallArray#" %a} -> {"State#" %s} -> {"GHC.Prim.Unit#" {"SmallMutableArray#" %s %a}}
    + "copySmallArray#"         :: {"SmallArray#" %a} -> T_Int64 -> {"SmallMutableArray#" %s %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.(##)"}
    + "copySmallMutableArray#"  :: {"SmallMutableArray#" %s %a} -> T_Int64 -> {"SmallMutableArray#" %s %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.(##)"}
    + "cloneSmallArray#"        :: {"SmallArray#" %a} -> T_Int64 -> T_Int64 -> {"SmallArray#" %a}
    + "cloneSmallMutableArray#" :: {"SmallMutableArray#" %s %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.Unit#" {"SmallMutableArray#" %s %a}}
    + "freezeSmallArray#"       :: {"SmallMutableArray#" %s %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.Unit#" {"SmallArray#" %a}}
    + "thawSmallArray#"         :: {"SmallArray#" %a} -> T_Int64 -> T_Int64 -> {"State#" %s} -> {"GHC.Prim.Unit#" {"SmallMutableArray#" %s %a}}
    + "casSmallArray#"          :: {"SmallMutableArray#" %s %a} -> T_Int64 -> %a -> %a -> {"State#" %s} -> {"GHC.Prim.(#,#)" T_Int64 %a}
-}
  describe "GHC Array PrimOps" $ do

    it "newArray#" $ do
      cfa <- controlFlowAnalysisM ["main"] [prog|
          primop effectful
            "newArray#" :: (T_Int64) @ t.106 -> %a.6 -> {"State#" %s.2} @ t.107 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.2 %a.6} @ t.109} @ t.108
          main =
            letS
              v00 = #T_Int64 10
              v01 = [Tup0]
              v02 = #T_Token "RealWorld"
              v03 = "newArray#" $ v00 v01 v02
              v05 = case v03 of
                ("GHC.Prim.Unit#" v04) @ a00 ->
                  v04
            v05
        |]
      addUsedM cfa
      toArrOp cfa `sameAs` Map.fromList
        [ ( "Array" , [ [ "v03" , "t.109" , "v01" ] ] )
        , ( "ExternalOrigin"
          , [ [ "a00" , "v03" , "t.108" ]
            , [ "v03" , "v03" , "t.108" ]
            , [ "v04" , "v03" , "t.109" ]
            , [ "v05" , "v03" , "t.109" ]
            ]
          )
        , ( "NodeOrigin"
          , [ [ "v00" , "v00" ]
            , [ "v01" , "v01" ]
            , [ "v02" , "v02" ]
            ]
          )
        , ( "TagValue"
          , [ [ "a00" , "GHC.Prim.Unit#" ]
            , [ "v00" , "lit:T_Int64" ]
            , [ "v01" , "Tup0" ]
            , [ "v02" , "lit:T_Token \"RealWorld\"" ]
            , [ "v03" , "GHC.Prim.Unit#" ]
            , [ "v04" , "MutableArray#" ]
            , [ "v05" , "MutableArray#" ]
            ]
          )
        ]

    it "readArray#" $ do
      cfa <- controlFlowAnalysisM ["main"] [prog|
          primop effectful
            "newArray#" :: (T_Int64) @ t.106 -> %a.6 -> {"State#" %s.2} @ t.107 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.2 %a.6} @ t.109} @ t.108
            "readArray#" :: {"MutableArray#" %s.21 %a.11} @ t.243 -> (T_Int64) @ t.244 -> {"State#" %s.21} @ t.245 -> {"GHC.Prim.Unit#" %a.11} @ t.246
          main =
            letS
              v00 = #T_Int64 10
              v01 = [Tup0]
              v02 = #T_Token "RealWorld"
              v03 = "newArray#" $ v00 v01 v02
              v09 = case v03 of
                ("GHC.Prim.Unit#" v04) @ a00 ->
                  letS
                    v05 = #T_Int64 0
                    v06 = "readArray#" $ v04 v05 v02
                    v08 = case v06 of
                      ("GHC.Prim.Unit#" v07) @ a01 ->
                        v07
                  v08
            v09
        |]
      addUsedM cfa
      toArrOp cfa `sameAs` Map.fromList
        [ ( "Array" , [ [ "v03" , "t.109" , "v01" ] ] )
        , ( "ExternalOrigin"
          , [ [ "a00" , "v03" , "t.108" ]
            , [ "a01" , "v06" , "t.246" ]
            , [ "v03" , "v03" , "t.108" ]
            , [ "v04" , "v03" , "t.109" ]
            , [ "v06" , "v06" , "t.246" ]
            , [ "v07" , "v06" , "a.11" ]
            , [ "v08" , "v06" , "a.11" ]
            , [ "v09" , "v06" , "a.11" ]
            ]
          )
        , ( "NodeOrigin"
          , [ [ "v00" , "v00" ]
            , [ "v01" , "v01" ]
            , [ "v02" , "v02" ]
            , [ "v05" , "v05" ]
            , [ "v07" , "v01" ]
            , [ "v08" , "v01" ]
            , [ "v09" , "v01" ]
            ]
          )
        , ( "TagValue"
          , [ [ "a00" , "GHC.Prim.Unit#" ]
            , [ "a01" , "GHC.Prim.Unit#" ]
            , [ "v00" , "lit:T_Int64" ]
            , [ "v01" , "Tup0" ]
            , [ "v02" , "lit:T_Token \"RealWorld\"" ]
            , [ "v03" , "GHC.Prim.Unit#" ]
            , [ "v04" , "MutableArray#" ]
            , [ "v05" , "lit:T_Int64" ]
            , [ "v06" , "GHC.Prim.Unit#" ]
            , [ "v07" , "Tup0" ]
            , [ "v08" , "Tup0" ]
            , [ "v09" , "Tup0" ]
            ]
          )
        ]

    it "writeArray#" $ do
      cfa <- controlFlowAnalysisM ["main"] [prog|
          primop effectful
            "newArray#"   :: (T_Int64) @ t.106 -> %a.6 -> {"State#" %s.2} @ t.107 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.2 %a.6} @ t.109} @ t.108
            "writeArray#" :: {"MutableArray#" %s.4 %a.9} @ t.115 -> (T_Int64) @ t.116 -> %a.9 -> {"State#" %s.4} @ t.117 -> {"GHC.Prim.(##)"} @ t.118
          main =
            letS
              v00 = #T_Int64 10
              v01 = [Tup0]
              v02 = #T_Token "RealWorld"
              v03 = "newArray#" $ v00 v01 v02
              v09 = case v03 of
                ("GHC.Prim.Unit#" v04) @ a00 ->
                  letS
                    v05 = #T_Int64 0
                    v06 = [C1]
                    v07 = v06
                    v08 = "writeArray#" $ v04 v05 v07 v02
                  v08
            v09
        |]
      addUsedM cfa
      toArrOp cfa `sameAs` Map.fromList
        [ ( "Array"
          , [ [ "v03" , "t.109" , "v01" ]
            , [ "v03" , "t.109" , "v07" ]
            ]
          )
        , ( "ExternalOrigin"
          , [ [ "a00" , "v03" , "t.108" ]
            , [ "v03" , "v03" , "t.108" ]
            , [ "v04" , "v03" , "t.109" ]
            , [ "v08" , "v08" , "t.118" ]
            , [ "v09" , "v08" , "t.118" ]
            ]
          )
        , ( "NodeOrigin"
          , [ [ "v00" , "v00" ]
            , [ "v01" , "v01" ]
            , [ "v02" , "v02" ]
            , [ "v05" , "v05" ]
            , [ "v06" , "v06" ]
            , [ "v07" , "v06" ]
            ]
          )
        , ( "TagValue"
          , [ [ "a00" , "GHC.Prim.Unit#" ]
            , [ "v00" , "lit:T_Int64" ]
            , [ "v01" , "Tup0" ]
            , [ "v02" , "lit:T_Token \"RealWorld\"" ]
            , [ "v03" , "GHC.Prim.Unit#" ]
            , [ "v04" , "MutableArray#" ]
            , [ "v05" , "lit:T_Int64" ]
            , [ "v06" , "C1" ]
            , [ "v07" , "C1" ]
            , [ "v08" , "GHC.Prim.(##)" ]
            , [ "v09" , "GHC.Prim.(##)" ]
            ]
          )
        ]

    it "unsafeFreezeArray#" $ do
      cfa <- controlFlowAnalysisM ["main"] [prog|
          primop effectful
            "newArray#"           :: (T_Int64) @ t.00 -> %a.01 -> {"State#" %s.02} @ t.03 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.02 %a.01} @ t.04} @ t.05
            "unsafeFreezeArray#"  :: {"MutableArray#" %s.10 %a.11} @ t.12 -> {"State#" %s.10} @ t.13 -> {"GHC.Prim.Unit#" {"Array#" %a.11} @ t.14} @ t.15
          main =
            letS
              v00 = #T_Int64 10
              v01 = [Tup0]
              v02 = #T_Token "RealWorld"
              v03 = "newArray#" $ v00 v01 v02
              v08 = case v03 of
                ("GHC.Prim.Unit#" v04) @ a00 ->
                  letS
                    v05 = "unsafeFreezeArray#" $ v04 v02
                    v07 = case v05 of
                      ("GHC.Prim.Unit#" v06) @ a01 ->
                        v06
                  v07
            v08
        |]
      addUsedM cfa
      toArrOp cfa `sameAs` Map.fromList
        [ ( "Array"
          , [ [ "v03" , "t.04" , "v01" ]
            ]
          )
        , ( "ExternalOrigin"
          , [ [ "a00" , "v03" , "t.05" ]
            , [ "a01" , "v05" , "t.15" ]
            , [ "v03" , "v03" , "t.05" ]
            , [ "v04" , "v03" , "t.04" ]
            , [ "v05" , "v05" , "t.15" ]
            , [ "v06" , "v03" , "t.04" ]
            , [ "v06" , "v05" , "t.14" ]
            , [ "v07" , "v03" , "t.04" ]
            , [ "v07" , "v05" , "t.14" ]
            , [ "v08" , "v03" , "t.04" ]
            , [ "v08" , "v05" , "t.14" ]
            ]
          )
        , ( "NodeOrigin"
          , [ [ "v00" , "v00" ]
            , [ "v01" , "v01" ]
            , [ "v02" , "v02" ]
            ]
          )
        , ( "TagValue"
          , [ [ "a00" , "GHC.Prim.Unit#" ]
            , [ "a01" , "GHC.Prim.Unit#" ]
            , [ "v00" , "lit:T_Int64" ]
            , [ "v01" , "Tup0" ]
            , [ "v02" , "lit:T_Token \"RealWorld\"" ]
            , [ "v03" , "GHC.Prim.Unit#" ]
            , [ "v04" , "MutableArray#" ]
            , [ "v05" , "GHC.Prim.Unit#" ]
            , [ "v06" , "Array#" ]
            , [ "v06" , "MutableArray#" ]
            , [ "v07" , "Array#" ]
            , [ "v07" , "MutableArray#" ]
            , [ "v08" , "Array#" ]
            , [ "v08" , "MutableArray#" ]
            ]
          )
        ]

    it "copyMutableArray#" $ do
      cfa <- controlFlowAnalysisM ["main"] [prog|
          primop effectful
            "newArray#"         :: (T_Int64) @ t.00 -> %a.01 -> {"State#" %s.02} @ t.03 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.02 %a.01} @ t.04} @ t.05
            "copyMutableArray#" :: {"MutableArray#" %s.10 %a.11} @ t.12 -> (T_Int64) @ t.13 -> {"MutableArray#" %s.10 %a.11} @ t.14 -> (T_Int64) @ t.15 -> (T_Int64) @ t.16 -> {"State#" %s.10} @ t.17 -> {"GHC.Prim.(##)"} @ t.18
          main =
            letS
              v00 = #T_Int64 10
              v01 = [Tup0]
              v02 = #T_Token "RealWorld"
              v03 = "newArray#" $ v00 v01 v02
              v11 = case v03 of
                ("GHC.Prim.Unit#" v04) @ a00 ->
                  letS
                    v05 = [C1]
                    v06 = "newArray#" $ v00 v05 v02
                    v10 = case v06 of
                      ("GHC.Prim.Unit#" v07) @ a01 ->
                        letS
                          v08 = #T_Int64 0
                          v09 = "copyMutableArray#" $ v04 v08 v07 v08 v00 v02
                        v09
                  v10
            v11
        |]
      addUsedM cfa
      toArrOp cfa `sameAs` Map.fromList
        [ ( "Array"
          , [ [ "v03" , "t.04" , "v01" ]
            , [ "v06" , "t.04" , "v01" ]
            , [ "v06" , "t.04" , "v05" ]
            ]
          )
        , ( "ExternalOrigin"
          , [ [ "a00" , "v03" , "t.05" ]
            , [ "a01" , "v06" , "t.05" ]
            , [ "v03" , "v03" , "t.05" ]
            , [ "v04" , "v03" , "t.04" ]
            , [ "v06" , "v06" , "t.05" ]
            , [ "v07" , "v06" , "t.04" ]
            , [ "v09" , "v09" , "t.18" ]
            , [ "v10" , "v09" , "t.18" ]
            , [ "v11" , "v09" , "t.18" ]
            ]
          )
        , ( "NodeOrigin"
          , [ [ "v00" , "v00" ]
            , [ "v01" , "v01" ]
            , [ "v02" , "v02" ]
            , [ "v05" , "v05" ]
            , [ "v08" , "v08" ]
            ]
          )
        , ( "TagValue"
          , [ [ "a00" , "GHC.Prim.Unit#" ]
            , [ "a01" , "GHC.Prim.Unit#" ]
            , [ "v00" , "lit:T_Int64" ]
            , [ "v01" , "Tup0" ]
            , [ "v02" , "lit:T_Token \"RealWorld\"" ]
            , [ "v03" , "GHC.Prim.Unit#" ]
            , [ "v04" , "MutableArray#" ]
            , [ "v05" , "C1" ]
            , [ "v06" , "GHC.Prim.Unit#" ]
            , [ "v07" , "MutableArray#" ]
            , [ "v08" , "lit:T_Int64" ]
            , [ "v09" , "GHC.Prim.(##)" ]
            , [ "v10" , "GHC.Prim.(##)" ]
            , [ "v11" , "GHC.Prim.(##)" ]
            ]
          )
        ]

    it "cloneArray#" $ do
      cfa <- controlFlowAnalysisM ["main"] [prog|
          primop effectful
            "newArray#"           :: (T_Int64) @ t.00 -> %a.01 -> {"State#" %s.02} @ t.03 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.02 %a.01} @ t.04} @ t.05
            "unsafeFreezeArray#"  :: {"MutableArray#" %s.10 %a.11} @ t.12 -> {"State#" %s.10} @ t.13 -> {"GHC.Prim.Unit#" {"Array#" %a.11} @ t.14} @ t.15
            "cloneArray#"         :: {"Array#" %a.20} @ t.21 -> (T_Int64) @ t.22 -> (T_Int64) @ t.23 -> {"Array#" %a.20} @ t.24
          main =
            letS
              v00 = #T_Int64 10
              v01 = [Tup0]
              v02 = #T_Token "RealWorld"
              v03 = "newArray#" $ v00 v01 v02
              v10 = case v03 of
                ("GHC.Prim.Unit#" v04) @ a00 ->
                  letS
                    v05 = "unsafeFreezeArray#" $ v04 v02
                    v09 = case v05 of
                      ("GHC.Prim.Unit#" v06) @ a01 ->
                        letS
                          v07 = #T_Int64 0
                          v08 = "cloneArray#" $ v06 v07 v00
                        v08
                  v09
            v10
        |]
      addUsedM cfa
      toArrOp cfa `sameAs` Map.fromList
        [ ( "Array"
          , [ [ "v03" , "t.04" , "v01" ]
            , [ "v08" , "t.24" , "v01" ]
            ]
          )
        , ( "ExternalOrigin"
          , [ [ "a00" , "v03" , "t.05" ]
            , [ "a01" , "v05" , "t.15" ]
            , [ "v03" , "v03" , "t.05" ]
            , [ "v04" , "v03" , "t.04" ]
            , [ "v05" , "v05" , "t.15" ]
            , [ "v06" , "v03" , "t.04" ]
            , [ "v06" , "v05" , "t.14" ]
            , [ "v08" , "v08" , "t.24" ]
            , [ "v09" , "v08" , "t.24" ]
            , [ "v10" , "v08" , "t.24" ]
            ]
          )
        , ( "NodeOrigin"
          , [ [ "v00" , "v00" ]
            , [ "v01" , "v01" ]
            , [ "v02" , "v02" ]
            , [ "v07" , "v07" ]
            ]
          )
        , ( "TagValue"
          , [ [ "a00" , "GHC.Prim.Unit#" ]
            , [ "a01" , "GHC.Prim.Unit#" ]
            , [ "v00" , "lit:T_Int64" ]
            , [ "v01" , "Tup0" ]
            , [ "v02" , "lit:T_Token \"RealWorld\"" ]
            , [ "v03" , "GHC.Prim.Unit#" ]
            , [ "v04" , "MutableArray#" ]
            , [ "v05" , "GHC.Prim.Unit#" ]
            , [ "v06" , "Array#" ]
            , [ "v06" , "MutableArray#" ]
            , [ "v07" , "lit:T_Int64" ]
            , [ "v08" , "Array#" ]
            , [ "v09" , "Array#" ]
            , [ "v10" , "Array#" ]
            ]
          )
        ]

    it "cloneMutableArray#" $ do
      cfa <- controlFlowAnalysisM ["main"] [prog|
          primop effectful
            "newArray#"          :: (T_Int64) @ t.00 -> %a.01 -> {"State#" %s.02} @ t.03 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.02 %a.01} @ t.04} @ t.05
            "cloneMutableArray#" :: {"MutableArray#" %s.10 %a.11} @ t.12 -> (T_Int64) @ t.13 -> (T_Int64) @ t.14 -> {"State#" %s.10} @ t.15 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.10 %a.11} @ t.16} @ t.17
          main =
            letS
              v00 = #T_Int64 10
              v01 = [Tup0]
              v02 = #T_Token "RealWorld"
              v03 = "newArray#" $ v00 v01 v02
              v09 = case v03 of
                ("GHC.Prim.Unit#" v04) @ a00 ->
                  letS
                    v05 = #T_Int64 0
                    v06 = "cloneMutableArray#" $ v04 v05 v00 v02
                    v08 = case v06 of
                      ("GHC.Prim.Unit#" v07) @ a01 ->
                        v07
                  v08
            v09
        |]
      addUsedM cfa
      toArrOp cfa `sameAs` Map.fromList
        [ ( "Array"
          , [ [ "v03" , "t.04" , "v01" ]
            , [ "v06" , "t.16" , "v01" ]
            ]
          )
        , ( "ExternalOrigin"
          , [ [ "a00" , "v03" , "t.05" ]
            , [ "a01" , "v06" , "t.17" ]
            , [ "v03" , "v03" , "t.05" ]
            , [ "v04" , "v03" , "t.04" ]
            , [ "v06" , "v06" , "t.17" ]
            , [ "v07" , "v06" , "t.16" ]
            , [ "v08" , "v06" , "t.16" ]
            , [ "v09" , "v06" , "t.16" ]
            ]
          )
        , ( "NodeOrigin"
          , [ [ "v00" , "v00" ]
            , [ "v01" , "v01" ]
            , [ "v02" , "v02" ]
            , [ "v05" , "v05" ]
            ]
          )
        , ( "TagValue"
          , [ [ "a00" , "GHC.Prim.Unit#" ]
            , [ "a01" , "GHC.Prim.Unit#" ]
            , [ "v00" , "lit:T_Int64" ]
            , [ "v01" , "Tup0" ]
            , [ "v02" , "lit:T_Token \"RealWorld\"" ]
            , [ "v03" , "GHC.Prim.Unit#" ]
            , [ "v04" , "MutableArray#" ]
            , [ "v05" , "lit:T_Int64" ]
            , [ "v06" , "GHC.Prim.Unit#" ]
            , [ "v07" , "MutableArray#" ]
            , [ "v08" , "MutableArray#" ]
            , [ "v09" , "MutableArray#" ]
            ]
          )
        ]

    it "casArray#" $ do
      cfa <- controlFlowAnalysisM ["main"] [prog|
          primop effectful
            "newArray#" :: (T_Int64) @ t.00 -> %a.01 -> {"State#" %s.02} @ t.03 -> {"GHC.Prim.Unit#" {"MutableArray#" %s.02 %a.01} @ t.04} @ t.05
            "casArray#" :: {"MutableArray#" %s.10 %a.11} @ t.12 -> (T_Int64) @ t.13 -> %a.11 -> %a.11 -> {"State#" %s.10} @ t.14 -> {"GHC.Prim.(#,#)" (T_Int64) @ t.15 %a.11} @ t.16
          main =
            letS
              v00 = #T_Int64 10
              v01 = [Tup0]
              v02 = #T_Token "RealWorld"
              v03 = "newArray#" $ v00 v01 v02
              v11 = case v03 of
                ("GHC.Prim.Unit#" v04) @ a00 ->
                  letS
                    v05 = #T_Int64 0
                    v06 = [C1]
                    v07 = "casArray#" $ v04 v05 v01 v06 v02
                    v10 = case v07 of
                      ("GHC.Prim.(#,#)" v08 v09) @ a01 ->
                        v08
                  v10
            v11
        |]
      addUsedM cfa
      toArrOp cfa `sameAs` Map.fromList
        [ ( "Array"
          , [ [ "v03" , "t.04" , "v01" ]
            , [ "v03" , "t.04" , "v06" ]
            ]
          )
        , ( "ExternalOrigin"
          , [ [ "a00" , "v03" , "t.05" ]
            , [ "a01" , "v07" , "t.16" ]
            , [ "v03" , "v03" , "t.05" ]
            , [ "v04" , "v03" , "t.04" ]
            , [ "v07" , "v07" , "t.16" ]
            , [ "v08" , "v07" , "t.15" ]
            , [ "v09" , "v07" , "a.11" ]
            , [ "v10" , "v07" , "t.15" ]
            , [ "v11" , "v07" , "t.15" ]
            ]
          )
        , ( "NodeOrigin"
          , [ [ "v00" , "v00" ]
            , [ "v01" , "v01" ]
            , [ "v02" , "v02" ]
            , [ "v05" , "v05" ]
            , [ "v06" , "v06" ]
            , [ "v09" , "v01" ]
            , [ "v09" , "v06" ]
            ]
          )
        , ( "TagValue"
          , [ [ "a00" , "GHC.Prim.Unit#" ]
            , [ "a01" , "GHC.Prim.(#,#)" ]
            , [ "v00" , "lit:T_Int64" ]
            , [ "v01" , "Tup0" ]
            , [ "v02" , "lit:T_Token \"RealWorld\"" ]
            , [ "v03" , "GHC.Prim.Unit#" ]
            , [ "v04" , "MutableArray#" ]
            , [ "v05" , "lit:T_Int64" ]
            , [ "v06" , "C1" ]
            , [ "v07" , "GHC.Prim.(#,#)" ]
            , [ "v08" , "lit:T_Int64" ]
            , [ "v09" , "C1" ]
            , [ "v09" , "Tup0" ]
            , [ "v10" , "lit:T_Int64" ]
            , [ "v11" , "lit:T_Int64" ]
            ]
          )
        ]

  describe "Coverage" $ do
    it "Used Rules" $ do
      printUsedM
