packages feed

Jikka-5.5.0.0: src/Jikka/Core/Convert/RemoveUnusedVars.hs

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}

-- |
-- Module      : Jikka.Core.Convert.RemoveUnusedVars
-- Description : removes unused variables. / 使われていない変数を削除します。
-- Copyright   : (c) Kimiyuki Onaka, 2020
-- License     : Apache License 2.0
-- Maintainer  : kimiyuki95@gmail.com
-- Stability   : experimental
-- Portability : portable
--
-- `Jikka.Language.Core.RemoveUnusedVars` remove unused variables from exprs.
module Jikka.Core.Convert.RemoveUnusedVars
  ( run,
    run',
  )
where

import Jikka.Common.Error
import Jikka.Core.Language.Expr
import Jikka.Core.Language.FreeVars (isUnusedVar)
import Jikka.Core.Language.Lint
import Jikka.Core.Language.Util

runExpr :: [(VarName, Type)] -> Expr -> Expr
runExpr _ = mapSubExpr go []
  where
    go _ = \case
      Let x _ _ e2 | x `isUnusedVar` e2 -> e2
      e -> e

-- | TODO: Remove `ToplevelLet` if its variable is not used.
runToplevelExpr :: [(VarName, Type)] -> ToplevelExpr -> ToplevelExpr
runToplevelExpr _ = \case
  ToplevelLetRec f args ret body cont ->
    if isUnusedVar f body
      then ToplevelLet f (curryFunTy (map snd args) ret) (curryLam args body) cont
      else ToplevelLetRec f args ret body cont
  e -> e

run' :: Program -> Program
run' = mapToplevelExprProgram runToplevelExpr . mapExprProgram (mapSubExpr runExpr)

-- | `run` removes unused variables in given programs.
--
-- This also removes variables for recursion, i.e. "rec" flags.
-- `ToplevelLetRec` may becomes `ToplevelLet`.
--
-- For example, this converts
--
-- > let rec solve x =
-- >     let y = 0
-- >     in x
-- > in solve
--
-- to
--
-- > let solve x =
-- >     x
-- > in solve
run :: MonadError Error m => Program -> m Program
run prog = wrapError' "Jikka.Core.Convert.RemoveUnusedVars" $ do
  precondition $ do
    lint prog
  prog <- return $ run' prog
  postcondition $ do
    lint prog
  return prog