Commit 3664d9f1 authored by Bodigrim's avatar Bodigrim
Browse files

Add HasCallStack to partial functions

parent 45d2fd88
......@@ -211,7 +211,6 @@ import Prelude (Char, Bool(..), Int, Maybe(..), String,
import Control.DeepSeq (NFData(rnf))
#if defined(ASSERTS)
import Control.Exception (assert)
import GHC.Stack (HasCallStack)
#endif
import Data.Bits ((.&.))
import Data.Char (isSpace, isAscii, ord)
......@@ -249,6 +248,7 @@ import Data.Word (Word8)
import Foreign.C.Types
import GHC.Base (eqInt, neInt, gtInt, geInt, ltInt, leInt, ByteArray#)
import qualified GHC.Exts as Exts
import GHC.Stack (HasCallStack)
import qualified Language.Haskell.TH.Lib as TH
import qualified Language.Haskell.TH.Syntax as TH
import Text.Printf (PrintfArg, formatArg, formatString)
......@@ -449,8 +449,8 @@ snoc t c = unstream (S.snoc (stream t) (safe c))
{-# INLINE snoc #-}
-- | /O(1)/ Returns the first character of a 'Text', which must be
-- non-empty.
head :: Text -> Char
-- non-empty. This is a partial function, consider using 'uncons' instead.
head :: HasCallStack => Text -> Char
head t = S.head (stream t)
{-# INLINE head #-}
......@@ -464,16 +464,16 @@ uncons t@(Text arr off len)
{-# INLINE [1] uncons #-}
-- | /O(1)/ Returns the last character of a 'Text', which must be
-- non-empty.
last :: Text -> Char
-- non-empty. This is a partial function, consider using 'unsnoc' instead.
last :: HasCallStack => Text -> Char
last t@(Text _ _ len)
| len <= 0 = emptyError "last"
| otherwise = let Iter c _ = reverseIter t (len - 1) in c
{-# INLINE [1] last #-}
-- | /O(1)/ Returns all characters after the head of a 'Text', which
-- must be non-empty.
tail :: Text -> Text
-- must be non-empty. This is a partial function, consider using 'uncons' instead.
tail :: HasCallStack => Text -> Text
tail t@(Text arr off len)
| len <= 0 = emptyError "tail"
| otherwise = text arr (off+d) (len-d)
......@@ -481,8 +481,8 @@ tail t@(Text arr off len)
{-# INLINE [1] tail #-}
-- | /O(1)/ Returns all but the last character of a 'Text', which must
-- be non-empty.
init :: Text -> Text
-- be non-empty. This is a partial function, consider using 'unsnoc' instead.
init :: HasCallStack => Text -> Text
init t@(Text arr off len)
| len <= 0 = emptyError "init"
| otherwise = text arr off (len + reverseIter_ t (len - 1))
......@@ -758,7 +758,8 @@ foreign import ccall unsafe "_hs_text_reverse" c_reverse
--
-- In (unlikely) bad cases, this function's time complexity degrades
-- towards /O(n*m)/.
replace :: Text
replace :: HasCallStack
=> Text
-- ^ @needle@ to search for. If this string is empty, an
-- error will occur.
-> Text
......@@ -960,12 +961,12 @@ foldl' f z t = S.foldl' f z (stream t)
-- | /O(n)/ A variant of 'foldl' that has no starting value argument,
-- and thus must be applied to a non-empty 'Text'.
foldl1 :: (Char -> Char -> Char) -> Text -> Char
foldl1 :: HasCallStack => (Char -> Char -> Char) -> Text -> Char
foldl1 f t = S.foldl1 f (stream t)
{-# INLINE foldl1 #-}
-- | /O(n)/ A strict version of 'foldl1'.
foldl1' :: (Char -> Char -> Char) -> Text -> Char
foldl1' :: HasCallStack => (Char -> Char -> Char) -> Text -> Char
foldl1' f t = S.foldl1' f (stream t)
{-# INLINE foldl1' #-}
......@@ -978,7 +979,7 @@ foldr f z t = S.foldr f z (stream t)
-- | /O(n)/ A variant of 'foldr' that has no starting value argument,
-- and thus must be applied to a non-empty 'Text'.
foldr1 :: (Char -> Char -> Char) -> Text -> Char
foldr1 :: HasCallStack => (Char -> Char -> Char) -> Text -> Char
foldr1 f t = S.foldr1 f (stream t)
{-# INLINE foldr1 #-}
......@@ -1020,13 +1021,13 @@ all p t = S.all p (stream t)
-- | /O(n)/ 'maximum' returns the maximum value from a 'Text', which
-- must be non-empty.
maximum :: Text -> Char
maximum :: HasCallStack => Text -> Char
maximum t = S.maximum (stream t)
{-# INLINE maximum #-}
-- | /O(n)/ 'minimum' returns the minimum value from a 'Text', which
-- must be non-empty.
minimum :: Text -> Char
minimum :: HasCallStack => Text -> Char
minimum t = S.minimum (stream t)
{-# INLINE minimum #-}
......@@ -1468,7 +1469,8 @@ tails t | null t = [empty]
--
-- In (unlikely) bad cases, this function's time complexity degrades
-- towards /O(n*m)/.
splitOn :: Text
splitOn :: HasCallStack
=> Text
-- ^ String to split on. If this string is empty, an error
-- will occur.
-> Text
......@@ -1648,7 +1650,7 @@ filter p = go
--
-- In (unlikely) bad cases, this function's time complexity degrades
-- towards /O(n*m)/.
breakOn :: Text -> Text -> (Text, Text)
breakOn :: HasCallStack => Text -> Text -> (Text, Text)
breakOn pat src@(Text arr off len)
| null pat = emptyError "breakOn"
| otherwise = case indices pat src of
......@@ -1665,7 +1667,7 @@ breakOn pat src@(Text arr off len)
--
-- >>> breakOnEnd "::" "a::b::c"
-- ("a::b::","c")
breakOnEnd :: Text -> Text -> (Text, Text)
breakOnEnd :: HasCallStack => Text -> Text -> (Text, Text)
breakOnEnd pat src = (reverse b, reverse a)
where (a,b) = breakOn (reverse pat) (reverse src)
{-# INLINE breakOnEnd #-}
......@@ -1689,7 +1691,8 @@ breakOnEnd pat src = (reverse b, reverse a)
-- towards /O(n*m)/.
--
-- The @needle@ parameter may not be empty.
breakOnAll :: Text -- ^ @needle@ to search for
breakOnAll :: HasCallStack
=> Text -- ^ @needle@ to search for
-> Text -- ^ @haystack@ in which to search
-> [(Text, Text)]
breakOnAll pat src@(Text arr off slen)
......@@ -1720,7 +1723,7 @@ breakOnAll pat src@(Text arr off slen)
-- before and after that index, you would instead use @breakOnAll \"::\"@.
-- | /O(n)/ 'Text' index (subscript) operator, starting from 0.
index :: Text -> Int -> Char
index :: HasCallStack => Text -> Int -> Char
index t n = S.index (stream t) n
{-# INLINE index #-}
......@@ -1737,7 +1740,7 @@ findIndex p t = S.findIndex p (stream t)
--
-- In (unlikely) bad cases, this function's time complexity degrades
-- towards /O(n*m)/.
count :: Text -> Text -> Int
count :: HasCallStack => Text -> Text -> Int
count pat
| null pat = emptyError "count"
| isSingleton pat = countChar (unsafeHead pat)
......@@ -1984,10 +1987,10 @@ sumP fun = go 0
where ax = a + x
go a _ = a
emptyError :: String -> a
emptyError :: HasCallStack => String -> a
emptyError fun = P.error $ "Data.Text." ++ fun ++ ": empty input"
overflowError :: String -> a
overflowError :: HasCallStack => String -> a
overflowError fun = P.error $ "Data.Text." ++ fun ++ ": size overflow"
-- | /O(n)/ Make a distinct copy of the given string, sharing no
......
......@@ -62,10 +62,7 @@ import Data.Text.Internal.Fusion.Types
import Data.Text.Internal.Fusion.Size
import qualified Data.Text.Internal as I
import qualified Data.Text.Internal.Encoding.Utf8 as U8
#if defined(ASSERTS)
import GHC.Stack (HasCallStack)
#endif
default(Int)
......@@ -248,7 +245,7 @@ unfoldrN n = S.unfoldrNI n
-- __Properties__
--
-- @'index' ('stream' t) n = 'Data.Text.index' t n @
index :: Stream Char -> Int -> Char
index :: HasCallStack => Stream Char -> Int -> Char
index = S.indexI
{-# INLINE [0] index #-}
......
......@@ -135,6 +135,7 @@ import Data.Text.Internal.Fusion.CaseMapping (foldMapping, lowerMapping, titleMa
import Data.Text.Internal.Fusion.Size
import GHC.Exts (Char(..), Char#, chr#)
import GHC.Prim (Addr#, indexWord8OffAddr#)
import GHC.Stack (HasCallStack)
import GHC.Types (Int(..))
import Data.Text.Internal.Unsafe.Char (unsafeChr8)
import GHC.Word
......@@ -264,11 +265,12 @@ append (Stream next0 s01 len1) (Stream next1 s02 len2) =
{-# INLINE [0] append #-}
-- | /O(1)/ Returns the first character of a 'Stream' 'Char', which must be non-empty.
-- This is a partial function, consider using 'uncons'.
--
-- __Properties__
--
-- @ 'head' . 'Data.Text.Internal.Fusion.stream' = 'Data.Text.head' @
head :: Stream Char -> Char
head :: HasCallStack => Stream Char -> Char
head (Stream next s0 _len) = loop_head s0
where
loop_head !s = case next s of
......@@ -277,7 +279,7 @@ head (Stream next s0 _len) = loop_head s0
Done -> head_empty
{-# INLINE [0] head #-}
head_empty :: a
head_empty :: HasCallStack => a
head_empty = streamError "head" "Empty stream"
{-# NOINLINE head_empty #-}
......@@ -304,7 +306,7 @@ uncons (Stream next s0 len) = loop_uncons s0
-- __Properties__
--
-- @ 'last' . 'Data.Text.Internal.Fusion.stream' = 'Data.Text.last' @
last :: Stream Char -> Char
last :: HasCallStack => Stream Char -> Char
last (Stream next s0 _len) = loop0_last s0
where
loop0_last !s = case next s of
......@@ -318,12 +320,12 @@ last (Stream next s0 _len) = loop0_last s0
{-# INLINE[0] last #-}
-- | /O(1)/ Returns all characters after the head of a 'Stream' 'Char', which must
-- be non-empty.
-- be non-empty. This is a partial function, consider using 'uncons'.
--
-- __Properties__
--
-- @ 'Data.Text.Internal.unstream' . 'tail' . 'Data.Text.Internal.Fusion.stream' = 'Data.Text.tail' @
tail :: Stream Char -> Stream Char
tail :: HasCallStack => Stream Char -> Stream Char
tail (Stream next0 s0 len) = Stream next (C0 s0) (len - codePointsSize 1)
where
next (C0 s) = case next0 s of
......@@ -345,7 +347,7 @@ data Init s = Init0 !s
-- __Properties__
--
-- @ 'Data.Text.Internal.unstream' . 'init' . 'Data.Text.Internal.Fusion.stream' = 'Data.Text.init' @
init :: Stream Char -> Stream Char
init :: HasCallStack => Stream Char -> Stream Char
init (Stream next0 s0 len) = Stream next (Init0 s0) (len - codePointsSize 1)
where
next (Init0 s) = case next0 s of
......@@ -647,7 +649,7 @@ foldl' f z0 (Stream next s0 _len) = loop_foldl' z0 s0
-- __Properties__
--
-- @ 'foldl1' f . 'Data.Text.Internal.Fusion.stream' = 'Data.Text.foldl1' f @
foldl1 :: (Char -> Char -> Char) -> Stream Char -> Char
foldl1 :: HasCallStack => (Char -> Char -> Char) -> Stream Char -> Char
foldl1 f (Stream next s0 _len) = loop0_foldl1 s0
where
loop0_foldl1 !s = case next s of
......@@ -665,7 +667,7 @@ foldl1 f (Stream next s0 _len) = loop0_foldl1 s0
-- __Properties__
--
-- @ 'foldl1'' f . 'Data.Text.Internal.Fusion.stream' = 'Data.Text.foldl1'' f @
foldl1' :: (Char -> Char -> Char) -> Stream Char -> Char
foldl1' :: HasCallStack => (Char -> Char -> Char) -> Stream Char -> Char
foldl1' f (Stream next s0 _len) = loop0_foldl1' s0
where
loop0_foldl1' !s = case next s of
......@@ -700,7 +702,7 @@ foldr f z (Stream next s0 _len) = loop_foldr s0
-- __Properties__
--
-- @ 'foldr1' f . 'Data.Text.Internal.Fusion.stream' = 'Data.Text.foldr1' f @
foldr1 :: (Char -> Char -> Char) -> Stream Char -> Char
foldr1 :: HasCallStack => (Char -> Char -> Char) -> Stream Char -> Char
foldr1 f (Stream next s0 _len) = loop0_foldr1 s0
where
loop0_foldr1 !s = case next s of
......@@ -784,7 +786,7 @@ all p (Stream next0 s0 _len) = loop_all s0
-- __Properties__
--
-- @'maximum' . 'Data.Text.Fusion.stream' = 'Data.Text.maximum'@
maximum :: Stream Char -> Char
maximum :: HasCallStack => Stream Char -> Char
maximum (Stream next0 s0 _len) = loop0_maximum s0
where
loop0_maximum !s = case next0 s of
......@@ -805,7 +807,7 @@ maximum (Stream next0 s0 _len) = loop0_maximum s0
-- __Properties__
--
-- @'minimum' . 'Data.Text.Fusion.stream' = 'Data.Text.minimum'@
minimum :: Stream Char -> Char
minimum :: HasCallStack => Stream Char -> Char
minimum (Stream next0 s0 _len) = loop0_minimum s0
where
loop0_minimum !s = case next0 s of
......@@ -1069,7 +1071,7 @@ findBy p (Stream next s0 _len) = loop_find s0
-- __Properties__
--
-- @ 'indexI' ('Data.Text.Internal.Fusion.stream' t) n = 'Data.Text.index' t n@
indexI :: Integral a => Stream Char -> a -> Char
indexI :: (HasCallStack, Integral a) => Stream Char -> a -> Char
indexI (Stream next s0 _len) n0
| n0 < 0 = streamError "index" "Negative index"
| otherwise = loop_index n0 s0
......@@ -1174,13 +1176,13 @@ countCharI a (Stream next s0 _len) = loop 0 s0
| otherwise -> loop i s'
{-# INLINE [0] countCharI #-}
streamError :: String -> String -> a
streamError :: HasCallStack => String -> String -> a
streamError func msg = P.error $ "Data.Text.Internal.Fusion.Common." ++ func ++ ": " ++ msg
emptyError :: String -> a
emptyError :: HasCallStack => String -> a
emptyError func = internalError func "Empty input"
internalError :: String -> a
internalError :: HasCallStack => String -> a
internalError func = streamError func "Internal error"
int64ToSize :: Int64 -> Size
......
......@@ -37,9 +37,7 @@ import qualified Data.Text.Array as A
import Data.Text.Internal.Unsafe.Char (unsafeWrite)
import Data.Text.Unsafe (Iter(..), iter)
import Data.Int (Int64)
#if defined(ASSERTS)
import GHC.Stack (HasCallStack)
#endif
default(Int64)
......@@ -125,7 +123,7 @@ unfoldrN n = S.unfoldrNI n
{-# INLINE [0] unfoldrN #-}
-- | /O(n)/ stream index (subscript) operator, starting from 0.
index :: Stream Char -> Int64 -> Char
index :: HasCallStack => Stream Char -> Int64 -> Char
index = S.indexI
{-# INLINE [0] index #-}
......
......@@ -233,14 +233,11 @@ import Data.Text.Internal.Lazy.Search (indices)
import qualified GHC.CString as GHC
import qualified GHC.Exts as Exts
import GHC.Prim (Addr#)
import GHC.Stack (HasCallStack)
import qualified Language.Haskell.TH.Lib as TH
import qualified Language.Haskell.TH.Syntax as TH
import Text.Printf (PrintfArg, formatArg, formatString)
#if defined(ASSERTS)
import GHC.Stack (HasCallStack)
#endif
-- $fusion
--
-- Starting from @text-1.3@ fusion is no longer implicit,
......@@ -467,21 +464,21 @@ uncons (Chunk t ts) = Just (T.unsafeHead t, ts')
{-# INLINE uncons #-}
-- | /O(1)/ Returns the first character of a 'Text', which must be
-- non-empty.
head :: Text -> Char
-- non-empty. This is a partial function, consider using 'uncons' instead.
head :: HasCallStack => Text -> Char
head t = S.head (stream t)
{-# INLINE head #-}
-- | /O(1)/ Returns all characters after the head of a 'Text', which
-- must be non-empty.
tail :: Text -> Text
-- must be non-empty. This is a partial function, consider using 'uncons' instead.
tail :: HasCallStack => Text -> Text
tail (Chunk t ts) = chunk (T.tail t) ts
tail Empty = emptyError "tail"
{-# INLINE [1] tail #-}
-- | /O(n\/c)/ Returns all but the last character of a 'Text', which must
-- be non-empty.
init :: Text -> Text
-- be non-empty. This is a partial function, consider using 'unsnoc' instead.
init :: HasCallStack => Text -> Text
init (Chunk t0 ts0) = go t0 ts0
where go t (Chunk t' ts) = Chunk t (go t' ts)
go t Empty = chunk (T.init t) Empty
......@@ -511,8 +508,8 @@ isSingleton = S.isSingleton . stream
{-# INLINE isSingleton #-}
-- | /O(n\/c)/ Returns the last character of a 'Text', which must be
-- non-empty.
last :: Text -> Char
-- non-empty. This is a partial function, consider using 'unsnoc' instead.
last :: HasCallStack => Text -> Char
last Empty = emptyError "last"
last (Chunk t ts) = go t ts
where go _ (Chunk t' ts') = go t' ts'
......@@ -670,7 +667,8 @@ reverse = rev Empty
--
-- In (unlikely) bad cases, this function's time complexity degrades
-- towards /O(n*m)/.
replace :: Text
replace :: HasCallStack
=> Text
-- ^ @needle@ to search for. If this string is empty, an
-- error will occur.
-> Text
......@@ -773,12 +771,12 @@ foldl' f z t = S.foldl' f z (stream t)
-- | /O(n)/ A variant of 'foldl' that has no starting value argument,
-- and thus must be applied to a non-empty 'Text'.
foldl1 :: (Char -> Char -> Char) -> Text -> Char
foldl1 :: HasCallStack => (Char -> Char -> Char) -> Text -> Char
foldl1 f t = S.foldl1 f (stream t)
{-# INLINE foldl1 #-}
-- | /O(n)/ A strict version of 'foldl1'.
foldl1' :: (Char -> Char -> Char) -> Text -> Char
foldl1' :: HasCallStack => (Char -> Char -> Char) -> Text -> Char
foldl1' f t = S.foldl1' f (stream t)
{-# INLINE foldl1' #-}
......@@ -791,7 +789,7 @@ foldr f z t = S.foldr f z (stream t)
-- | /O(n)/ A variant of 'foldr' that has no starting value argument,
-- and thus must be applied to a non-empty 'Text'.
foldr1 :: (Char -> Char -> Char) -> Text -> Char
foldr1 :: HasCallStack => (Char -> Char -> Char) -> Text -> Char
foldr1 f t = S.foldr1 f (stream t)
{-# INLINE foldr1 #-}
......@@ -823,13 +821,13 @@ all p t = S.all p (stream t)
-- | /O(n)/ 'maximum' returns the maximum value from a 'Text', which
-- must be non-empty.
maximum :: Text -> Char
maximum :: HasCallStack => Text -> Char
maximum t = S.maximum (stream t)
{-# INLINE maximum #-}
-- | /O(n)/ 'minimum' returns the minimum value from a 'Text', which
-- must be non-empty.
minimum :: Text -> Char
minimum :: HasCallStack => Text -> Char
minimum t = S.minimum (stream t)
{-# INLINE minimum #-}
......@@ -935,7 +933,7 @@ replicateChunk !n !t@(T.Text _ _ len)
-- equivalently, the infinite repetition of the original 'Text'.
--
-- @since 1.2.0.5
cycle :: Text -> Text
cycle :: HasCallStack => Text -> Text
cycle Empty = emptyError "cycle"
cycle t = let t' = foldrChunks Chunk t' t
in t'
......@@ -1214,7 +1212,7 @@ splitAtWord x (Chunk c@(T.Text arr off len) cs)
--
-- In (unlikely) bad cases, this function's time complexity degrades
-- towards /O(n*m)/.
breakOn :: Text -> Text -> (Text, Text)
breakOn :: HasCallStack => Text -> Text -> (Text, Text)
breakOn pat src
| null pat = emptyError "breakOn"
| otherwise = case indices pat src of
......@@ -1229,7 +1227,7 @@ breakOn pat src
-- remainder of @haystack@, following the match.
--
-- > breakOnEnd "::" "a::b::c" ==> ("a::b::", "c")
breakOnEnd :: Text -> Text -> (Text, Text)
breakOnEnd :: HasCallStack => Text -> Text -> (Text, Text)
breakOnEnd pat src = let (a,b) = breakOn (reverse pat) (reverse src)
in (reverse b, reverse a)
{-# INLINE breakOnEnd #-}
......@@ -1255,7 +1253,8 @@ breakOnEnd pat src = let (a,b) = breakOn (reverse pat) (reverse src)
-- towards /O(n*m)/.
--
-- The @needle@ parameter may not be empty.
breakOnAll :: Text -- ^ @needle@ to search for
breakOnAll :: HasCallStack
=> Text -- ^ @needle@ to search for
-> Text -- ^ @haystack@ in which to search
-> [(Text, Text)]
breakOnAll pat src
......@@ -1360,7 +1359,8 @@ tails ts@(Chunk t ts')
--
-- In (unlikely) bad cases, this function's time complexity degrades
-- towards /O(n*m)/.
splitOn :: Text
splitOn :: HasCallStack
=> Text
-- ^ String to split on. If this string is empty, an error
-- will occur.
-> Text
......@@ -1426,7 +1426,7 @@ lines t = NE.toList $ go t
-- x is non-empty, so T.lines x is non-empty as well
| hasNlEnd x = NE.fromList $ P.map fromStrict (T.lines x) ++ lines xs
| otherwise = case unsnocList (T.lines x) of
Nothing -> error "lines: unexpected empty chunk"
Nothing -> impossibleError "lines"
Just (ls, l) -> P.foldr (NE.cons . fromStrict) (prependToHead l (go xs)) ls
prependToHead :: T.Text -> NonEmpty Text -> NonEmpty Text
......@@ -1608,7 +1608,7 @@ partition p t = (filter p t, filter (not . p) t)
{-# INLINE partition #-}
-- | /O(n)/ 'Text' index (subscript) operator, starting from 0.
index :: Text -> Int64 -> Char
index :: HasCallStack => Text -> Int64 -> Char
index t n = S.index (stream t) n
{-# INLINE index #-}
......@@ -1618,7 +1618,7 @@ index t n = S.index (stream t) n
--
-- In (unlikely) bad cases, this function's time complexity degrades
-- towards /O(n*m)/.
count :: Text -> Text -> Int64
count :: HasCallStack => Text -> Text -> Int64
count pat
| null pat = emptyError "count"
| otherwise = go 0 . indices pat
......@@ -1655,10 +1655,10 @@ zipWith f t1 t2 = unstream (S.zipWith g (stream t1) (stream t2))
revChunks :: [T.Text] -> Text
revChunks = L.foldl' (flip chunk) Empty
emptyError :: String -> a
emptyError :: HasCallStack => String -> a
emptyError fun = P.error ("Data.Text.Lazy." ++ fun ++ ": empty input")
impossibleError :: String -> a
impossibleError :: HasCallStack => String -> a
impossibleError fun = P.error ("Data.Text.Lazy." ++ fun ++ ": impossible case")
intToInt64 :: Exts.Int -> Int64
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment