Worker/wrapper transformation doesn't unpack all applicable dictionaries
Disclaimer: apologies for no standalone reproducer, but I couldn't quite get the same clear result.
The test project for easy reproduction is here: https://github.com/arybczak/ww-test, the full Core can be obtained by running
git clone git@github.com:arybczak/ww-test.git
cd ww-test
cabal build
The relevant code:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Test where
import GHC.Exts
import Effectful
data E1 :: Effect where
E1 :: Int# -> E1 m ()
data E2 :: Effect where
E2 :: Int# -> E2 m ()
data E3 :: Effect where
E3 :: Int# -> E3 m ()
type instance DispatchOf E1 = 'Dynamic
type instance DispatchOf E2 = 'Dynamic
type instance DispatchOf E3 = 'Dynamic
fun :: (E1 :> es, E2 :> es, E3 :> es) => Int -> Int -> Int -> Eff es ()
fun (I# i1) (I# i2) (I# i3) = do
send $ E1 i1
send $ E2 i2
send $ E3 i3
The relevant excerpt of Core produced is as follows:
-- RHS size: {terms: 48, types: 62, coercions: 21, joins: 0/0}
$wfun
:: forall {es :: [Effect]}.
Int#
-> (E2 :> es, E3 :> es) =>
Int#
-> Int#
-> Int#
-> Forks
-> MutVar# RealWorld EnvRef
-> MutVar# RealWorld ForkId
-> State# RealWorld
-> (# State# RealWorld, () #)
$wfun
= \ (@(es_s5mH :: [Effect]))
(ww_s5mS :: Int#)
(w_s5mJ :: E2 :> es_s5mH)
(w1_s5mK :: E3 :> es_s5mH)
(ww1_s5mW :: Int#)
(ww2_s5n0 :: Int#)
(ww3_s5n4 :: Int#)
(ww4_s5n8
:: Forks
Unf=OtherCon [])
(ww5_s5n9 :: MutVar# RealWorld EnvRef)
(ww6_s5na :: MutVar# RealWorld ForkId)
(w2_s5mP :: State# RealWorld) ->
case $wsend
(fun16 `cast` <Co:4>)
@~<Co:1>
ww_s5mS
($WE1 ww1_s5mW)
ww4_s5n8
ww5_s5n9
ww6_s5na
w2_s5mP
of
{ (# ipv_a5e8, ipv1_a5e9 #) ->
case w_s5mJ `cast` <Co:3> of { I# ww8_Xb ->
case $wsend
(fun13 `cast` <Co:4>)
@~<Co:1>
ww8_Xb
($WE2 ww2_s5n0)
ww4_s5n8
ww5_s5n9
ww6_s5na
ipv_a5e8
of
{ (# ipv2_Xg, ipv3_Xh #) ->
case w1_s5mK `cast` <Co:3> of { I# ww10_Xj ->
$wsend
(fun2 `cast` <Co:4>)
@~<Co:1>
ww10_Xj
($WE3 ww3_s5n4)
ww4_s5n8
ww5_s5n9
ww6_s5na
ipv2_Xg
}
}
}
}
-- RHS size: {terms: 35, types: 36, coercions: 3, joins: 0/0}
fun1
:: forall {es :: [Effect]}.
(E1 :> es, E2 :> es, E3 :> es) =>
Int
-> Int
-> Int
-> Env es
-> State# RealWorld
-> (# State# RealWorld, () #)
fun1
= \ (@(es_s5mH :: [Effect]))
(w_s5mI :: E1 :> es_s5mH)
(w1_s5mJ :: E2 :> es_s5mH)
(w2_s5mK :: E3 :> es_s5mH)
(w3_s5mL :: Int)
(w4_s5mM :: Int)
(w5_s5mN :: Int)
(w6_s5mO :: Env es_s5mH)
(w7_s5mP :: State# RealWorld) ->
case w_s5mI `cast` <Co:3> of { I# ww1_s5mS ->
case w3_s5mL of { I# ww3_s5mW ->
case w4_s5mM of { I# ww5_s5n0 ->
case w5_s5mN of { I# ww7_s5n4 ->
case w6_s5mO of { Env ww9_s5n8 ww10_s5n9 ww11_s5na ->
$wfun
ww1_s5mS
w1_s5mJ
w2_s5mK
ww3_s5mW
ww5_s5n0
ww7_s5n4
ww9_s5n8
ww10_s5n9
ww11_s5na
w7_s5mP
}
}
}
}
}
-- RHS size: {terms: 1, types: 0, coercions: 39, joins: 0/0}
fun
:: forall (es :: [Effect]).
(E1 :> es, E2 :> es, E3 :> es) =>
Int -> Int -> Int -> Eff es ()
fun = fun1 `cast` <Co:39>
Note that fun
unpacks all arguments that are reasonable to unpack and calls $wfun
, but for some reason it only unpacks the dictionary (which is an Int
) of E1 :> es
, the first on the list of constraints. The other two are left boxed even though they are used in exactly the same way as E1 :> es
. This doesn't seem to happen with regular arguments, as all IntS
passed to fun
are unpacked.
This happens with 8.8.4, 8.10.7, 9.0.2 and 9.2.1, I didn't check HEAD.
Is there any particular reason why not all dictionaries are unpacked here?