Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HasCallStack #440

Merged
merged 1 commit into from
Nov 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 15 additions & 14 deletions Data/ByteString.hs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ import GHC.IO.BufferedIO as Buffered
import GHC.IO.Encoding (getFileSystemEncoding)
import GHC.IO (unsafePerformIO, unsafeDupablePerformIO)
import GHC.Foreign (newCStringLen, peekCStringLen)
import GHC.Stack.Types (HasCallStack)
import Data.Char (ord)
import Foreign.Marshal.Utils (copyBytes)

Expand Down Expand Up @@ -398,15 +399,15 @@ snoc (BS x l) c = unsafeCreate (l+1) $ \p -> unsafeWithForeignPtr x $ \f -> do

-- | /O(1)/ Extract the first element of a ByteString, which must be non-empty.
-- An exception will be thrown in the case of an empty ByteString.
head :: ByteString -> Word8
head :: HasCallStack => ByteString -> Word8
head (BS x l)
| l <= 0 = errorEmptyList "head"
| otherwise = accursedUnutterablePerformIO $ unsafeWithForeignPtr x $ \p -> peek p
{-# INLINE head #-}

-- | /O(1)/ Extract the elements after the head of a ByteString, which must be non-empty.
-- An exception will be thrown in the case of an empty ByteString.
tail :: ByteString -> ByteString
tail :: HasCallStack => ByteString -> ByteString
tail (BS p l)
| l <= 0 = errorEmptyList "tail"
| otherwise = BS (plusForeignPtr p 1) (l-1)
Expand All @@ -424,7 +425,7 @@ uncons (BS x l)

-- | /O(1)/ Extract the last element of a ByteString, which must be finite and non-empty.
-- An exception will be thrown in the case of an empty ByteString.
last :: ByteString -> Word8
last :: HasCallStack => ByteString -> Word8
last ps@(BS x l)
| null ps = errorEmptyList "last"
| otherwise = accursedUnutterablePerformIO $
Expand All @@ -433,7 +434,7 @@ last ps@(BS x l)

-- | /O(1)/ Return all the elements of a 'ByteString' except the last one.
-- An exception will be thrown in the case of an empty ByteString.
init :: ByteString -> ByteString
init :: HasCallStack => ByteString -> ByteString
init ps@(BS p l)
| null ps = errorEmptyList "init"
| otherwise = BS p (l-1)
Expand Down Expand Up @@ -583,15 +584,15 @@ foldr' k v = \(BS fp len) ->
-- | 'foldl1' is a variant of 'foldl' that has no starting value
-- argument, and thus must be applied to non-empty 'ByteString's.
-- An exception will be thrown in the case of an empty ByteString.
foldl1 :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
foldl1 :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8
foldl1 f ps = case uncons ps of
Nothing -> errorEmptyList "foldl1"
Just (h, t) -> foldl f h t
{-# INLINE foldl1 #-}

-- | 'foldl1'' is like 'foldl1', but strict in the accumulator.
-- An exception will be thrown in the case of an empty ByteString.
foldl1' :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
foldl1' :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8
foldl1' f ps = case uncons ps of
Nothing -> errorEmptyList "foldl1'"
Just (h, t) -> foldl' f h t
Expand All @@ -600,15 +601,15 @@ foldl1' f ps = case uncons ps of
-- | 'foldr1' is a variant of 'foldr' that has no starting value argument,
-- and thus must be applied to non-empty 'ByteString's
-- An exception will be thrown in the case of an empty ByteString.
foldr1 :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
foldr1 :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8
foldr1 f ps = case unsnoc ps of
Nothing -> errorEmptyList "foldr1"
Just (b, c) -> foldr f c b
{-# INLINE foldr1 #-}

-- | 'foldr1'' is a variant of 'foldr1', but is strict in the
-- accumulator.
foldr1' :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
foldr1' :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8
foldr1' f ps = case unsnoc ps of
Nothing -> errorEmptyList "foldr1'"
Just (b, c) -> foldr' f c b
Expand Down Expand Up @@ -683,7 +684,7 @@ all f (BS x len) = accursedUnutterablePerformIO $ unsafeWithForeignPtr x g

-- | /O(n)/ 'maximum' returns the maximum value from a 'ByteString'
-- An exception will be thrown in the case of an empty ByteString.
maximum :: ByteString -> Word8
maximum :: HasCallStack => ByteString -> Word8
maximum xs@(BS x l)
| null xs = errorEmptyList "maximum"
| otherwise = accursedUnutterablePerformIO $ unsafeWithForeignPtr x $ \p ->
Expand All @@ -692,7 +693,7 @@ maximum xs@(BS x l)

-- | /O(n)/ 'minimum' returns the minimum value from a 'ByteString'
-- An exception will be thrown in the case of an empty ByteString.
minimum :: ByteString -> Word8
minimum :: HasCallStack => ByteString -> Word8
minimum xs@(BS x l)
| null xs = errorEmptyList "minimum"
| otherwise = accursedUnutterablePerformIO $ unsafeWithForeignPtr x $ \p ->
Expand Down Expand Up @@ -1238,7 +1239,7 @@ intercalateWithByte c f@(BS ffp l) g@(BS fgp m) = unsafeCreate len $ \ptr ->
-- Indexing ByteStrings

-- | /O(1)/ 'ByteString' index (subscript) operator, starting from 0.
index :: ByteString -> Int -> Word8
index :: HasCallStack => ByteString -> Int -> Word8
index ps n
| n < 0 = moduleError "index" ("negative index: " ++ show n)
| n >= length ps = moduleError "index" ("index too large: " ++ show n
Expand Down Expand Up @@ -2009,15 +2010,15 @@ appendFile = modifyFile AppendMode

-- Common up near identical calls to `error' to reduce the number
-- constant strings created when compiled:
errorEmptyList :: String -> a
errorEmptyList :: HasCallStack => String -> a
errorEmptyList fun = moduleError fun "empty ByteString"
{-# NOINLINE errorEmptyList #-}

moduleError :: String -> String -> a
moduleError :: HasCallStack => String -> String -> a
moduleError fun msg = error (moduleErrorMsg fun msg)
{-# NOINLINE moduleError #-}

moduleErrorIO :: String -> String -> IO a
moduleErrorIO :: HasCallStack => String -> String -> IO a
moduleErrorIO fun msg = throwIO . userError $ moduleErrorMsg fun msg
{-# NOINLINE moduleErrorIO #-}

Expand Down
29 changes: 15 additions & 14 deletions Data/ByteString/Lazy.hs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ import Data.ByteString.Lazy.Internal
import Control.Monad (mplus)
import Data.Word (Word8)
import Data.Int (Int64)
import GHC.Stack.Types (HasCallStack)
import System.IO (Handle,openBinaryFile,stdin,stdout,withBinaryFile,IOMode(..)
,hClose)
import System.IO.Error (mkIOError, illegalOperationErrorType)
Expand Down Expand Up @@ -341,7 +342,7 @@ snoc cs w = foldrChunks Chunk (singleton w) cs
{-# INLINE snoc #-}

-- | /O(1)/ Extract the first element of a ByteString, which must be non-empty.
head :: ByteString -> Word8
head :: HasCallStack => ByteString -> Word8
head Empty = errorEmptyList "head"
head (Chunk c _) = S.unsafeHead c
{-# INLINE head #-}
Expand All @@ -357,7 +358,7 @@ uncons (Chunk c cs)

-- | /O(1)/ Extract the elements after the head of a ByteString, which must be
-- non-empty.
tail :: ByteString -> ByteString
tail :: HasCallStack => ByteString -> ByteString
tail Empty = errorEmptyList "tail"
tail (Chunk c cs)
| S.length c == 1 = cs
Expand All @@ -366,15 +367,15 @@ tail (Chunk c cs)

-- | /O(n\/c)/ Extract the last element of a ByteString, which must be finite
-- and non-empty.
last :: ByteString -> Word8
last :: HasCallStack => ByteString -> Word8
last Empty = errorEmptyList "last"
last (Chunk c0 cs0) = go c0 cs0
where go c Empty = S.unsafeLast c
go _ (Chunk c cs) = go c cs
-- XXX Don't inline this. Something breaks with 6.8.2 (haven't investigated yet)

-- | /O(n\/c)/ Return all the elements of a 'ByteString' except the last one.
init :: ByteString -> ByteString
init :: HasCallStack => ByteString -> ByteString
init Empty = errorEmptyList "init"
init (Chunk c0 cs0) = go c0 cs0
where go c Empty | S.length c == 1 = Empty
Expand Down Expand Up @@ -474,18 +475,18 @@ foldr' f a = go

-- | 'foldl1' is a variant of 'foldl' that has no starting value
-- argument, and thus must be applied to non-empty 'ByteString's.
foldl1 :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
foldl1 :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8
foldl1 _ Empty = errorEmptyList "foldl1"
foldl1 f (Chunk c cs) = foldl f (S.unsafeHead c) (Chunk (S.unsafeTail c) cs)

-- | 'foldl1'' is like 'foldl1', but strict in the accumulator.
foldl1' :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
foldl1' :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8
foldl1' _ Empty = errorEmptyList "foldl1'"
foldl1' f (Chunk c cs) = foldl' f (S.unsafeHead c) (Chunk (S.unsafeTail c) cs)

-- | 'foldr1' is a variant of 'foldr' that has no starting value argument,
-- and thus must be applied to non-empty 'ByteString's
foldr1 :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
foldr1 :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8
foldr1 _ Empty = errorEmptyList "foldr1"
foldr1 f (Chunk c0 cs0) = go c0 cs0
where go c Empty = S.foldr1 f c
Expand All @@ -494,7 +495,7 @@ foldr1 f (Chunk c0 cs0) = go c0 cs0
-- | 'foldr1'' is like 'foldr1', but strict in the accumulator.
--
-- @since 0.11.2.0
foldr1' :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
foldr1' :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8
foldr1' _ Empty = errorEmptyList "foldr1'"
foldr1' f (Chunk c0 cs0) = go c0 cs0
where go c Empty = S.foldr1' f c
Expand Down Expand Up @@ -535,14 +536,14 @@ all f = foldrChunks (\c rest -> S.all f c && rest) True
{-# INLINE all #-}

-- | /O(n)/ 'maximum' returns the maximum value from a 'ByteString'
maximum :: ByteString -> Word8
maximum :: HasCallStack => ByteString -> Word8
maximum Empty = errorEmptyList "maximum"
maximum (Chunk c cs) = foldlChunks (\n c' -> n `max` S.maximum c')
(S.maximum c) cs
{-# INLINE maximum #-}

-- | /O(n)/ 'minimum' returns the minimum value from a 'ByteString'
minimum :: ByteString -> Word8
minimum :: HasCallStack => ByteString -> Word8
minimum Empty = errorEmptyList "minimum"
minimum (Chunk c cs) = foldlChunks (\n c' -> n `min` S.minimum c')
(S.minimum c) cs
Expand Down Expand Up @@ -715,7 +716,7 @@ replicate n w
-- | 'cycle' ties a finite ByteString into a circular one, or equivalently,
-- the infinite repetition of the original ByteString.
--
cycle :: ByteString -> ByteString
cycle :: HasCallStack => ByteString -> ByteString
cycle Empty = errorEmptyList "cycle"
cycle cs = cs' where cs' = foldrChunks Chunk cs' cs

Expand Down Expand Up @@ -1122,7 +1123,7 @@ intercalate s = concat . List.intersperse s
-- Indexing ByteStrings

-- | /O(c)/ 'ByteString' index (subscript) operator, starting from 0.
index :: ByteString -> Int64 -> Word8
index :: HasCallStack => ByteString -> Int64 -> Word8
index _ i | i < 0 = moduleError "index" ("negative index: " ++ show i)
index cs0 i = index' cs0 i
where index' Empty n = moduleError "index" ("index too large: " ++ show n)
Expand Down Expand Up @@ -1613,11 +1614,11 @@ interact transformer = putStr . transformer =<< getContents

-- Common up near identical calls to `error' to reduce the number
-- constant strings created when compiled:
errorEmptyList :: String -> a
errorEmptyList :: HasCallStack => String -> a
errorEmptyList fun = moduleError fun "empty ByteString"
{-# NOINLINE errorEmptyList #-}

moduleError :: String -> String -> a
moduleError :: HasCallStack => String -> String -> a
moduleError fun msg = error ("Data.ByteString.Lazy." ++ fun ++ ':':' ':msg)
{-# NOINLINE moduleError #-}

Expand Down
7 changes: 4 additions & 3 deletions Data/ByteString/Short/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ import GHC.Exts ( Int(I#), Int#, Ptr(Ptr), Addr#, Char(C#)
import GHC.IO
import GHC.ForeignPtr (ForeignPtr(ForeignPtr), ForeignPtrContents(PlainPtr))
import GHC.ST (ST(ST), runST)
import GHC.Stack.Types (HasCallStack)
import GHC.Word

import Prelude ( Eq(..), Ord(..), Ordering(..), Read(..), Show(..)
Expand Down Expand Up @@ -194,7 +195,7 @@ null :: ShortByteString -> Bool
null sbs = length sbs == 0

-- | /O(1)/ 'ShortByteString' index (subscript) operator, starting from 0.
index :: ShortByteString -> Int -> Word8
index :: HasCallStack => ShortByteString -> Int -> Word8
index sbs i
| i >= 0 && i < length sbs = unsafeIndex sbs i
| otherwise = indexError sbs i
Expand Down Expand Up @@ -222,7 +223,7 @@ indexMaybe sbs i
unsafeIndex :: ShortByteString -> Int -> Word8
unsafeIndex sbs = indexWord8Array (asBA sbs)

indexError :: ShortByteString -> Int -> a
indexError :: HasCallStack => ShortByteString -> Int -> a
indexError sbs i =
error $ "Data.ByteString.Short.index: error in array index; " ++ show i
++ " not in range [0.." ++ show (length sbs) ++ ")"
Expand Down Expand Up @@ -601,7 +602,7 @@ useAsCStringLen bs action =
-- ---------------------------------------------------------------------
-- Internal utilities

moduleErrorIO :: String -> String -> IO a
moduleErrorIO :: HasCallStack => String -> String -> IO a
moduleErrorIO fun msg = throwIO . userError $ moduleErrorMsg fun msg
{-# NOINLINE moduleErrorIO #-}

Expand Down