packages feed

effectful-core 2.7.1.0 → 2.7.1.1

raw patch · 3 files changed

+28/−5 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,3 +1,7 @@+# effectful-core-2.7.1.1 (2026-08-24)+* Fix a performance regression introduced in 2.7.0.0 that increased the+  per-operation overhead of dynamically dispatched effects.+ # effectful-core-2.7.1.0 (2026-08-24) * Export `seqForkUnliftIO` and add `unsafeSeqForkUnliftIO` in   `Effectful.Dispatch.Static` for the `SeqForkUnlift` strategy.
effectful-core.cabal view
@@ -1,7 +1,7 @@ cabal-version:      3.8 build-type:         Simple name:               effectful-core-version:            2.7.1.0+version:            2.7.1.1 license:            BSD-3-Clause license-file:       LICENSE category:           Control@@ -51,6 +51,10 @@ library     import:         language +    -- -O2 enables -ffast-pap-calls, without which the handler invocation in+    -- send and passthrough (an unknown call with 5 pointers and the State#+    -- token that matches no precompiled RTS apply pattern) allocates an+    -- intermediate PAP on every operation of a dynamically dispatched effect.     ghc-options:    -O2      build-depends:    base                >= 4.18      && < 5
src/Effectful/Dispatch/Dynamic.hs view
@@ -1210,6 +1210,21 @@ ---------------------------------------- -- Helpers +-- Note [NOINLINE on the Impl functions]+--+-- The public wrappers must inline at call sites, because that's the only place+-- the callstack-thawing adapter around the handler (see 'HandlerImpl') can+-- fuse with a concrete handler. If it doesn't, the adapter is stored in the+-- 'Handler' as a closure over an unknown function and every 'send' pays for an+-- extra unknown call, CallStack allocation and generic apply of a PAP.+--+-- The wrappers have no INLINE pragmas, so they expose their optimized RHS as+-- the unfolding and GHC inlines them based on its size. NOINLINE below keeps+-- the bodies of the Impl functions out of these unfoldings, guaranteeing that+-- they stay small. Historically reinterpretImpl had an INLINE pragma instead+-- and a minor addition to it grew the wrappers of reinterpret past the+-- inlining threshold, silently causing exactly this regression.+ interpretImpl   :: (HasCallStack, DispatchOf e ~ Dynamic)   => Eff (e : es) a@@ -1217,7 +1232,7 @@   -> Eff      es  a interpretImpl action handlerImpl = unsafeEff $ \es -> do   (`unEff` es) $ runHandler (Handler es handlerImpl) action-{-# INLINE interpretImpl #-}+{-# NOINLINE interpretImpl #-}  reinterpretImpl   :: (HasCallStack, DispatchOf e ~ Dynamic)@@ -1229,7 +1244,7 @@   (`unEff` es) . runSetup . unsafeEff $ \handlerEs -> do     requireInScopeSetup es handlerEs     (`unEff` es) $ runHandler (Handler handlerEs handlerImpl) action-{-# INLINE reinterpretImpl #-}+{-# NOINLINE reinterpretImpl #-}  interposeImpl   :: forall e es a. (HasCallStack, DispatchOf e ~ Dynamic, e :> es)@@ -1253,7 +1268,7 @@         putEnv es $ Handler newEs handlerImpl         unEff action es     )-{-# INLINE interposeImpl #-}+{-# NOINLINE interposeImpl #-}  imposeImpl   :: forall e es handlerEs a b. (HasCallStack, DispatchOf e ~ Dynamic, e :> es)@@ -1281,7 +1296,7 @@           putEnv es $ Handler handlerEs handlerImpl           unEff action es     )-{-# INLINE imposeImpl #-}+{-# NOINLINE imposeImpl #-}  copyRefs   :: forall es srcEs destEs