prepareAlts :: OutExpr -> OutId -> [InAlt] -> SimplM ([AltCon], [InAlt])
-- The returned alternatives can be empty, none are possible
prepareAlts scrut case_bndr' alts
  | Just (tc, tys) <- splitTyConApp_maybe (varType case_bndr')
           -- Case binder is needed just for its type. Note that as an
           --   OutId, it has maximum information; this is important.
           --   Test simpl013 is an example
  = do { us <- getUniquesM
       ; let (idcs1, alts1)       = filterAlts tc tys imposs_cons alts
             (yes2,  alts2)       = refineDefaultAlt us tc tys idcs1 alts1
             (yes3, idcs3, alts3) = combineIdenticalAlts idcs1 alts2
             -- "idcs" stands for "impossible default data constructors"
             -- i.e. the constructors that can't match the default case
       ; when yes2 $ tick (FillInCaseDefault case_bndr')
       ; when yes3 $ tick (AltMerge case_bndr')
       ; return (idcs3, alts3) }

  | otherwise  -- Not a data type, so nothing interesting happens
  = return ([], alts)
  where
    imposs_cons = case scrut of
                    Var v -> otherCons (idUnfolding v)
                    _     -> []


{-
************************************************************************
*                                                                      *
                mkCase
*                                                                      *
************************************************************************

mkCase tries these things

1.  Merge Nested Cases

       case e of b {             ==>   case e of b {
         p1 -> rhs1                      p1 -> rhs1
         ...                             ...
         pm -> rhsm                      pm -> rhsm
         _  -> case b of b' {            pn -> let b'=b in rhsn
                     pn -> rhsn          ...
                     ...                 po -> let b'=b in rhso
                     po -> rhso          _  -> let b'=b in rhsd
                     _  -> rhsd
       }

    which merges two cases in one case when -- the default alternative of
    the outer case scrutises the same variable as the outer case. This
    transformation is called Case Merging.  It avoids that the same
    variable is scrutinised multiple times.

2.  Eliminate Identity Case

        case e of               ===> e
                True  -> True;
                False -> False

    and similar friends.
-}
prepareAlts :: OutExpr -> OutId -> [InAlt] -> SimplM ([AltCon], [InAlt])
prepareAlts scrut case_bndr' alts
  | Just (tc, tys) <- splitTyConApp_maybe (varType case_bndr')
           -- Case binder is needed just for its type. Note that as an
           --   OutId, it has maximum information; this is important.
           --   Test simpl013 is an example
  = do { us <- getUniquesM
       ; let (idcs1, alts1)       = filterAlts tc tys imposs_cons alts
             (yes2,  alts2)       = refineDefaultAlt us tc tys idcs1 alts1
             (yes3, idcs3, alts3) = combineIdenticalAlts idcs1 alts2
             -- "idcs" stands for "impossible default data constructors"
             -- i.e. the constructors that can't match the default case
       ; when yes2 $ tick (FillInCaseDefault case_bndr')
       ; when yes3 $ tick (AltMerge case_bndr')
       ; return (idcs3, alts3) }

  | otherwise  -- Not a data type, so nothing interesting happens
  = return ([], alts)
  where
    imposs_cons = case scrut of
                    Var v -> otherCons (idUnfolding v)
                    _     -> []


{-
************************************************************************
*                                                                      *
                mkCase
*                                                                      *
************************************************************************

mkCase tries these things

1.  Merge Nested Cases

       case e of b {             ==>   case e of b {
         p1 -> rhs1                      p1 -> rhs1
         ...                             ...
         pm -> rhsm                      pm -> rhsm
         _  -> case b of b' {            pn -> let b'=b in rhsn
                     pn -> rhsn          ...
                     ...                 po -> let b'=b in rhso
                     po -> rhso          _  -> let b'=b in rhsd
                     _  -> rhsd
       }

    which merges two cases in one case when -- the default alternative of
    the outer case scrutises the same variable as the outer case. This
    transformation is called Case Merging.  It avoids that the same
    variable is scrutinised multiple times.

2.  Eliminate Identity Case

        case e of               ===> e
                True  -> True;
                False -> False

    and similar friends.
-}
prepareAlts scrut case_bndr' alts
  | Just (tc, tys) <- splitTyConApp_maybe (varType case_bndr')
           -- Case binder is needed just for its type. Note that as an
           --   OutId, it has maximum information; this is important.
           --   Test simpl013 is an example
  = do { us <- getUniquesM
       ; let (idcs1, alts1)       = filterAlts tc tys imposs_cons alts
             (yes2,  alts2)       = refineDefaultAlt us tc tys idcs1 alts1
             (yes3, idcs3, alts3) = combineIdenticalAlts idcs1 alts2
             -- "idcs" stands for "impossible default data constructors"
             -- i.e. the constructors that can't match the default case
       ; when yes2 $ tick (FillInCaseDefault case_bndr')
       ; when yes3 $ tick (AltMerge case_bndr')
       ; return (idcs3, alts3) }

  | otherwise  -- Not a data type, so nothing interesting happens
  = return ([], alts)
  where
    imposs_cons = case scrut of
                    Var v -> otherCons (idUnfolding v)
                    _     -> []


{-
************************************************************************
*                                                                      *
                mkCase
*                                                                      *
************************************************************************

mkCase tries these things

1.  Merge Nested Cases

       case e of b {             ==>   case e of b {
         p1 -> rhs1                      p1 -> rhs1
         ...                             ...
         pm -> rhsm                      pm -> rhsm
         _  -> case b of b' {            pn -> let b'=b in rhsn
                     pn -> rhsn          ...
                     ...                 po -> let b'=b in rhso
                     po -> rhso          _  -> let b'=b in rhsd
                     _  -> rhsd
       }

    which merges two cases in one case when -- the default alternative of
    the outer case scrutises the same variable as the outer case. This
    transformation is called Case Merging.  It avoids that the same
    variable is scrutinised multiple times.

2.  Eliminate Identity Case

        case e of               ===> e
                True  -> True;
                False -> False

    and similar friends.
-}