on master help sign in
Less unsafe functions, document unsafeness
commit8f37f3f79e58b79513b84aad7a9d9032361a8c00 authorAndrzej Rybczak <andrzej@rybczak.net> dateSat 31 Jul 2021, 17:03 (5 years ago) parenta9516ac
4 files changed+50−41
effectful-core/src/Effectful/Handler.hs+14−14 effectful-core/src/Effectful/Internal/Env.hs+5−5 effectful-core/src/Effectful/Internal/Monad.hs+25−16 effectful-core/src/Effectful/Internal/Unlift.hs+6−6
effectful-core/src/Effectful/Handler.hs+14−14
@@ -120,7 +120,7 @@ localSeqUnlift
120120 -- ^ Continuation with the unlifting function in scope.
121121 -> Eff es a
122122localSeqUnlift (LocalEnv les) k = unsafeEff $ \es -> do
123− unsafeSeqUnliftEff les $ \unlift -> do
123+ seqUnliftEff les $ \unlift -> do
124124 (`unEff` es) $ k $ unsafeEff_ . unlift
125125
126126-- | Create a local unlifting function with the 'SeqUnlift' strategy. For the
@@ -132,7 +132,7 @@ localSeqUnliftIO
132132 -> ((forall r. Eff localEs r -> IO r) -> IO a)
133133 -- ^ Continuation with the unlifting function in scope.
134134 -> Eff es a
135−localSeqUnliftIO (LocalEnv les) k = liftIO $ unsafeSeqUnliftEff les k
135+localSeqUnliftIO (LocalEnv les) k = liftIO $ seqUnliftEff les k
136136
137137-- | Create a local unlifting function with the given strategy.
138138localUnlift
@@ -145,10 +145,10 @@ localUnlift
145145 -> Eff es a
146146localUnlift (LocalEnv les) strategy k = case strategy of
147147 SeqUnlift -> unsafeEff $ \es -> do
148− unsafeSeqUnliftEff les $ \unlift -> do
148+ seqUnliftEff les $ \unlift -> do
149149 (`unEff` es) $ k $ unsafeEff_ . unlift
150150 ConcUnlift p l -> unsafeEff $ \es -> do
151− unsafeConcUnliftEff les p l $ \unlift -> do
151+ concUnliftEff les p l $ \unlift -> do
152152 (`unEff` es) $ k $ unsafeEff_ . unlift
153153
154154-- | Create a local unlifting function with the given strategy.
@@ -161,8 +161,8 @@ localUnliftIO
161161 -- ^ Continuation with the unlifting function in scope.
162162 -> Eff es a
163163localUnliftIO (LocalEnv les) strategy k = case strategy of
164− SeqUnlift -> liftIO $ unsafeSeqUnliftEff les k
165− ConcUnlift p l -> liftIO $ unsafeConcUnliftEff les p l k
164+ SeqUnlift -> liftIO $ seqUnliftEff les k
165+ ConcUnlift p l -> liftIO $ concUnliftEff les p l k
166166
167167-- | Utility for lifting 'Eff' operations of type
168168--
@@ -181,7 +181,7 @@ withLiftMap
181181 -> Eff es r
182182withLiftMap k = unsafeEff $ \es -> do
183183 (`unEff` es) $ k $ \mapEff m -> unsafeEff $ \localEs -> do
184− unsafeSeqUnliftEff localEs $ \unlift -> do
184+ seqUnliftEff localEs $ \unlift -> do
185185 (`unEff` es) . mapEff . liftIO $ unlift m
186186
187187-- | Utility for lifting 'IO' operations of type
@@ -215,7 +215,7 @@ withLiftMapIO
215215 -- ^ Continuation with the lifting function in scope.
216216 -> Eff es r
217217withLiftMapIO k = k $ \mapIO m -> unsafeEff $ \es -> do
218− unsafeSeqUnliftEff es $ \unlift -> mapIO $ unlift m
218+ seqUnliftEff es $ \unlift -> mapIO $ unlift m
219219
220220----------------------------------------
221221-- Bidirectional lifts
@@ -237,12 +237,12 @@ localLiftUnlift
237237 -> Eff es a
238238localLiftUnlift (LocalEnv les) strategy k = case strategy of
239239 SeqUnlift -> unsafeEff $ \es -> do
240− unsafeSeqUnliftEff es $ \unliftEs -> do
241− unsafeSeqUnliftEff les $ \unliftLocalEs -> do
240+ seqUnliftEff es $ \unliftEs -> do
241+ seqUnliftEff les $ \unliftLocalEs -> do
242242 (`unEff` es) $ k (unsafeEff_ . unliftEs) (liftIO . unliftLocalEs)
243243 ConcUnlift p l -> unsafeEff $ \es -> do
244− unsafeConcUnliftEff es p l $ \unliftEs -> do
245− unsafeConcUnliftEff les p l $ \unliftLocalEs -> do
244+ concUnliftEff es p l $ \unliftEs -> do
245+ concUnliftEff les p l $ \unliftLocalEs -> do
246246 (`unEff` es) $ k (unsafeEff_ . unliftEs) (liftIO . unliftLocalEs)
247247
248248-- | Create a local unlifting function with the given strategy along with an
@@ -262,8 +262,8 @@ localLiftUnliftIO
262262 -- ^ Continuation with the lifting and unlifting function in scope.
263263 -> Eff es a
264264localLiftUnliftIO (LocalEnv les) strategy k = case strategy of
265− SeqUnlift -> liftIO $ unsafeSeqUnliftEff les $ k unsafeEff_
266− ConcUnlift p l -> liftIO $ unsafeConcUnliftEff les p l $ k unsafeEff_
265+ SeqUnlift -> liftIO $ seqUnliftEff les $ k unsafeEff_
266+ ConcUnlift p l -> liftIO $ concUnliftEff les p l $ k unsafeEff_
267267
268268-- $setup
269269-- >>> import Control.Concurrent
effectful-core/src/Effectful/Internal/Env.hs+5−5
@@ -342,9 +342,9 @@ checkSizeEnv k (Env (Forks _ baseIx lref _) _ _) = do
342342
343343-- | Extend the environment with a new data type (in place).
344344--
345−-- /Note:/ this function is __unsafe__ because it renders the input 'Env'
346−-- unusable until the corresponding 'unsafeTailEnv' call, but it's not checked
347−-- anywhere.
345+-- This function is __highly unsafe__ because it renders the input 'Env'
346+-- unusable until the corresponding 'unsafeTailEnv' call is made, but it's not
347+-- checked anywhere.
348348unsafeConsEnv :: handler e -> Relinker handler e -> Env es -> IO (Env (e : es))
349349unsafeConsEnv e f (Env fork gref gen) = case fork of
350350 NoFork -> do
@@ -381,11 +381,11 @@ unsafeConsEnv e f (Env fork gref gen) = case fork of
381381-- | Shrink the environment by one data type (in place). Makes sure the size of
382382-- the environment is as expected.
383383--
384−-- /Note:/ this function is __unsafe__ because it renders the input 'Env'
384+-- This function is __highly unsafe__ because it renders the input 'Env'
385385-- unusable, but it's not checked anywhere.
386386unsafeTailEnv :: Int -> Env (e : es) -> IO ()
387387unsafeTailEnv len (Env fork gref _) = case fork of
388− NoFork -> shrinkEnvRef len gref
388+ NoFork -> shrinkEnvRef len gref
389389 Forks _ baseIx lref _ -> shrinkEnvRef (len - baseIx) lref
390390 where
391391 shrinkEnvRef :: Int -> IORef EnvRef -> IO ()
effectful-core/src/Effectful/Internal/Monad.hs+25−16
@@ -37,8 +37,8 @@ module Effectful.Internal.Monad
3737
3838 --- *** Low-level helpers
3939 , unsafeWithLiftMapIO
40− , unsafeSeqUnliftEff
41− , unsafeConcUnliftEff
40+ , seqUnliftEff
41+ , concUnliftEff
4242
4343 -- * Primitive effects
4444
@@ -126,10 +126,16 @@ unEff :: Eff es a -> Env es -> IO a
126126unEff (Eff m) = m
127127
128128-- | Access the underlying 'IO' monad along with the environment.
129+--
130+-- This function is __unsafe__ because it can be used to introduce arbitrary
131+-- 'IO' actions into pure 'Eff' operations.
129132unsafeEff :: (Env es -> IO a) -> Eff es a
130133unsafeEff m = Eff (oneShot m)
131134
132135-- | Access the underlying 'IO' monad.
136+--
137+-- This function is __unsafe__ because it can be used to introduce arbitrary
138+-- 'IO' actions into pure 'Eff' operations.
133139unsafeEff_ :: IO a -> Eff es a
134140unsafeEff_ m = unsafeEff $ \_ -> m
135141
@@ -141,6 +147,9 @@ unsafeEff_ m = unsafeEff $ \_ -> m
141147--
142148-- @forall localEs. 'Eff' localEs a -> 'Eff' localEs b@
143149--
150+-- This function is __unsafe__ because it can be used to introduce arbitrary
151+-- 'IO' actions into pure 'Eff' operations.
152+--
144153-- /Note:/ the 'IO' operation must not run its argument in a separate thread,
145154-- attempting to do so will result in a runtime error.
146155unsafeWithLiftMapIO
@@ -148,15 +157,15 @@ unsafeWithLiftMapIO
148157 => ((forall a b localEs. (IO a -> IO b) -> Eff localEs a -> Eff localEs b) -> Eff es r)
149158 -> Eff es r
150159unsafeWithLiftMapIO k = k $ \mapIO m -> unsafeEff $ \es -> do
151− unsafeSeqUnliftEff es $ \unlift -> mapIO $ unlift m
160+ seqUnliftEff es $ \unlift -> mapIO $ unlift m
152161
153162-- | Lower 'Eff' operations into 'IO' ('SeqUnlift').
154−unsafeSeqUnliftEff
163+seqUnliftEff
155164 :: HasCallStack
156165 => Env es
157166 -> ((forall r. Eff es r -> IO r) -> IO a)
158167 -> IO a
159−unsafeSeqUnliftEff es k = do
168+seqUnliftEff es k = do
160169 tid0 <- myThreadId
161170 k $ \m -> do
162171 tid <- myThreadId
@@ -167,21 +176,21 @@ unsafeSeqUnliftEff es k = do
167176 ++ "in multiple threads, have a look at UnliftStrategy (ConcUnlift)."
168177
169178-- | Lower 'Eff' operations into 'IO' ('ConcUnlift').
170−unsafeConcUnliftEff
179+concUnliftEff
171180 :: HasCallStack
172181 => Env es
173182 -> Persistence
174183 -> Limit
175184 -> ((forall r. Eff es r -> IO r) -> IO a)
176185 -> IO a
177−unsafeConcUnliftEff es Ephemeral (Limited uses) k =
178− unsafeEphemeralConcUnliftIO uses k es unEff
179−unsafeConcUnliftEff es Ephemeral Unlimited k =
180− unsafeEphemeralConcUnliftIO maxBound k es unEff
181−unsafeConcUnliftEff es Persistent (Limited threads) k =
182− unsafePersistentConcUnliftIO False threads k es unEff
183−unsafeConcUnliftEff es Persistent Unlimited k =
184− unsafePersistentConcUnliftIO True maxBound k es unEff
186+concUnliftEff es Ephemeral (Limited uses) k =
187+ ephemeralConcUnliftIO uses k es unEff
188+concUnliftEff es Ephemeral Unlimited k =
189+ ephemeralConcUnliftIO maxBound k es unEff
190+concUnliftEff es Persistent (Limited threads) k =
191+ persistentConcUnliftIO False threads k es unEff
192+concUnliftEff es Persistent Unlimited k =
193+ persistentConcUnliftIO True maxBound k es unEff
185194
186195----------------------------------------
187196-- Base
@@ -400,9 +409,9 @@ withEffToIO
400409 -- ^ Continuation with the unlifting function in scope.
401410 -> Eff es a
402411withEffToIO f = unliftStrategy >>= \case
403− SeqUnlift -> unsafeEff $ \es -> unsafeSeqUnliftEff es f
412+ SeqUnlift -> unsafeEff $ \es -> seqUnliftEff es f
404413 ConcUnlift p b -> withUnliftStrategy SeqUnlift $ do
405− unsafeEff $ \es -> unsafeConcUnliftEff es p b f
414+ unsafeEff $ \es -> concUnliftEff es p b f
406415
407416----------------------------------------
408417-- Helpers
effectful-core/src/Effectful/Internal/Unlift.hs+6−6
@@ -6,8 +6,8 @@
66-- This module is intended for internal use only, and may change without warning
77-- in subsequent releases.
88module Effectful.Internal.Unlift
9− ( unsafeEphemeralConcUnliftIO
10− , unsafePersistentConcUnliftIO
9+ ( ephemeralConcUnliftIO
10+ , persistentConcUnliftIO
1111 ) where
1212
1313import Control.Concurrent
@@ -25,14 +25,14 @@ import Effectful.Internal.Utils
2525
2626-- | Concurrent unlift that doesn't preserve the environment between calls to
2727-- the unlifting function in threads other than its creator.
28−unsafeEphemeralConcUnliftIO
28+ephemeralConcUnliftIO
2929 :: HasCallStack
3030 => Int
3131 -> ((forall r. m r -> IO r) -> IO a)
3232 -> Env es
3333 -> (forall r. m r -> Env es -> IO r)
3434 -> IO a
35−unsafeEphemeralConcUnliftIO uses k es0 unEff = do
35+ephemeralConcUnliftIO uses k es0 unEff = do
3636 unless (uses > 0) $ do
3737 error $ "Invalid number of uses: " ++ show uses
3838 tid0 <- myThreadId
@@ -58,7 +58,7 @@ unsafeEphemeralConcUnliftIO uses k es0 unEff = do
5858
5959-- | Concurrent unlift that preserves the environment between calls to the
6060-- unlifting function within a particular thread.
61−unsafePersistentConcUnliftIO
61+persistentConcUnliftIO
6262 :: HasCallStack
6363 => Bool
6464 -> Int
@@ -66,7 +66,7 @@ unsafePersistentConcUnliftIO
6666 -> Env es
6767 -> (forall r. m r -> Env es -> IO r)
6868 -> IO a
69−unsafePersistentConcUnliftIO cleanUp threads k es0 unEff = do
69+persistentConcUnliftIO cleanUp threads k es0 unEff = do
7070 unless (threads > 0) $ do
7171 error $ "Invalid number of threads: " ++ show threads
7272 tid0 <- myThreadId