content: {-# LANGUAGE CPP #-}
  {-# LANGUAGE OverloadedStrings #-}
  
  module Clash.Tests.Core.FreeVars (tests) where
  
  #if MIN_VERSION_ghc(9,0,0)
  import           GHC.Types.SrcLoc        (noSrcSpan)
  #else
  import           SrcLoc                  (noSrcSpan)
  #endif
  import qualified Control.Lens            as Lens
  
  import           Test.Tasty
  import           Test.Tasty.HUnit
  
  import           Clash.Core.FreeVars     (globalIds)
  import           Clash.Core.Name         (Name(..), NameSort(..))
  import           Clash.Core.Term         (Term(Var, App, Lam))
  import           Clash.Core.Type         (ConstTy(..), Type(ConstTy))
  import           Clash.Core.Var          (IdScope(..), Var(..))
  
  -- TODO: We need tooling to create these mock constructs
  fakeName :: Name a
  fakeName =
    Name
      { nameSort=User
      , nameOcc="fake"
      , nameUniq=0
      , nameLoc=noSrcSpan
      }
  
  f :: IdScope -> Var Term
  f scope =
    let unique = 20 in
    Id { varName = Name { nameSort=User
                        , nameOcc="f"
                        , nameUniq=unique
                        , nameLoc=noSrcSpan }
       , varUniq = unique
       , varType = ConstTy (TyCon fakeName)
       , idScope = scope }
  
  fLocalId, fGlobalId :: Var Term
  fLocalId = f LocalId
  fGlobalId = f GlobalId
  
  -- 'term1' is a simple lambda function:
  --
  --   \f -> g f
  --
  -- where f and g have the same unique, but f has been marked as _local_ while
  -- g is _global_. In other words:
  --
  --   \f[l] -> f[g] f[l]
  --
  -- This term is tested against to check whether various functions account for
  -- the distinction between local/global variables correctly.
  term1 :: Term
  term1 =
    Lam fLocalId (Var fGlobalId `App` Var fLocalId)
  
  tests :: TestTree
  tests =
    let globs1 = Lens.toListOf globalIds term1 in
    testGroup
      "Clash.Tests.Core.FreeVars"
      [ testCase "globalIds1" $ globs1 @=? [fGlobalId]
      , testCase "globalIds2" $
          assertBool
            "Global and local id can't BOTH be in globs1"
            (fLocalId `notElem` globs1)
      ]
  