content: {-# OPTIONS_GHC -O2 -fforce-recomp #-}
  
  -- | From Note [Boxity analysis] and related Notes
  module T19871 where
  
  data Huge
    = Huge
    { f1 :: Bool
    , f2 :: Bool
    , f3 :: Bool
    , f4 :: Bool
    , f5 :: Bool
    , f6 :: Bool
    , f7 :: Bool
    , f8 :: Bool
    , f9 :: Bool
    , f10 :: Bool
    , f11 :: Bool
    , f12 :: Bool }
  
  -- | Should not unbox Huge
  ann :: Huge -> (Bool, Huge)
  ann h@(Huge{f1=True}) = (False, h)
  ann h                 = (True,  h)
  {-# NOINLINE ann #-}
  
  -- A few examples demonstrating the lubBoxity = unboxedWins tradeoff
  
  -- | Should unbox 'z'.
  -- We won't with `lubBoxity = boxedWins`.
  -- We will  with `lubBoxity = unboxedWins`.
  sumIO :: Int -> Int -> IO Int
  sumIO 0 !z = return z
  sumIO n !z = sumIO (n-1) (z+n)
  {-# NOINLINE sumIO #-}
  
  -- | Should /not/ unbox 'h'.
  -- We won't with `lubBoxity = boxedWins`.
  -- We will  with `lubBoxity = unboxedWins`.
  update :: Huge -> (Bool, Huge)
  update h@(Huge{f1=True}) = (False, h{f1=False})
  update h                 = (True,  h)
  {-# NOINLINE update #-}
  
  -- | Should /not/ unbox 'h'.
  -- We won't with `lubBoxity = boxedWins`.
  -- We will  with `lubBoxity = unboxedWins`.
  guarded :: (Huge -> Bool) -> Huge -> Bool
  guarded g h | f1 h      = True
              | otherwise = g h
  {-# NOINLINE guarded #-}
  
  -- | Should /not/ unbox 'h'.
  -- We won't with `lubBoxity = boxedWins`.
  -- We will  with `lubBoxity = unboxedWins`.
  --
  -- This example also demonstrates the usefulness of carrying a Boxity in Poly.
  -- Most absent sub-demands here should be considered Boxed (and of course we
  -- also need Unboxed absent Poly). See Note [Boxity in Poly].
  absent :: Huge -> Int
  absent h = if f1 h || f2 h then g h else 2
    where
      g :: a -> Int
      g a = a `seq` f a True
      {-# NOINLINE g #-}
      f :: a -> Bool -> Int
      f _ True = 1
      f a False = a `seq` 2
      {-# NOINLINE f #-}
  {-# NOINLINE absent #-}
  