-----------------------------------------------------------------------------
-- |
-- Module      :  GHC.JS.Opt.Simple
-- Copyright   :  (c) The University of Glasgow 2001
-- License     :  BSD-style (see the file LICENSE)
--
-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>
--                Luite Stegeman <luite.stegeman@iohk.io>
--                Sylvain Henry  <sylvain.henry@iohk.io>
--                Josh Meredith  <josh.meredith@iohk.io>
-- Stability   :  experimental
--
--
-- * Simple optimizer for the JavaScript IR
--
--     This is a simple optimizer for the JavaScript IR. It is intended to be
--     the first optimization pass after generating the JavaScript IR.
--
-- * Design
--
--     The optimizer is invoked on the top-level JStat. It leaves the top-level
--     scope alone, but traverses into each function body and optimizes it.
--     Nested functions are mostly left alone, since they are uncommon in
--     generated code.
--
--     The optimizations are:
--
--       - rename local variables to shorter names
--       - remove unused variables
--       - remove trivial assignments: x = x
--       - "float" expressions without side effects:
--       -   var x = 1; var y = x + 1; -> var y = 1 + 1;
--
-- * Limitations
--
--     The simple optimization pass is intended to be fast and applicable to
--     almost all generated JavaScript code. Limitations are:
--
--       - optimization is disabled if an `eval` statement is encountered
--       - variables declared in nested scopes are not renamed
--
-----------------------------------------------------------------------------

{-# LANGUAGE OverloadedStrings #-}
module GHC.JS.Opt.Simple (simpleOpt) where

import GHC.Prelude

import GHC.JS.Opt.Expr
import GHC.JS.Syntax

import GHC.Data.FastString
import qualified GHC.Types.Unique.Map as UM
import GHC.Types.Unique.Map (UniqMap)
import qualified GHC.Types.Unique.Set as US

import Control.Monad
import Data.Function
import Data.List (sortBy)
import Data.Maybe
import qualified Data.Semigroup as Semi


data Multiplicity = Zero | One | Many
    deriving (Multiplicity -> Multiplicity -> Bool
(Multiplicity -> Multiplicity -> Bool)
-> (Multiplicity -> Multiplicity -> Bool) -> Eq Multiplicity
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Multiplicity -> Multiplicity -> Bool
== :: Multiplicity -> Multiplicity -> Bool
$c/= :: Multiplicity -> Multiplicity -> Bool
/= :: Multiplicity -> Multiplicity -> Bool
Eq, Eq Multiplicity
Eq Multiplicity =>
(Multiplicity -> Multiplicity -> Ordering)
-> (Multiplicity -> Multiplicity -> Bool)
-> (Multiplicity -> Multiplicity -> Bool)
-> (Multiplicity -> Multiplicity -> Bool)
-> (Multiplicity -> Multiplicity -> Bool)
-> (Multiplicity -> Multiplicity -> Multiplicity)
-> (Multiplicity -> Multiplicity -> Multiplicity)
-> Ord Multiplicity
Multiplicity -> Multiplicity -> Bool
Multiplicity -> Multiplicity -> Ordering
Multiplicity -> Multiplicity -> Multiplicity
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Multiplicity -> Multiplicity -> Ordering
compare :: Multiplicity -> Multiplicity -> Ordering
$c< :: Multiplicity -> Multiplicity -> Bool
< :: Multiplicity -> Multiplicity -> Bool
$c<= :: Multiplicity -> Multiplicity -> Bool
<= :: Multiplicity -> Multiplicity -> Bool
$c> :: Multiplicity -> Multiplicity -> Bool
> :: Multiplicity -> Multiplicity -> Bool
$c>= :: Multiplicity -> Multiplicity -> Bool
>= :: Multiplicity -> Multiplicity -> Bool
$cmax :: Multiplicity -> Multiplicity -> Multiplicity
max :: Multiplicity -> Multiplicity -> Multiplicity
$cmin :: Multiplicity -> Multiplicity -> Multiplicity
min :: Multiplicity -> Multiplicity -> Multiplicity
Ord, Int -> Multiplicity -> ShowS
[Multiplicity] -> ShowS
Multiplicity -> String
(Int -> Multiplicity -> ShowS)
-> (Multiplicity -> String)
-> ([Multiplicity] -> ShowS)
-> Show Multiplicity
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Multiplicity -> ShowS
showsPrec :: Int -> Multiplicity -> ShowS
$cshow :: Multiplicity -> String
show :: Multiplicity -> String
$cshowList :: [Multiplicity] -> ShowS
showList :: [Multiplicity] -> ShowS
Show)

data VarValue = Unassigned
              | AssignedOnce
              | AssignedOnceKnown !JExpr
              | AssignedMany

data VarDecl = NoDecl -- not declared in analyzed scope (possibly deeper or global)
             | ArgDecl !Int -- argument in analyzed scope
             | LocalDecl !Int -- local variable in analyzed scope
  deriving (VarDecl -> VarDecl -> Bool
(VarDecl -> VarDecl -> Bool)
-> (VarDecl -> VarDecl -> Bool) -> Eq VarDecl
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: VarDecl -> VarDecl -> Bool
== :: VarDecl -> VarDecl -> Bool
$c/= :: VarDecl -> VarDecl -> Bool
/= :: VarDecl -> VarDecl -> Bool
Eq, Int -> VarDecl -> ShowS
[VarDecl] -> ShowS
VarDecl -> String
(Int -> VarDecl -> ShowS)
-> (VarDecl -> String) -> ([VarDecl] -> ShowS) -> Show VarDecl
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> VarDecl -> ShowS
showsPrec :: Int -> VarDecl -> ShowS
$cshow :: VarDecl -> String
show :: VarDecl -> String
$cshowList :: [VarDecl] -> ShowS
showList :: [VarDecl] -> ShowS
Show)

isLocalOrArg :: VarDecl -> Bool
isLocalOrArg :: VarDecl -> Bool
isLocalOrArg (LocalDecl {}) = Bool
True
isLocalOrArg (ArgDecl {})   = Bool
True
isLocalOrArg VarDecl
_              = Bool
False

isDecl :: VarDecl -> Bool
isDecl :: VarDecl -> Bool
isDecl VarDecl
NoDecl = Bool
False
isDecl VarDecl
_      = Bool
True

instance Semi.Semigroup VarDecl where
  VarDecl
NoDecl <> :: VarDecl -> VarDecl -> VarDecl
<> VarDecl
x = VarDecl
x
  VarDecl
x <> VarDecl
NoDecl = VarDecl
x
  ArgDecl Int
n <> ArgDecl Int
m = Int -> VarDecl
ArgDecl (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
n Int
m)
  LocalDecl Int
n <> LocalDecl Int
m = Int -> VarDecl
LocalDecl (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
n Int
m)
  ArgDecl Int
n <> VarDecl
_ = Int -> VarDecl
ArgDecl Int
n
  VarDecl
_ <> ArgDecl Int
n = Int -> VarDecl
ArgDecl Int
n

instance Ord VarDecl where
  compare :: VarDecl -> VarDecl -> Ordering
compare VarDecl
NoDecl VarDecl
NoDecl = Ordering
EQ
  compare VarDecl
NoDecl VarDecl
_      = Ordering
LT
  compare VarDecl
_      VarDecl
NoDecl = Ordering
GT
  compare (ArgDecl Int
n) (ArgDecl Int
m) = Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Int
n Int
m
  compare (ArgDecl {}) VarDecl
_ = Ordering
LT
  compare VarDecl
_ (ArgDecl {}) = Ordering
GT
  compare (LocalDecl Int
n) (LocalDecl Int
m) = Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Int
n Int
m

data JFunction = JFunction [Ident] JStat

instance Semi.Semigroup VarValue where
  VarValue
Unassigned <> :: VarValue -> VarValue -> VarValue
<> VarValue
x = VarValue
x
  VarValue
x <> VarValue
Unassigned = VarValue
x
  VarValue
_ <> VarValue
_ = VarValue
AssignedMany

instance Monoid VarValue where
  mempty :: VarValue
mempty = VarValue
Unassigned
  mappend :: VarValue -> VarValue -> VarValue
mappend = VarValue -> VarValue -> VarValue
forall a. Semigroup a => a -> a -> a
(Semi.<>)

instance Semigroup Multiplicity where
    Multiplicity
Zero <> :: Multiplicity -> Multiplicity -> Multiplicity
<> Multiplicity
x = Multiplicity
x
    Multiplicity
x <> Multiplicity
Zero = Multiplicity
x
    Multiplicity
_ <> Multiplicity
_    = Multiplicity
Many

instance Monoid Multiplicity where
    mempty :: Multiplicity
mempty = Multiplicity
Zero
    mappend :: Multiplicity -> Multiplicity -> Multiplicity
mappend = Multiplicity -> Multiplicity -> Multiplicity
forall a. Semigroup a => a -> a -> a
(Semi.<>)

data VarUsage = VarUsage
    { VarUsage -> Multiplicity
varUsed :: !Multiplicity
    , VarUsage -> VarValue
varAssigned :: !VarValue
    , VarUsage -> VarDecl
varDeclared :: !VarDecl
    , VarUsage -> Bool
varDeepDeclared :: !Bool
    }

assignedMultiple :: VarUsage -> Bool
assignedMultiple :: VarUsage -> Bool
assignedMultiple VarUsage { varAssigned :: VarUsage -> VarValue
varAssigned = VarValue
AssignedMany } = Bool
True
assignedMultiple VarUsage
_                                       = Bool
False

data SimpleRewrite = SimpleRewrite
    { SimpleRewrite -> UniqMap Ident Ident
renameVar :: UniqMap Ident Ident
    , SimpleRewrite -> UniqMap Ident VarUsage
varUsage :: UniqMap Ident VarUsage
    }

instance Semigroup VarUsage where
    VarUsage
x <> :: VarUsage -> VarUsage -> VarUsage
<> VarUsage
y = VarUsage
        { varUsed :: Multiplicity
varUsed = VarUsage -> Multiplicity
varUsed VarUsage
x Multiplicity -> Multiplicity -> Multiplicity
forall a. Semigroup a => a -> a -> a
Semi.<> VarUsage -> Multiplicity
varUsed VarUsage
y
        , varAssigned :: VarValue
varAssigned = VarUsage -> VarValue
varAssigned VarUsage
x VarValue -> VarValue -> VarValue
forall a. Semigroup a => a -> a -> a
Semi.<> VarUsage -> VarValue
varAssigned VarUsage
y
        , varDeclared :: VarDecl
varDeclared = VarUsage -> VarDecl
varDeclared VarUsage
x VarDecl -> VarDecl -> VarDecl
forall a. Semigroup a => a -> a -> a
Semi.<> VarUsage -> VarDecl
varDeclared VarUsage
y
        , varDeepDeclared :: Bool
varDeepDeclared = VarUsage -> Bool
varDeepDeclared VarUsage
x Bool -> Bool -> Bool
|| VarUsage -> Bool
varDeepDeclared VarUsage
y
        }

instance Monoid VarUsage where
    mempty :: VarUsage
mempty = Multiplicity -> VarValue -> VarDecl -> Bool -> VarUsage
VarUsage Multiplicity
Zero VarValue
Unassigned VarDecl
NoDecl Bool
False

disableOpt :: Bool
-- disableOpt = True
disableOpt :: Bool
disableOpt = Bool
False

simpleOpt :: JStat -> JStat
simpleOpt :: JStat -> JStat
simpleOpt JStat
x | Bool
disableOpt = JStat
x
simpleOpt (BlockStat [JStat]
xs) = [JStat] -> JStat
BlockStat ((JStat -> JStat) -> [JStat] -> [JStat]
forall a b. (a -> b) -> [a] -> [b]
map JStat -> JStat
simpleOpt [JStat]
xs)
simpleOpt (AssignStat JExpr
lhs AOp
AssignOp (ValExpr (JFunc [Ident]
args JStat
body)))  =
     let JFunction [Ident]
args' JStat
body' = JFunction -> JFunction
simpleOptFunction ([Ident] -> JStat -> JFunction
JFunction [Ident]
args JStat
body)
     in JExpr -> AOp -> JExpr -> JStat
AssignStat JExpr
lhs AOp
AssignOp (JVal -> JExpr
ValExpr ([Ident] -> JStat -> JVal
JFunc [Ident]
args' JStat
body'))
simpleOpt (FuncStat Ident
name [Ident]
args JStat
body) =
     let JFunction [Ident]
args' JStat
body' = JFunction -> JFunction
simpleOptFunction ([Ident] -> JStat -> JFunction
JFunction [Ident]
args JStat
body)
     in  Ident -> [Ident] -> JStat -> JStat
FuncStat Ident
name [Ident]
args' JStat
body'
simpleOpt JStat
s = JStat
s

simpleOptFunction :: JFunction -> JFunction
simpleOptFunction :: JFunction -> JFunction
simpleOptFunction JFunction
jf = JFunction
s_opt
  where
    -- we need to run it twice since floating in the first pass can
    -- cause unused variables that can be removed in the second pass
    s_opt :: JFunction
s_opt  = JFunction -> JFunction
functionOptExprs (JFunction -> JFunction) -> JFunction -> JFunction
forall a b. (a -> b) -> a -> b
$ JFunction
-> (SimpleRewrite -> JFunction) -> Maybe SimpleRewrite -> JFunction
forall b a. b -> (a -> b) -> Maybe a -> b
maybe JFunction
jf (SimpleRewrite -> JFunction -> JFunction
`simpleRewrite` JFunction
s_opt0) Maybe SimpleRewrite
mb_rw
    mb_rw :: Maybe SimpleRewrite
mb_rw  = Bool -> AnalysisResult -> Maybe SimpleRewrite
mkRewrite Bool
True (JFunction -> AnalysisResult
simpleAnalyze JFunction
s_opt0)
    s_opt0 :: JFunction
s_opt0 = JFunction -> JFunction
functionOptExprs (JFunction -> JFunction) -> JFunction -> JFunction
forall a b. (a -> b) -> a -> b
$ JFunction
-> (SimpleRewrite -> JFunction) -> Maybe SimpleRewrite -> JFunction
forall b a. b -> (a -> b) -> Maybe a -> b
maybe JFunction
jf (SimpleRewrite -> JFunction -> JFunction
`simpleRewrite` JFunction
jf) Maybe SimpleRewrite
mb_rw0
    mb_rw0 :: Maybe SimpleRewrite
mb_rw0 = Bool -> AnalysisResult -> Maybe SimpleRewrite
mkRewrite Bool
False (JFunction -> AnalysisResult
simpleAnalyze JFunction
jf)

functionOptExprs :: JFunction -> JFunction
functionOptExprs :: JFunction -> JFunction
functionOptExprs (JFunction [Ident]
args JStat
s) = [Ident] -> JStat -> JFunction
JFunction [Ident]
args (JStat -> JStat
optExprs JStat
s)

newLocals :: [Ident]
newLocals :: [Ident]
newLocals = (Ident -> Bool) -> [Ident] -> [Ident]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (Ident -> Bool) -> Ident -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ident -> Bool
isReserved  ) ([Ident] -> [Ident]) -> [Ident] -> [Ident]
forall a b. (a -> b) -> a -> b
$
            (String -> Ident) -> [String] -> [Ident]
forall a b. (a -> b) -> [a] -> [b]
map (FastString -> Ident
TxtI (FastString -> Ident) -> (String -> FastString) -> String -> Ident
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> FastString
mkFastString) ([String] -> [Ident]) -> [String] -> [Ident]
forall a b. (a -> b) -> a -> b
$
            (Char -> String) -> String -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (Char -> ShowS
forall a. a -> [a] -> [a]
:[]) String
chars0 [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ (Int -> [String]) -> [Int] -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Int -> [String]
mkIdents [Int
1..]
  where
    mkIdents :: Int -> [String]
mkIdents Int
n = [Char
c0Char -> ShowS
forall a. a -> [a] -> [a]
:String
cs | Char
c0 <- String
chars0, String
cs <- Int -> String -> [String]
forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM Int
n String
chars]
    chars0 :: String
chars0 = [Char
'a'..Char
'z']String -> ShowS
forall a. [a] -> [a] -> [a]
++[Char
'A'..Char
'Z']
    chars :: String
chars = String
chars0String -> ShowS
forall a. [a] -> [a] -> [a]
++[Char
'0'..Char
'9']
    isReserved :: Ident -> Bool
isReserved (TxtI FastString
i) = FastString
i FastString -> UniqSet FastString -> Bool
forall a. Uniquable a => a -> UniqSet a -> Bool
`US.elementOfUniqSet` UniqSet FastString
reservedSet
    reservedSet :: UniqSet FastString
reservedSet = [FastString] -> UniqSet FastString
forall a. Uniquable a => [a] -> UniqSet a
US.mkUniqSet [FastString]
reserved
    reserved :: [FastString]
reserved = [  -- reserved words
                  FastString
"abstract", FastString
"arguments", FastString
"await", FastString
"boolean"
                , FastString
"break", FastString
"byte", FastString
"case", FastString
"catch"
                , FastString
"char", FastString
"class", FastString
"const", FastString
"continue"
                , FastString
"debugger", FastString
"default", FastString
"delete", FastString
"do"
                , FastString
"double", FastString
"else", FastString
"enum", FastString
"eval"
                , FastString
"export", FastString
"extends", FastString
"false", FastString
"final"
                , FastString
"finally", FastString
"float", FastString
"for", FastString
"function"
                , FastString
"goto", FastString
"if", FastString
"implements", FastString
"import"
                , FastString
"in", FastString
"instanceof", FastString
"int", FastString
"interface"
                , FastString
"let", FastString
"long", FastString
"native", FastString
"new"
                , FastString
"null", FastString
"package", FastString
"private", FastString
"protected"
                , FastString
"public", FastString
"return", FastString
"short", FastString
"static"
                , FastString
"super", FastString
"switch", FastString
"synchronized", FastString
"this"
                , FastString
"throw", FastString
"throws", FastString
"transient", FastString
"true"
                , FastString
"try", FastString
"typeof", FastString
"var", FastString
"void"
                , FastString
"volatile", FastString
"while", FastString
"with", FastString
"yield"
                -- some special values
                , FastString
"as", FastString
"async", FastString
"from", FastString
"get"
                , FastString
"of", FastString
"NaN", FastString
"prototype", FastString
"undefined"
                ]

mkRewrite :: Bool -> AnalysisResult -> Maybe SimpleRewrite
mkRewrite :: Bool -> AnalysisResult -> Maybe SimpleRewrite
mkRewrite Bool
do_rename AnalysisResult
a
  | AnalysisResult -> Bool
arBailout AnalysisResult
a = Maybe SimpleRewrite
forall a. Maybe a
Nothing
  | Bool
otherwise  = SimpleRewrite -> Maybe SimpleRewrite
forall a. a -> Maybe a
Just (SimpleRewrite -> Maybe SimpleRewrite)
-> SimpleRewrite -> Maybe SimpleRewrite
forall a b. (a -> b) -> a -> b
$
  SimpleRewrite { renameVar :: UniqMap Ident Ident
renameVar = if Bool
do_rename
                              then [(Ident, Ident)] -> UniqMap Ident Ident
forall k a. Uniquable k => [(k, a)] -> UniqMap k a
UM.listToUniqMap ([Ident] -> [Ident] -> [(Ident, Ident)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Ident]
localVars [Ident]
newVars)
                              else UniqMap Ident Ident
forall k a. UniqMap k a
UM.emptyUniqMap
                , varUsage :: UniqMap Ident VarUsage
varUsage = UniqMap Ident VarUsage
vu
                }
  where
    vu :: UM.UniqMap Ident VarUsage
    vu :: UniqMap Ident VarUsage
vu = AnalysisResult -> UniqMap Ident VarUsage
arVarUsage AnalysisResult
a

    -- local variables in the order that they were declared
    localVars :: [Ident]
    localVars :: [Ident]
localVars =
        ((Ident, VarDecl) -> Ident) -> [(Ident, VarDecl)] -> [Ident]
forall a b. (a -> b) -> [a] -> [b]
map (Ident, VarDecl) -> Ident
forall a b. (a, b) -> a
fst
         -- recover original order and remove non-determinism
      ([(Ident, VarDecl)] -> [Ident])
-> ([(Ident, VarUsage)] -> [(Ident, VarDecl)])
-> [(Ident, VarUsage)]
-> [Ident]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Ident, VarDecl) -> (Ident, VarDecl) -> Ordering)
-> [(Ident, VarDecl)] -> [(Ident, VarDecl)]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (VarDecl -> VarDecl -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (VarDecl -> VarDecl -> Ordering)
-> ((Ident, VarDecl) -> VarDecl)
-> (Ident, VarDecl)
-> (Ident, VarDecl)
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (Ident, VarDecl) -> VarDecl
forall a b. (a, b) -> b
snd)
      ([(Ident, VarDecl)] -> [(Ident, VarDecl)])
-> ([(Ident, VarUsage)] -> [(Ident, VarDecl)])
-> [(Ident, VarUsage)]
-> [(Ident, VarDecl)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Ident, VarUsage) -> (Ident, VarDecl))
-> [(Ident, VarUsage)] -> [(Ident, VarDecl)]
forall a b. (a -> b) -> [a] -> [b]
map (\(Ident
v, VarUsage
u) -> (Ident
v, VarUsage -> VarDecl
varDeclared VarUsage
u))
      ([(Ident, VarUsage)] -> [(Ident, VarDecl)])
-> ([(Ident, VarUsage)] -> [(Ident, VarUsage)])
-> [(Ident, VarUsage)]
-> [(Ident, VarDecl)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Ident, VarUsage) -> Bool)
-> [(Ident, VarUsage)] -> [(Ident, VarUsage)]
forall a. (a -> Bool) -> [a] -> [a]
filter (VarDecl -> Bool
isDecl (VarDecl -> Bool)
-> ((Ident, VarUsage) -> VarDecl) -> (Ident, VarUsage) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VarUsage -> VarDecl
varDeclared (VarUsage -> VarDecl)
-> ((Ident, VarUsage) -> VarUsage) -> (Ident, VarUsage) -> VarDecl
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Ident, VarUsage) -> VarUsage
forall a b. (a, b) -> b
snd)
      -- non-determinism is removed by sorting afterwards
      ([(Ident, VarUsage)] -> [Ident]) -> [(Ident, VarUsage)] -> [Ident]
forall a b. (a -> b) -> a -> b
$ UniqMap Ident VarUsage -> [(Ident, VarUsage)]
forall k a. UniqMap k a -> [(k, a)]
UM.nonDetUniqMapToList UniqMap Ident VarUsage
vu
    -- we can't rename variables that are used in the global scope
    blockedNames :: US.UniqSet Ident
    blockedNames :: UniqSet Ident
blockedNames =
      [Ident] -> UniqSet Ident
forall a. Uniquable a => [a] -> UniqSet a
US.mkUniqSet ([Ident] -> UniqSet Ident) -> [Ident] -> UniqSet Ident
forall a b. (a -> b) -> a -> b
$
      ((Ident, VarUsage) -> Ident) -> [(Ident, VarUsage)] -> [Ident]
forall a b. (a -> b) -> [a] -> [b]
map (Ident, VarUsage) -> Ident
forall a b. (a, b) -> a
fst (
      ((Ident, VarUsage) -> Bool)
-> [(Ident, VarUsage)] -> [(Ident, VarUsage)]
forall a. (a -> Bool) -> [a] -> [a]
filter (\(Ident
_k,VarUsage
v) -> (Bool -> Bool
not (Bool -> Bool) -> (VarDecl -> Bool) -> VarDecl -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VarDecl -> Bool
isDecl) (VarUsage -> VarDecl
varDeclared VarUsage
v) Bool -> Bool -> Bool
|| VarUsage -> Bool
varDeepDeclared VarUsage
v)
             (UniqMap Ident VarUsage -> [(Ident, VarUsage)]
forall k a. UniqMap k a -> [(k, a)]
UM.nonDetUniqMapToList UniqMap Ident VarUsage
vu))


    newVars :: [Ident]
    newVars :: [Ident]
newVars = (Ident -> Bool) -> [Ident] -> [Ident]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (Ident -> Bool) -> Ident -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Ident -> UniqSet Ident -> Bool
forall a. Uniquable a => a -> UniqSet a -> Bool
`US.elementOfUniqSet` UniqSet Ident
blockedNames)) [Ident]
newLocals

simpleRewrite :: SimpleRewrite -> JFunction -> JFunction
simpleRewrite :: SimpleRewrite -> JFunction -> JFunction
simpleRewrite SimpleRewrite
rw (JFunction [Ident]
args JStat
stat)= [Ident] -> JStat -> JFunction
JFunction ((Ident -> Ident) -> [Ident] -> [Ident]
forall a b. (a -> b) -> [a] -> [b]
map Ident -> Ident
varReplace [Ident]
args) (JStat -> JStat
go JStat
stat)
  where
    zeroUsed :: JExpr -> Bool
    zeroUsed :: JExpr -> Bool
zeroUsed (ValExpr (JVar Ident
v)) =
      Bool -> (VarUsage -> Bool) -> Maybe VarUsage -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
True ((Multiplicity -> Multiplicity -> Bool
forall a. Eq a => a -> a -> Bool
== Multiplicity
Zero) (Multiplicity -> Bool)
-> (VarUsage -> Multiplicity) -> VarUsage -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VarUsage -> Multiplicity
varUsed) (UniqMap Ident VarUsage -> Ident -> Maybe VarUsage
forall k a. Uniquable k => UniqMap k a -> k -> Maybe a
UM.lookupUniqMap (SimpleRewrite -> UniqMap Ident VarUsage
varUsage SimpleRewrite
rw) Ident
v) Bool -> Bool -> Bool
&&
      Bool -> (VarUsage -> Bool) -> Maybe VarUsage -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (VarDecl -> Bool
isDecl (VarDecl -> Bool) -> (VarUsage -> VarDecl) -> VarUsage -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VarUsage -> VarDecl
varDeclared) (UniqMap Ident VarUsage -> Ident -> Maybe VarUsage
forall k a. Uniquable k => UniqMap k a -> k -> Maybe a
UM.lookupUniqMap (SimpleRewrite -> UniqMap Ident VarUsage
varUsage SimpleRewrite
rw) Ident
v)
    zeroUsed JExpr
_                  = Bool
False

    varReplace :: Ident -> Ident
    varReplace :: Ident -> Ident
varReplace Ident
v = Ident -> Maybe Ident -> Ident
forall a. a -> Maybe a -> a
fromMaybe Ident
v (UniqMap Ident Ident -> Ident -> Maybe Ident
forall k a. Uniquable k => UniqMap k a -> k -> Maybe a
UM.lookupUniqMap (SimpleRewrite -> UniqMap Ident Ident
renameVar SimpleRewrite
rw) Ident
v)

    {-
      We can sometimes float down an expression to avoid an assignment:

      var x = e;
      f(x);
        ==>
      f(e);

      This can only be done if the expression has no side effects and x is
      only used once.

      Heap object property lookups cannot be floated just yet, since we
      don't know whether an object is mutable or not. For example a thunk
      can be blackholed, which would change the result if we float the lookup
      after the blackholing.
     -}

    mayBeFloated :: JExpr -> Bool
    mayBeFloated :: JExpr -> Bool
mayBeFloated (ValExpr JVal
v) = JVal -> Bool
mayBeFloatedV JVal
v
    mayBeFloated (SelExpr JExpr
_e Ident
_) = Bool
False
    mayBeFloated (IdxExpr JExpr
_e1 JExpr
_e2) = Bool
False
    mayBeFloated (InfixExpr Op
_ JExpr
e1 JExpr
e2)= JExpr -> Bool
mayBeFloated JExpr
e1 Bool -> Bool -> Bool
&& JExpr -> Bool
mayBeFloated JExpr
e2
    mayBeFloated (UOpExpr UOp
_ JExpr
_e) = Bool
False
    mayBeFloated (IfExpr JExpr
e1 JExpr
e2 JExpr
e3) = JExpr -> Bool
mayBeFloated JExpr
e1 Bool -> Bool -> Bool
&&
                                     JExpr -> Bool
mayBeFloated JExpr
e2 Bool -> Bool -> Bool
&&
                                     JExpr -> Bool
mayBeFloated JExpr
e3
    mayBeFloated (ApplExpr JExpr
e [JExpr]
es)
      | ValExpr (JVar (TxtI FastString
i)) <- JExpr
e, FastString -> Bool
isClosureAllocator FastString
i = (JExpr -> Bool) -> [JExpr] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all JExpr -> Bool
mayBeFloated [JExpr]
es
      | Bool
otherwise                                          = Bool
False

    mayBeFloatedV :: JVal -> Bool
    mayBeFloatedV :: JVal -> Bool
mayBeFloatedV (JVar Ident
v)
      | Just VarUsage
vu <- UniqMap Ident VarUsage -> Ident -> Maybe VarUsage
forall k a. Uniquable k => UniqMap k a -> k -> Maybe a
UM.lookupUniqMap (SimpleRewrite -> UniqMap Ident VarUsage
varUsage SimpleRewrite
rw) Ident
v
      = VarDecl -> Bool
isDecl (VarUsage -> VarDecl
varDeclared VarUsage
vu) Bool -> Bool -> Bool
&& Bool -> Bool
not (VarUsage -> Bool
assignedMultiple VarUsage
vu)
      | Bool
otherwise = Bool
False
    mayBeFloatedV (JList [JExpr]
es) = (JExpr -> Bool) -> [JExpr] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all JExpr -> Bool
mayBeFloated [JExpr]
es
    mayBeFloatedV (JDouble {}) = Bool
True
    mayBeFloatedV (JInt {}) = Bool
True
    mayBeFloatedV (JStr {}) = Bool
True
    mayBeFloatedV (JRegEx {}) = Bool
True
    mayBeFloatedV (JBool {}) = Bool
True
    mayBeFloatedV (JHash UniqMap FastString JExpr
ps) = ((FastString, JExpr) -> Bool) -> [(FastString, JExpr)] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (JExpr -> Bool
mayBeFloated (JExpr -> Bool)
-> ((FastString, JExpr) -> JExpr) -> (FastString, JExpr) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FastString, JExpr) -> JExpr
forall a b. (a, b) -> b
snd)
                                   (UniqMap FastString JExpr -> [(FastString, JExpr)]
forall k a. UniqMap k a -> [(k, a)]
UM.nonDetUniqMapToList UniqMap FastString JExpr
ps)
    mayBeFloatedV (JFunc {}) = Bool
False

    {-
       we allow small literals and local variables and arguments to be
       duplicated, since they tend to take up little space.
      -}
    mayDuplicate :: JExpr -> Bool
    mayDuplicate :: JExpr -> Bool
mayDuplicate (ValExpr (JVar Ident
i))
      | Just VarUsage
vu <- (UniqMap Ident VarUsage -> Ident -> Maybe VarUsage
forall k a. Uniquable k => UniqMap k a -> k -> Maybe a
UM.lookupUniqMap (SimpleRewrite -> UniqMap Ident VarUsage
varUsage SimpleRewrite
rw) Ident
i)
      = VarDecl -> Bool
isLocalOrArg (VarUsage -> VarDecl
varDeclared VarUsage
vu)
    mayDuplicate (ValExpr (JInt Integer
n))     = Integer -> Integer
forall a. Num a => a -> a
abs Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
1000000
    mayDuplicate (ValExpr (JDouble {})) = Bool
True
    mayDuplicate JExpr
_                      = Bool
False

    zeroAssigned :: Ident -> Bool
    zeroAssigned :: Ident -> Bool
zeroAssigned Ident
v
       | Just VarUsage
vu <- UniqMap Ident VarUsage -> Ident -> Maybe VarUsage
forall k a. Uniquable k => UniqMap k a -> k -> Maybe a
UM.lookupUniqMap (SimpleRewrite -> UniqMap Ident VarUsage
varUsage SimpleRewrite
rw) Ident
v
       = case VarUsage -> VarValue
varAssigned VarUsage
vu of
          VarValue
Unassigned -> Bool
True
          VarValue
_          -> Bool
False
      | Bool
otherwise = Bool
False

    assignedAtMostOnce :: Ident -> Bool
    assignedAtMostOnce :: Ident -> Bool
assignedAtMostOnce Ident
v
      | Just VarUsage
vu <- UniqMap Ident VarUsage -> Ident -> Maybe VarUsage
forall k a. Uniquable k => UniqMap k a -> k -> Maybe a
UM.lookupUniqMap (SimpleRewrite -> UniqMap Ident VarUsage
varUsage SimpleRewrite
rw) Ident
v =
        case VarUsage -> VarValue
varAssigned VarUsage
vu of
          VarValue
Unassigned           -> Bool
True
          VarValue
AssignedOnce         -> Bool
True
          AssignedOnceKnown {} -> Bool
True
          VarValue
AssignedMany         -> Bool
False
      | Bool
otherwise = Bool
False

    go :: JStat -> JStat
    go :: JStat -> JStat
go (DeclStat Ident
v Maybe JExpr
mb_e)
        | JExpr -> Bool
zeroUsed (JVal -> JExpr
ValExpr (Ident -> JVal
JVar Ident
v)) =
          case Maybe JExpr
mb_e of
            Maybe JExpr
Nothing | Ident -> Bool
zeroAssigned Ident
v -> [JStat] -> JStat
BlockStat []
                    | Bool
otherwise      -> Ident -> Maybe JExpr -> JStat
DeclStat (Ident -> Ident
varReplace Ident
v) Maybe JExpr
forall a. Maybe a
Nothing
            Just JExpr
e | Bool -> Bool
not (JExpr -> Bool
mayHaveSideEffects JExpr
e) Bool -> Bool -> Bool
&& Ident -> Bool
assignedAtMostOnce Ident
v
                                                -> [JStat] -> JStat
BlockStat []
                   | Bool
otherwise                  -> Ident -> Maybe JExpr -> JStat
DeclStat (Ident -> Ident
varReplace Ident
v) (JExpr -> Maybe JExpr
forall a. a -> Maybe a
Just (Bool -> JExpr -> JExpr
goE Bool
True JExpr
e))
        | Bool
otherwise = Ident -> Maybe JExpr -> JStat
DeclStat (Ident -> Ident
varReplace Ident
v) ((JExpr -> JExpr) -> Maybe JExpr -> Maybe JExpr
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Bool -> JExpr -> JExpr
goE Bool
True) Maybe JExpr
mb_e)
    go (AssignStat JExpr
lhs AOp
aop JExpr
e)
        | ValExpr (JVar Ident
i) <- JExpr
lhs, Ident -> AOp -> JExpr -> Bool
isTrivialAssignment Ident
i AOp
aop JExpr
e = [JStat] -> JStat
BlockStat []
        | JExpr -> Bool
zeroUsed JExpr
lhs Bool -> Bool -> Bool
&& Bool -> Bool
not (JExpr -> Bool
mayHaveSideEffects JExpr
e) = [JStat] -> JStat
BlockStat []
        | JExpr -> Bool
zeroUsed JExpr
lhs = JExpr -> AOp -> JExpr -> JStat
AssignStat (Bool -> JExpr -> JExpr
goE Bool
False JExpr
lhs) AOp
aop (Bool -> JExpr -> JExpr
goE Bool
True JExpr
e)
        | Bool
otherwise = JExpr -> AOp -> JExpr -> JStat
AssignStat (Bool -> JExpr -> JExpr
goE Bool
False JExpr
lhs) AOp
aop (Bool -> JExpr -> JExpr
goE Bool
True JExpr
e)
    go (ReturnStat JExpr
e) = JExpr -> JStat
ReturnStat (Bool -> JExpr -> JExpr
goE Bool
True JExpr
e)
    go (BlockStat [JStat]
ss) = [JStat] -> JStat
flattenBlock ((JStat -> JStat) -> [JStat] -> [JStat]
forall a b. (a -> b) -> [a] -> [b]
map JStat -> JStat
go [JStat]
ss)
    go (IfStat JExpr
e JStat
s1 JStat
s2) = JExpr -> JStat -> JStat -> JStat
IfStat (Bool -> JExpr -> JExpr
goE Bool
True JExpr
e) (JStat -> JStat
go JStat
s1) (JStat -> JStat
go JStat
s2)
    go (WhileStat Bool
b JExpr
e JStat
s) = Bool -> JExpr -> JStat -> JStat
WhileStat Bool
b (Bool -> JExpr -> JExpr
goE Bool
True JExpr
e) (JStat -> JStat
go JStat
s)
    go (ForStat JStat
s1 JExpr
e JStat
s2 JStat
s3) = JStat -> JExpr -> JStat -> JStat -> JStat
ForStat (JStat -> JStat
go JStat
s1) (Bool -> JExpr -> JExpr
goE Bool
True JExpr
e) (JStat -> JStat
go JStat
s2) (JStat -> JStat
go JStat
s3)
    go (ForInStat Bool
b Ident
v JExpr
e JStat
s) = Bool -> Ident -> JExpr -> JStat -> JStat
ForInStat Bool
b (Ident -> Ident
varReplace Ident
v) (Bool -> JExpr -> JExpr
goE Bool
True JExpr
e) (JStat -> JStat
go JStat
s)
    go (SwitchStat JExpr
e [(JExpr, JStat)]
cases JStat
s) = JExpr -> [(JExpr, JStat)] -> JStat -> JStat
SwitchStat (Bool -> JExpr -> JExpr
goE Bool
True JExpr
e)
                                           (((JExpr, JStat) -> (JExpr, JStat))
-> [(JExpr, JStat)] -> [(JExpr, JStat)]
forall a b. (a -> b) -> [a] -> [b]
map (\(JExpr
c,JStat
cs) -> (JExpr
c, JStat -> JStat
go JStat
cs)) [(JExpr, JStat)]
cases)
                                           (JStat -> JStat
go JStat
s)
    go (TryStat JStat
s1 Ident
v JStat
s2 JStat
s3) = JStat -> Ident -> JStat -> JStat -> JStat
TryStat (JStat -> JStat
go JStat
s1) (Ident -> Ident
varReplace Ident
v) (JStat -> JStat
go JStat
s2) (JStat -> JStat
go JStat
s3)
    go (ApplStat JExpr
e [JExpr]
es) = JExpr -> [JExpr] -> JStat
ApplStat (Bool -> JExpr -> JExpr
goE Bool
True JExpr
e) ((JExpr -> JExpr) -> [JExpr] -> [JExpr]
forall a b. (a -> b) -> [a] -> [b]
map (Bool -> JExpr -> JExpr
goE Bool
True) [JExpr]
es)
    go (UOpStat UOp
uop JExpr
e) = UOp -> JExpr -> JStat
UOpStat UOp
uop (Bool -> JExpr -> JExpr
goE Bool
False JExpr
e)
    go (LabelStat JLabel
lbl JStat
s) = JLabel -> JStat -> JStat
LabelStat JLabel
lbl (JStat -> JStat
go JStat
s)
    go s :: JStat
s@(BreakStat {}) = JStat
s
    go s :: JStat
s@(ContinueStat {}) = JStat
s
    go (FuncStat Ident
i [Ident]
args JStat
s) = Ident -> [Ident] -> JStat -> JStat
FuncStat Ident
i ((Ident -> Ident) -> [Ident] -> [Ident]
forall a b. (a -> b) -> [a] -> [b]
map Ident -> Ident
varReplace [Ident]
args) (JStat -> JStat
go JStat
s)

    goE :: Bool -> JExpr -> JExpr
    goE :: Bool -> JExpr -> JExpr
goE Bool
rhs (ValExpr (JVar Ident
v))
      | Bool
rhs
      , Just VarUsage
vu <- UniqMap Ident VarUsage -> Ident -> Maybe VarUsage
forall k a. Uniquable k => UniqMap k a -> k -> Maybe a
UM.lookupUniqMap (SimpleRewrite -> UniqMap Ident VarUsage
varUsage SimpleRewrite
rw) Ident
v
      , AssignedOnceKnown JExpr
ee <- VarUsage -> VarValue
varAssigned VarUsage
vu
      , VarUsage -> Multiplicity
varUsed VarUsage
vu Multiplicity -> Multiplicity -> Bool
forall a. Eq a => a -> a -> Bool
== Multiplicity
One Bool -> Bool -> Bool
|| JExpr -> Bool
mayDuplicate JExpr
ee
      , VarDecl -> Bool
isDecl (VarUsage -> VarDecl
varDeclared VarUsage
vu)
      , JExpr -> Bool
mayBeFloated JExpr
ee
      = Bool -> JExpr -> JExpr
goE Bool
rhs JExpr
ee
    goE Bool
_rhs (ValExpr JVal
v) = JVal -> JExpr
ValExpr (JVal -> JVal
goV JVal
v)
    goE Bool
rhs (SelExpr JExpr
e Ident
i) = JExpr -> Ident -> JExpr
SelExpr (Bool -> JExpr -> JExpr
goE Bool
rhs JExpr
e) Ident
i
    goE Bool
rhs (IdxExpr JExpr
e1 JExpr
e2) = JExpr -> JExpr -> JExpr
IdxExpr (Bool -> JExpr -> JExpr
goE Bool
rhs JExpr
e1) (Bool -> JExpr -> JExpr
goE Bool
rhs JExpr
e2)
    goE Bool
rhs (InfixExpr Op
op JExpr
e1 JExpr
e2) = Op -> JExpr -> JExpr -> JExpr
InfixExpr Op
op (Bool -> JExpr -> JExpr
goE Bool
rhs JExpr
e1) (Bool -> JExpr -> JExpr
goE Bool
rhs JExpr
e2)
    goE Bool
rhs (UOpExpr UOp
op JExpr
e) = UOp -> JExpr -> JExpr
UOpExpr UOp
op (Bool -> JExpr -> JExpr
goE Bool
rhs JExpr
e)
    goE Bool
rhs (IfExpr JExpr
e1 JExpr
e2 JExpr
e3) = JExpr -> JExpr -> JExpr -> JExpr
IfExpr (Bool -> JExpr -> JExpr
goE Bool
rhs JExpr
e1) (Bool -> JExpr -> JExpr
goE Bool
rhs JExpr
e2) (Bool -> JExpr -> JExpr
goE Bool
rhs JExpr
e3)
    goE Bool
rhs (ApplExpr JExpr
e [JExpr]
es) = JExpr -> [JExpr] -> JExpr
ApplExpr (Bool -> JExpr -> JExpr
goE Bool
rhs JExpr
e) ((JExpr -> JExpr) -> [JExpr] -> [JExpr]
forall a b. (a -> b) -> [a] -> [b]
map (Bool -> JExpr -> JExpr
goE Bool
rhs) [JExpr]
es)

    goV :: JVal -> JVal
    goV :: JVal -> JVal
goV (JVar Ident
v) = Ident -> JVal
JVar (Ident -> Ident
varReplace Ident
v)
    goV (JList [JExpr]
es) = [JExpr] -> JVal
JList ((JExpr -> JExpr) -> [JExpr] -> [JExpr]
forall a b. (a -> b) -> [a] -> [b]
map (Bool -> JExpr -> JExpr
goE Bool
True) [JExpr]
es)
    goV (JHash UniqMap FastString JExpr
ps) = UniqMap FastString JExpr -> JVal
JHash ((JExpr -> JExpr)
-> UniqMap FastString JExpr -> UniqMap FastString JExpr
forall a b.
(a -> b) -> UniqMap FastString a -> UniqMap FastString b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Bool -> JExpr -> JExpr
goE Bool
True) UniqMap FastString JExpr
ps)
    goV v :: JVal
v@(JFunc {}) = JVal
v
    goV v :: JVal
v@(JDouble {}) = JVal
v
    goV v :: JVal
v@(JInt {}) = JVal
v
    goV v :: JVal
v@(JStr {}) = JVal
v
    goV v :: JVal
v@(JRegEx {}) = JVal
v
    goV v :: JVal
v@(JBool {}) = JVal
v

flattenBlock :: [JStat] -> JStat
flattenBlock :: [JStat] -> JStat
flattenBlock [JStat]
stats =
    case (JStat -> Bool) -> [JStat] -> [JStat]
forall a. (a -> Bool) -> [a] -> [a]
filter (JStat -> JStat -> Bool
forall a. Eq a => a -> a -> Bool
/= [JStat] -> JStat
BlockStat []) [JStat]
stats of
        []  -> [JStat] -> JStat
BlockStat []
        [JStat
s] -> JStat
s
        [JStat]
ss  -> [JStat] -> JStat
BlockStat [JStat]
ss

data AnalysisResult = AnalysisResult
  { AnalysisResult -> Bool
arBailout       :: !Bool
  , AnalysisResult -> UniqMap Ident VarUsage
arVarUsage      :: !(UniqMap Ident VarUsage)
  , AnalysisResult -> Int
arDeclaredCount :: !Int
  }

simpleAnalyze :: JFunction -> AnalysisResult
simpleAnalyze :: JFunction -> AnalysisResult
simpleAnalyze (JFunction [Ident]
args JStat
body) = Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
False (Bool -> UniqMap Ident VarUsage -> Int -> AnalysisResult
AnalysisResult Bool
False UniqMap Ident VarUsage
start Int
0) JStat
body
  where
    start :: UniqMap Ident VarUsage
    start :: UniqMap Ident VarUsage
start = [(Ident, VarUsage)] -> UniqMap Ident VarUsage
forall k a. Uniquable k => [(k, a)] -> UniqMap k a
UM.listToUniqMap
          ([(Ident, VarUsage)] -> UniqMap Ident VarUsage)
-> [(Ident, VarUsage)] -> UniqMap Ident VarUsage
forall a b. (a -> b) -> a -> b
$ (Int -> Ident -> (Ident, VarUsage))
-> [Int] -> [Ident] -> [(Ident, VarUsage)]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (\Int
n Ident
v -> (Ident
v, Multiplicity -> VarValue -> VarDecl -> Bool -> VarUsage
VarUsage Multiplicity
Zero VarValue
Unassigned (Int -> VarDecl
ArgDecl Int
n) Bool
False))
                    [Int
0..]
                    [Ident]
args

    add :: Ident -> VarUsage -> AnalysisResult -> AnalysisResult
    add :: Ident -> VarUsage -> AnalysisResult -> AnalysisResult
add Ident
i VarUsage
vu AnalysisResult
m = AnalysisResult
m { arVarUsage = UM.addToUniqMap_C (Semi.<>) (arVarUsage m) i vu }


    declare :: Bool -> Ident -> Maybe JExpr -> AnalysisResult -> AnalysisResult
    declare :: Bool -> Ident -> Maybe JExpr -> AnalysisResult -> AnalysisResult
declare Bool
True Ident
i Maybe JExpr
_assign AnalysisResult
m = -- declaration in deeper scope
      let vu :: VarUsage
vu = Multiplicity -> VarValue -> VarDecl -> Bool -> VarUsage
VarUsage Multiplicity
Zero VarValue
AssignedMany VarDecl
NoDecl Bool
True
      in  AnalysisResult
m { arVarUsage = UM.addToUniqMap_C (Semi.<>) (arVarUsage m) i vu}
    declare Bool
False Ident
i Maybe JExpr
assign AnalysisResult
m = -- declaration in analyzed scope
      let count :: Int
count  = AnalysisResult -> Int
arDeclaredCount AnalysisResult
m
          !newCount :: Int
newCount
            | Just (VarUsage Multiplicity
_ VarValue
_ (LocalDecl Int
_) Bool
_) <-
                UniqMap Ident VarUsage -> Ident -> Maybe VarUsage
forall k a. Uniquable k => UniqMap k a -> k -> Maybe a
UM.lookupUniqMap (AnalysisResult -> UniqMap Ident VarUsage
arVarUsage AnalysisResult
m) Ident
i = Int
count -- already declared
            | Bool
otherwise                           = Int
count Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
          vassign :: VarValue
vassign | Just JExpr
e <- Maybe JExpr
assign = JExpr -> VarValue
AssignedOnceKnown JExpr
e
                  | Bool
otherwise        = VarValue
Unassigned
          !vu :: VarUsage
vu = Multiplicity -> VarValue -> VarDecl -> Bool -> VarUsage
VarUsage Multiplicity
Zero VarValue
vassign (Int -> VarDecl
LocalDecl Int
count) Bool
False
      in AnalysisResult
m { arDeclaredCount = newCount
           , arVarUsage = UM.addToUniqMap_C (Semi.<>) (arVarUsage m) i vu
           }

    go :: Bool -> AnalysisResult -> JStat -> AnalysisResult
    go :: Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
deep AnalysisResult
u (DeclStat Ident
v Maybe JExpr
mb_e) =
        case Maybe JExpr
mb_e of
            Maybe JExpr
Nothing -> Bool -> Ident -> Maybe JExpr -> AnalysisResult -> AnalysisResult
declare Bool
deep Ident
v Maybe JExpr
mb_e AnalysisResult
u
            Just JExpr
e  -> Bool -> Ident -> Maybe JExpr -> AnalysisResult -> AnalysisResult
declare Bool
deep Ident
v Maybe JExpr
mb_e (AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u JExpr
e)
    go Bool
_deep AnalysisResult
u (AssignStat (ValExpr (JVar Ident
v)) AOp
aop JExpr
e) =
        let use :: Multiplicity
use = case AOp
aop of
                    AOp
AssignOp -> Multiplicity
Zero
                    AOp
_        -> Multiplicity
One
        in Ident -> VarUsage -> AnalysisResult -> AnalysisResult
add Ident
v (Multiplicity -> VarValue -> VarDecl -> Bool -> VarUsage
VarUsage Multiplicity
use (JExpr -> VarValue
AssignedOnceKnown JExpr
e) VarDecl
NoDecl Bool
False) (AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u JExpr
e)
    go Bool
_deep AnalysisResult
u (AssignStat JExpr
lhs AOp
_aop JExpr
rhs) = AnalysisResult -> JExpr -> AnalysisResult
goE (AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u JExpr
lhs) JExpr
rhs
    go Bool
_deep AnalysisResult
u (ReturnStat JExpr
e) = AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u JExpr
e
    go Bool
deep AnalysisResult
u (BlockStat [JStat]
ss) = (AnalysisResult -> JStat -> AnalysisResult)
-> AnalysisResult -> [JStat] -> AnalysisResult
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
deep) AnalysisResult
u [JStat]
ss
    go Bool
deep AnalysisResult
u (IfStat JExpr
e JStat
s1 JStat
s2) = Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
deep (Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
deep (AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u JExpr
e) JStat
s1) JStat
s2
    go Bool
deep AnalysisResult
u (WhileStat Bool
_b JExpr
e JStat
s) = Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
deep (AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u JExpr
e) JStat
s
    go Bool
deep AnalysisResult
u (ForStat JStat
s1 JExpr
e JStat
s2 JStat
s3)
      = Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
deep (Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
deep (AnalysisResult -> JExpr -> AnalysisResult
goE (Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
deep AnalysisResult
u JStat
s1) JExpr
e) JStat
s2) JStat
s3
    go Bool
deep AnalysisResult
u (ForInStat Bool
b Ident
v JExpr
e JStat
s) =
      let !u' :: AnalysisResult
u' = if Bool
b then Bool -> Ident -> Maybe JExpr -> AnalysisResult -> AnalysisResult
declare Bool
deep Ident
v Maybe JExpr
forall a. Maybe a
Nothing AnalysisResult
u else AnalysisResult
u
      in  Ident -> VarUsage -> AnalysisResult -> AnalysisResult
add Ident
v (Multiplicity -> VarValue -> VarDecl -> Bool -> VarUsage
VarUsage Multiplicity
Zero VarValue
AssignedMany VarDecl
NoDecl Bool
True)
                (Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
deep (Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
deep (AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u' JExpr
e) JStat
s) JStat
s)
    go Bool
deep AnalysisResult
u (SwitchStat JExpr
e [(JExpr, JStat)]
cases JStat
s)
      = Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
deep (AnalysisResult -> JExpr -> AnalysisResult
goE ((AnalysisResult -> JStat -> AnalysisResult)
-> AnalysisResult -> [JStat] -> AnalysisResult
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
deep) AnalysisResult
u (((JExpr, JStat) -> JStat) -> [(JExpr, JStat)] -> [JStat]
forall a b. (a -> b) -> [a] -> [b]
map (JExpr, JStat) -> JStat
forall a b. (a, b) -> b
snd [(JExpr, JStat)]
cases)) JExpr
e) JStat
s
    go Bool
deep AnalysisResult
u (TryStat JStat
s1 Ident
v JStat
s2 JStat
s3)
      = Ident -> VarUsage -> AnalysisResult -> AnalysisResult
add Ident
v (Multiplicity -> VarValue -> VarDecl -> Bool -> VarUsage
VarUsage Multiplicity
Zero VarValue
AssignedMany VarDecl
NoDecl Bool
True)
              (Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
deep (Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
deep (Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
deep AnalysisResult
u JStat
s1) JStat
s2) JStat
s3)
    go Bool
_deep AnalysisResult
u (ApplStat JExpr
e [JExpr]
es)
      | (ValExpr (JVar (TxtI FastString
i))) <- JExpr
e, FastString
i FastString -> FastString -> Bool
forall a. Eq a => a -> a -> Bool
== FastString
"eval" = AnalysisResult
u { arBailout = True }
      | Bool
otherwise = (AnalysisResult -> JExpr -> AnalysisResult)
-> AnalysisResult -> [JExpr] -> AnalysisResult
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' AnalysisResult -> JExpr -> AnalysisResult
goE (AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u JExpr
e) [JExpr]
es
    go Bool
_deep AnalysisResult
u (UOpStat UOp
op JExpr
e)
      | ValExpr (JVar Ident
v) <- JExpr
e
      , UOp
op UOp -> [UOp] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [UOp
PreIncOp, UOp
PostIncOp, UOp
PreDecOp, UOp
PostDecOp] =
          Ident -> VarUsage -> AnalysisResult -> AnalysisResult
add Ident
v (Multiplicity -> VarValue -> VarDecl -> Bool -> VarUsage
VarUsage Multiplicity
One VarValue
AssignedOnce VarDecl
NoDecl Bool
False) AnalysisResult
u
      | Bool
otherwise = AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u JExpr
e
    go Bool
deep AnalysisResult
u (LabelStat JLabel
_ JStat
s) = Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
deep AnalysisResult
u JStat
s
    go Bool
_deep AnalysisResult
u (BreakStat Maybe JLabel
_) = AnalysisResult
u
    go Bool
_deep AnalysisResult
u (ContinueStat Maybe JLabel
_) = AnalysisResult
u
    go Bool
_deep AnalysisResult
u (FuncStat Ident
_ [Ident]
vs JStat
s)
      = Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
True ((AnalysisResult -> Ident -> AnalysisResult)
-> AnalysisResult -> [Ident] -> AnalysisResult
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (\AnalysisResult
u Ident
v -> Ident -> VarUsage -> AnalysisResult -> AnalysisResult
add Ident
v (Multiplicity -> VarValue -> VarDecl -> Bool -> VarUsage
VarUsage Multiplicity
Zero VarValue
AssignedOnce VarDecl
NoDecl Bool
True) AnalysisResult
u) AnalysisResult
u [Ident]
vs) JStat
s

    goE :: AnalysisResult -> JExpr -> AnalysisResult
    goE :: AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u (ValExpr JVal
v) = AnalysisResult -> JVal -> AnalysisResult
goV AnalysisResult
u JVal
v
    goE AnalysisResult
u (SelExpr JExpr
e Ident
_i) = AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u JExpr
e
    goE AnalysisResult
u (IdxExpr JExpr
e1 JExpr
e2) = AnalysisResult -> JExpr -> AnalysisResult
goE (AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u JExpr
e1) JExpr
e2
    goE AnalysisResult
u (InfixExpr Op
_ JExpr
e1 JExpr
e2) = AnalysisResult -> JExpr -> AnalysisResult
goE (AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u JExpr
e1) JExpr
e2
    goE AnalysisResult
u (UOpExpr UOp
_ JExpr
e) = AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u JExpr
e
    goE AnalysisResult
u (IfExpr JExpr
e1 JExpr
e2 JExpr
e3) = AnalysisResult -> JExpr -> AnalysisResult
goE (AnalysisResult -> JExpr -> AnalysisResult
goE (AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u JExpr
e1) JExpr
e2) JExpr
e3
    goE AnalysisResult
u (ApplExpr JExpr
e [JExpr]
es)
      | (ValExpr (JVar (TxtI FastString
i))) <- JExpr
e, FastString
i FastString -> FastString -> Bool
forall a. Eq a => a -> a -> Bool
== FastString
"eval" = AnalysisResult
u { arBailout = True }
      | Bool
otherwise = (AnalysisResult -> JExpr -> AnalysisResult)
-> AnalysisResult -> [JExpr] -> AnalysisResult
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' AnalysisResult -> JExpr -> AnalysisResult
goE (AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u JExpr
e) [JExpr]
es

    goV :: AnalysisResult -> JVal -> AnalysisResult
    goV :: AnalysisResult -> JVal -> AnalysisResult
goV AnalysisResult
u (JVar Ident
v)   = Ident -> VarUsage -> AnalysisResult -> AnalysisResult
add Ident
v (Multiplicity -> VarValue -> VarDecl -> Bool -> VarUsage
VarUsage Multiplicity
One VarValue
Unassigned VarDecl
NoDecl Bool
False) AnalysisResult
u
    goV AnalysisResult
u (JList [JExpr]
es) = (AnalysisResult -> JExpr -> AnalysisResult)
-> AnalysisResult -> [JExpr] -> AnalysisResult
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u [JExpr]
es
    goV AnalysisResult
u (JDouble SaneDouble
_) = AnalysisResult
u
    goV AnalysisResult
u (JInt Integer
_) = AnalysisResult
u
    goV AnalysisResult
u (JStr FastString
_) = AnalysisResult
u
    goV AnalysisResult
u (JRegEx FastString
_) = AnalysisResult
u
    goV AnalysisResult
u (JBool Bool
_) = AnalysisResult
u
    goV AnalysisResult
u (JHash UniqMap FastString JExpr
ps) = (AnalysisResult -> JExpr -> AnalysisResult)
-> AnalysisResult -> [JExpr] -> AnalysisResult
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' AnalysisResult -> JExpr -> AnalysisResult
goE AnalysisResult
u (((FastString, JExpr) -> JExpr) -> [(FastString, JExpr)] -> [JExpr]
forall a b. (a -> b) -> [a] -> [b]
map (FastString, JExpr) -> JExpr
forall a b. (a, b) -> b
snd ([(FastString, JExpr)] -> [JExpr])
-> [(FastString, JExpr)] -> [JExpr]
forall a b. (a -> b) -> a -> b
$ UniqMap FastString JExpr -> [(FastString, JExpr)]
forall k a. UniqMap k a -> [(k, a)]
UM.nonDetUniqMapToList UniqMap FastString JExpr
ps)
    goV AnalysisResult
u (JFunc [Ident]
vs JStat
s)
      = Bool -> AnalysisResult -> JStat -> AnalysisResult
go Bool
True ((AnalysisResult -> Ident -> AnalysisResult)
-> AnalysisResult -> [Ident] -> AnalysisResult
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl (\AnalysisResult
u Ident
v -> Ident -> VarUsage -> AnalysisResult -> AnalysisResult
add Ident
v (Multiplicity -> VarValue -> VarDecl -> Bool -> VarUsage
VarUsage Multiplicity
Zero VarValue
AssignedOnce VarDecl
NoDecl Bool
True) AnalysisResult
u) AnalysisResult
u [Ident]
vs) JStat
s

-- | A trivial assignment is an assignment of a variable to itself: x = x
isTrivialAssignment :: Ident -> AOp -> JExpr -> Bool
isTrivialAssignment :: Ident -> AOp -> JExpr -> Bool
isTrivialAssignment Ident
v AOp
AssignOp (ValExpr (JVar Ident
v')) = Ident
v Ident -> Ident -> Bool
forall a. Eq a => a -> a -> Bool
== Ident
v'
isTrivialAssignment Ident
_ AOp
_ JExpr
_                          = Bool
False

-- | Does the expression have side effects?
--
-- This only returns False if the expression definitely does not have side
-- effects, i.e. it can be removed without changing the semantics if the
-- result is not used.
--
-- Note: We have some assumptions here about Haskell RTS related values, which
--       may not be true for all JavaScript code. We should really replace
--       these with explicit nodes or annotations in the AST.
--
mayHaveSideEffects :: JExpr -> Bool
-- special cases for Haskell things. These should really be special operations
-- in the AST:
-- 1. stack indexing does not have side effects
mayHaveSideEffects :: JExpr -> Bool
mayHaveSideEffects (IdxExpr (ValExpr (JVar (TxtI FastString
i))) JExpr
e)
  | FastString
i FastString -> FastString -> Bool
forall a. Eq a => a -> a -> Bool
== FastString
"h$stack" = JExpr -> Bool
mayHaveSideEffects JExpr
e
-- 2. we assume that x.d1, x.d2, ... are heap object property lookups,
--    which do not have side effects
mayHaveSideEffects (SelExpr JExpr
e (TxtI FastString
i))
  | FastString -> Bool
isHeapObjectProperty FastString
i = JExpr -> Bool
mayHaveSideEffects JExpr
e

-- general cases (no Haskell RTS specific assumptions here):
mayHaveSideEffects (ValExpr JVal
v) = JVal -> Bool
mayHaveSideEffectsV JVal
v
mayHaveSideEffects (SelExpr {}) = Bool
True
mayHaveSideEffects (IdxExpr {}) = Bool
True
mayHaveSideEffects (UOpExpr UOp
uop JExpr
e) = Bool
uo Bool -> Bool -> Bool
|| JExpr -> Bool
mayHaveSideEffects JExpr
e
    where
        uo :: Bool
uo = case UOp
uop of
              UOp
NotOp    -> Bool
False
              UOp
BNotOp   -> Bool
False
              UOp
NegOp    -> Bool
False
              UOp
PlusOp   -> Bool
False
              UOp
TypeofOp -> Bool
False
              UOp
_        -> Bool
True
mayHaveSideEffects (InfixExpr Op
_o JExpr
e1 JExpr
e2) =
  JExpr -> Bool
mayHaveSideEffects JExpr
e1 Bool -> Bool -> Bool
|| JExpr -> Bool
mayHaveSideEffects JExpr
e2
mayHaveSideEffects (IfExpr JExpr
e1 JExpr
e2 JExpr
e3) =
  JExpr -> Bool
mayHaveSideEffects JExpr
e1 Bool -> Bool -> Bool
|| JExpr -> Bool
mayHaveSideEffects JExpr
e2 Bool -> Bool -> Bool
|| JExpr -> Bool
mayHaveSideEffects JExpr
e3
mayHaveSideEffects (ApplExpr {}) = Bool
True

mayHaveSideEffectsV :: JVal -> Bool
mayHaveSideEffectsV :: JVal -> Bool
mayHaveSideEffectsV (JVar {}) = Bool
False
mayHaveSideEffectsV (JList [JExpr]
es) = (JExpr -> Bool) -> [JExpr] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any JExpr -> Bool
mayHaveSideEffects [JExpr]
es
mayHaveSideEffectsV (JDouble {}) = Bool
False
mayHaveSideEffectsV (JInt {}) = Bool
False
mayHaveSideEffectsV (JStr {}) = Bool
False
mayHaveSideEffectsV (JRegEx {}) = Bool
False
mayHaveSideEffectsV (JBool {}) = Bool
False
mayHaveSideEffectsV (JHash UniqMap FastString JExpr
ps) = (JExpr -> Bool) -> UniqMap FastString JExpr -> Bool
forall a k. (a -> Bool) -> UniqMap k a -> Bool
UM.anyUniqMap JExpr -> Bool
mayHaveSideEffects UniqMap FastString JExpr
ps
mayHaveSideEffectsV (JFunc {}) = Bool
True

isHeapObjectProperty :: FastString -> Bool
isHeapObjectProperty :: FastString -> Bool
isHeapObjectProperty FastString
"d1"  = Bool
True
isHeapObjectProperty FastString
"d2"  = Bool
True
isHeapObjectProperty FastString
"d3"  = Bool
True
isHeapObjectProperty FastString
"d4"  = Bool
True
isHeapObjectProperty FastString
"d5"  = Bool
True
isHeapObjectProperty FastString
"d6"  = Bool
True
isHeapObjectProperty FastString
"d7"  = Bool
True
isHeapObjectProperty FastString
"d8"  = Bool
True
isHeapObjectProperty FastString
"d9"  = Bool
True
isHeapObjectProperty FastString
"d10" = Bool
True
isHeapObjectProperty FastString
"d11" = Bool
True
isHeapObjectProperty FastString
"d12" = Bool
True
isHeapObjectProperty FastString
"d13" = Bool
True
isHeapObjectProperty FastString
"d14" = Bool
True
isHeapObjectProperty FastString
"d15" = Bool
True
isHeapObjectProperty FastString
"d16" = Bool
True
isHeapObjectProperty FastString
"d17" = Bool
True
isHeapObjectProperty FastString
"d18" = Bool
True
isHeapObjectProperty FastString
"d19" = Bool
True
isHeapObjectProperty FastString
"d20" = Bool
True
isHeapObjectProperty FastString
"d21" = Bool
True
isHeapObjectProperty FastString
"d22" = Bool
True
isHeapObjectProperty FastString
"d23" = Bool
True
isHeapObjectProperty FastString
"d24" = Bool
True

isHeapObjectProperty FastString
_     = Bool
False

isClosureAllocator :: FastString -> Bool
isClosureAllocator :: FastString -> Bool
isClosureAllocator FastString
"h$c1" = Bool
True
isClosureAllocator FastString
"h$c2" = Bool
True
isClosureAllocator FastString
"h$c3" = Bool
True
isClosureAllocator FastString
"h$c4" = Bool
True
isClosureAllocator FastString
"h$c5" = Bool
True
isClosureAllocator FastString
"h$c6" = Bool
True
isClosureAllocator FastString
"h$c7" = Bool
True
isClosureAllocator FastString
"h$c8" = Bool
True
isClosureAllocator FastString
"h$c9" = Bool
True
isClosureAllocator FastString
"h$c10" = Bool
True
isClosureAllocator FastString
"h$c11" = Bool
True
isClosureAllocator FastString
"h$c12" = Bool
True
isClosureAllocator FastString
"h$c13" = Bool
True
isClosureAllocator FastString
"h$c14" = Bool
True
isClosureAllocator FastString
"h$c15" = Bool
True
isClosureAllocator FastString
"h$c16" = Bool
True
isClosureAllocator FastString
"h$c17" = Bool
True
isClosureAllocator FastString
"h$c18" = Bool
True
isClosureAllocator FastString
"h$c19" = Bool
True
isClosureAllocator FastString
"h$c20" = Bool
True
isClosureAllocator FastString
"h$c21" = Bool
True
isClosureAllocator FastString
"h$c22" = Bool
True
isClosureAllocator FastString
"h$c23" = Bool
True
isClosureAllocator FastString
"h$c24" = Bool
True
isClosureAllocator FastString
_       = Bool
False