Skip to content

INLINABLE pragma prevents worker-wrapper to happen.

When working on containers I found out that a method returning a pair marked as INLINABLE does not go through a worker/wrapper transformation to get a worker that would return unboxed pair.

For example:

module Test where

smallerAndRest :: Ord a => a -> [a] -> (Maybe a, [a])
smallerAndRest x [] = (Nothing, [])
smallerAndRest x (y:ys) | y < x = (Just y, ys)
                        | otherwise = smallerAndRest x ys

{-# INLINABLE smallerAndRest #-}

With the INLINABLE pragma, -ddump-prep prints

==================== CorePrep ====================
Result size = 42

lvl_rkg :: forall a_ajz. (Data.Maybe.Maybe a_ajz, [a_ajz])
[GblId, Caf=NoCafRefs, Str=DmdType m, Unf=OtherCon []]
lvl_rkg =
  \ (@ a_ajz) -> (Data.Maybe.Nothing @ a_ajz, GHC.Types.[] @ a_ajz)

Rec {
Test.smallerAndRest [InlPrag=INLINABLE[ALWAYS], Occ=LoopBreaker]
  :: forall a_a9I.
     GHC.Classes.Ord a_a9I =>
     a_a9I -> [a_a9I] -> (Data.Maybe.Maybe a_a9I, [a_a9I])
[GblId, Arity=3, Caf=NoCafRefs, Str=DmdType LLSm, Unf=OtherCon []]
Test.smallerAndRest =
  \ (@ a_ajz)
    ($dOrd_sko :: GHC.Classes.Ord a_ajz)
    (x_skq :: a_ajz)
    (ds_skk :: [a_ajz]) ->
    case ds_skk of _ {
      [] -> lvl_rkg @ a_ajz;
      : y_skp ys_sks ->
        case GHC.Classes.< @ a_ajz $dOrd_sko y_skp x_skq of _ {
          GHC.Types.False ->
            Test.smallerAndRest @ a_ajz $dOrd_sko x_skq ys_sks;
          GHC.Types.True ->
            let {
              sat_skw :: Data.Maybe.Maybe a_ajz
              [LclId]
              sat_skw = Data.Maybe.Just @ a_ajz y_skp } in
            (sat_skw, ys_sks)
        }
    }
end Rec }

but without the INLINABLE pragma, we get

==================== CorePrep ====================
Result size = 57

Rec {
Test.$wsmallerAndRest [Occ=LoopBreaker]
  :: forall a_a9I.
     GHC.Classes.Ord a_a9I =>
     a_a9I -> [a_a9I] -> (# Data.Maybe.Maybe a_a9I, [a_a9I] #)
[GblId, Arity=3, Caf=NoCafRefs, Str=DmdType LLS, Unf=OtherCon []]
Test.$wsmallerAndRest =
  \ (@ a_a9I)
    (w_skC :: GHC.Classes.Ord a_a9I)
    (w1_skE :: a_a9I)
    (w2_sky :: [a_a9I]) ->
    case w2_sky of _ {
      [] -> (# Data.Maybe.Nothing @ a_a9I, GHC.Types.[] @ a_a9I #);
      : y_skD ys_skG ->
        case GHC.Classes.< @ a_a9I w_skC y_skD w1_skE of _ {
          GHC.Types.False ->
            Test.$wsmallerAndRest @ a_a9I w_skC w1_skE ys_skG;
          GHC.Types.True ->
            let {
              sat_skV :: Data.Maybe.Maybe a_a9I
              [LclId]
              sat_skV = Data.Maybe.Just @ a_a9I y_skD } in
            (# sat_skV, ys_skG #)
        }
    }
end Rec }

Test.smallerAndRest [InlPrag=INLINE[0]]
  :: forall a_a9I.
     GHC.Classes.Ord a_a9I =>
     a_a9I -> [a_a9I] -> (Data.Maybe.Maybe a_a9I, [a_a9I])
[GblId, Arity=3, Caf=NoCafRefs, Str=DmdType LLSm, Unf=OtherCon []]
Test.smallerAndRest =
  \ (@ a_a9I)
    (w_skL :: GHC.Classes.Ord a_a9I)
    (w1_skM :: a_a9I)
    (w2_skN :: [a_a9I]) ->
    case Test.$wsmallerAndRest @ a_a9I w_skL w1_skM w2_skN
    of _ { (# ww1_skR, ww2_skS #) ->
    (ww1_skR, ww2_skS)
    }

Here the worker-wrapper creates a variant, which returns unboxed pair.

I assume that there is no simple solution to this, because the worker/wrapper changes the INLINABLE on smallerAndRest to INLINE. The INLINABLE could be added to $wsmallerAndRest, but then #5928 causes the specialization to fail.

Maybe at least both smallerAndRest and $wsmallerAndRest could be marked INLINABLE? Then it is not sure that smallerAndRest gets INLINED and $wsmallerAndRest exposed, but it is not worse than current situation.

Trac metadata
Trac field Value
Version 7.4.1
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC fox@ucw.cz
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information