Skip to content

GitLab

  • Menu
Projects Groups Snippets
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
  • GHC GHC
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 4,830
    • Issues 4,830
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 448
    • Merge requests 448
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Releases
  • Analytics
    • Analytics
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
    • Value stream
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #20917

Closed
Open
Created Jan 08, 2022 by Andrzej Rybczak@arybczakContributor

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?

Edited Jan 08, 2022 by Andrzej Rybczak
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking