purescript-0.14.6: src/Language/PureScript/CoreFn/Optimizer.hs
module Language.PureScript.CoreFn.Optimizer (optimizeCoreFn) where
import Protolude hiding (Type)
import Data.List (lookup)
import qualified Data.Text as T
import Language.PureScript.AST.Literals
import Language.PureScript.AST.SourcePos
import Language.PureScript.CoreFn.Ann
import Language.PureScript.CoreFn.Expr
import Language.PureScript.CoreFn.Module
import Language.PureScript.CoreFn.Traversals
import Language.PureScript.Names (Ident(..), ModuleName(..), Qualified(..))
import Language.PureScript.Label
import Language.PureScript.Types
import qualified Language.PureScript.Constants.Prelude as C
import qualified Language.PureScript.Constants.Prim as C
-- |
-- CoreFn optimization pass.
--
optimizeCoreFn :: Module Ann -> Module Ann
optimizeCoreFn m = m {moduleDecls = optimizeModuleDecls $ moduleDecls m}
optimizeModuleDecls :: [Bind Ann] -> [Bind Ann]
optimizeModuleDecls = map transformBinds
where
(transformBinds, _, _) = everywhereOnValues identity transformExprs identity
transformExprs
= optimizeClosedRecordUpdate
. optimizeDataFunctionApply
optimizeClosedRecordUpdate :: Expr Ann -> Expr Ann
optimizeClosedRecordUpdate ou@(ObjectUpdate a@(_, _, Just t, _) r updatedFields) =
case closedRecordFields t of
Nothing -> ou
Just allFields -> Literal a (ObjectLiteral (map f allFields))
where f (Label l) = case lookup l updatedFields of
Nothing -> (l, Accessor (nullSourceSpan, [], Nothing, Nothing) l r)
Just e -> (l, e)
optimizeClosedRecordUpdate e = e
-- | Return the labels of a closed record, or Nothing for other types or open records.
closedRecordFields :: Type a -> Maybe [Label]
closedRecordFields (TypeApp _ (TypeConstructor _ C.Record) row) =
collect row
where
collect :: Type a -> Maybe [Label]
collect (REmptyKinded _ _) = Just []
collect (RCons _ l _ r) = (l :) <$> collect r
collect _ = Nothing
closedRecordFields _ = Nothing
optimizeDataFunctionApply :: Expr a -> Expr a
optimizeDataFunctionApply e = case e of
(App a (App _ (Var _ (Qualified (Just (ModuleName mn)) (Ident fn))) x) y)
| mn == dataFunction && fn == C.apply -> App a x y
| mn == dataFunction && fn == C.applyFlipped -> App a y x
_ -> e
where
dataFunction :: Text
dataFunction = T.replace "_" "." C.dataFunction