on master help sign in
Make use of assert conditional

This turns out to make about a 10% difference to performance, even though the GHC docs claim it shouldn't :-( --HG-- extra : convert_revision : 446f05ea889a715272cd709cbd2d3b11260df7ba

commita99b318f9a12f0d6bf73b0c4ce7bea1d9b3e4a08 authorBryan O'Sullivan <bos@serpentine.com> dateSun 15 Aug 2010, 01:47 (16 years ago) parenteac9147
14 files changed+150−66
Data/Text.hs+7−1 Data/Text/Array.hs+15−8 Data/Text/Encoding/Fusion.hs+8−2 Data/Text/Encoding/Fusion/Common.hs+1−1 Data/Text/Encoding/Utf8.hs+19−5 Data/Text/Foreign.hs+9−2 Data/Text/Fusion.hs+1−2 Data/Text/Fusion/Size.hs+13−2 Data/Text/Internal.hs+12−8 Data/Text/Lazy/Builder.hs+13−5 Data/Text/Lazy/Encoding/Fusion.hs+8−2 Data/Text/Unsafe.hs+25−20 Data/Text/UnsafeChar.hs+18−8 text.cabal+1
Data/Text.hs+7−1
@@ -174,7 +174,9 @@ import Prelude (Char, Bool(..), Functor(..), Int, Maybe(..), String,
174174#if defined(HAVE_DEEPSEQ)
175175import Control.DeepSeq (NFData)
176176#endif
177+#if defined(ASSERTS)
177178import Control.Exception (assert)
179+#endif
178180import Data.Char (isSpace)
179181import Data.Data (Data(gfoldl, toConstr, gunfold, dataTypeOf))
180182#if __GLASGOW_HASKELL__ >= 612
@@ -395,7 +397,11 @@ init (Text arr off len) | len <= 0 = emptyError "init"
395397-- | /O(1)/ Tests whether a 'Text' is empty or not. Subject to
396398-- fusion.
397399null :: Text -> Bool
398−null (Text _arr _off len) = assert (len >= 0) $ len <= 0
400+null (Text _arr _off len) =
401+#if defined(ASSERTS)
402+ assert (len >= 0) $
403+#endif
404+ len <= 0
399405{-# INLINE [1] null #-}
400406
401407{-# RULES
Data/Text/Array.hs+15−8
@@ -42,19 +42,20 @@ module Data.Text.Array
4242 , unsafeWrite
4343 ) where
4444
45−#if 0
46−#define BOUNDS_CHECKING
45+#if defined(ASSERTS)
4746-- This fugly hack is brought by GHC's apparent reluctance to deal
4847-- with MagicHash and UnboxedTuples when inferring types. Eek!
49−#define CHECK_BOUNDS(_func_,_len_,_k_) \
48+# define CHECK_BOUNDS(_func_,_len_,_k_) \
5049if (_k_) < 0 || (_k_) >= (_len_) then error ("Data.Text.Array." ++ (_func_) ++ ": bounds error, offset " ++ show (_k_) ++ ", length " ++ show (_len_)) else
5150#else
52−#define CHECK_BOUNDS(_func_,_len_,_k_)
51+# define CHECK_BOUNDS(_func_,_len_,_k_)
5352#endif
5453
5554#include "MachDeps.h"
5655
56+#if defined(ASSERTS)
5757import Control.Exception (assert)
58+#endif
5859import Data.Text.UnsafeShift (shiftL)
5960import GHC.Base (ByteArray#, MutableByteArray#, Int(..),
6061 indexWord16Array#, newByteArray#,
@@ -92,10 +93,14 @@ unsafeFreeze :: MArray s -> ST s (Array)
9293
9394-- | Create an uninitialized mutable array.
9495unsafeNew :: forall s. Int -> ST s (MArray s)
95−unsafeNew n = assert (n >= 0) . ST $ \s1# ->
96− case bytesInArray n of
97− len@(I# len#) ->
98−#if defined(BOUNDS_CHECKING)
96+unsafeNew n =
97+#if defined(ASSERTS)
98+ assert (n >= 0) .
99+#endif
100+ ST $ \s1# ->
101+ case bytesInArray n of
102+ len@(I# len#) ->
103+#if defined(ASSERTS)
99104 if len < 0 then error (show ("unsafeNew",len)) else
100105#endif
101106 case newByteArray# len# s1# of
@@ -181,8 +186,10 @@ copy src dest
181186-- | Unsafely copy the elements of an array.
182187unsafeCopy :: MArray s -> Int -> MArray s -> Int -> Int -> ST s ()
183188unsafeCopy src sidx dest didx count =
189+#if defined(ASSERTS)
184190 assert (sidx + count <= length src) .
185191 assert (didx + count <= length dest) $
192+#endif
186193 copy_loop sidx didx 0
187194 where
188195 copy_loop !i !j !c
Data/Text/Encoding/Fusion.hs+8−2
@@ -1,4 +1,4 @@
1−{-# LANGUAGE BangPatterns, Rank2Types #-}
1+{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}
22
33-- |
44-- Module : Data.Text.Encoding.Fusion
@@ -31,7 +31,9 @@ module Data.Text.Encoding.Fusion
3131 , module Data.Text.Encoding.Fusion.Common
3232 ) where
3333
34+#if defined(ASSERTS)
3435import Control.Exception (assert)
36+#endif
3537import Data.ByteString.Internal (ByteString(..), mallocByteString, memcpy)
3638import Data.Text.Fusion (Step(..), Stream(..))
3739import Data.Text.Fusion.Size
@@ -182,7 +184,11 @@ unstream (Stream next s0 len) = unsafePerformIO $ do
182184 {-# NOINLINE trimUp #-}
183185 trimUp fp _ off = return $! PS fp 0 off
184186 copy0 :: ForeignPtr Word8 -> Int -> Int -> IO (ForeignPtr Word8)
185− copy0 !src !srcLen !destLen = assert (srcLen <= destLen) $ do
187+ copy0 !src !srcLen !destLen =
188+#if defined(ASSERTS)
189+ assert (srcLen <= destLen) $
190+#endif
191+ do
186192 dest <- mallocByteString destLen
187193 withForeignPtr src $ \src' ->
188194 withForeignPtr dest $ \dest' ->
Data/Text/Encoding/Fusion/Common.hs+1−1
@@ -28,9 +28,9 @@ module Data.Text.Encoding.Fusion.Common
2828 ) where
2929
3030import Data.Bits ((.&.))
31−import Data.Char (ord)
3231import Data.Text.Fusion (Step(..), Stream(..))
3332import Data.Text.Fusion.Internal (M(..), S(..))
33+import Data.Text.UnsafeChar (ord)
3434import Data.Text.UnsafeShift (shiftR)
3535import Data.Word (Word8)
3636import qualified Data.Text.Encoding.Utf8 as U8
Data/Text/Encoding/Utf8.hs+19−5
@@ -1,4 +1,4 @@
1−{-# LANGUAGE MagicHash #-}
1+{-# LANGUAGE CPP, MagicHash #-}
22
33-- |
44-- Module : Data.Text.Encoding.Utf16
@@ -30,9 +30,11 @@ module Data.Text.Encoding.Utf8
3030 , validate4
3131 ) where
3232
33+#if defined(ASSERTS)
3334import Control.Exception (assert)
34−import Data.Char (ord)
35+#endif
3536import Data.Bits ((.&.))
37+import Data.Text.UnsafeChar (ord)
3638import Data.Text.UnsafeShift (shiftR)
3739import GHC.Exts
3840import GHC.Word (Word8(..))
@@ -47,14 +49,22 @@ between x y z = x >= y && x <= z
4749{-# INLINE between #-}
4850
4951ord2 :: Char -> (Word8,Word8)
50−ord2 c = assert (n >= 0x80 && n <= 0x07ff) (x1,x2)
52+ord2 c =
53+#if defined(ASSERTS)
54+ assert (n >= 0x80 && n <= 0x07ff)
55+#endif
56+ (x1,x2)
5157 where
5258 n = ord c
5359 x1 = fromIntegral $ (n `shiftR` 6) + 0xC0
5460 x2 = fromIntegral $ (n .&. 0x3F) + 0x80
5561
5662ord3 :: Char -> (Word8,Word8,Word8)
57−ord3 c = assert (n >= 0x0800 && n <= 0xffff) (x1,x2,x3)
63+ord3 c =
64+#if defined(ASSERTS)
65+ assert (n >= 0x0800 && n <= 0xffff)
66+#endif
67+ (x1,x2,x3)
5868 where
5969 n = ord c
6070 x1 = fromIntegral $ (n `shiftR` 12) + 0xE0
@@ -62,7 +72,11 @@ ord3 c = assert (n >= 0x0800 && n <= 0xffff) (x1,x2,x3)
6272 x3 = fromIntegral $ (n .&. 0x3F) + 0x80
6373
6474ord4 :: Char -> (Word8,Word8,Word8,Word8)
65−ord4 c = assert (n >= 0x10000) (x1,x2,x3,x4)
75+ord4 c =
76+#if defined(ASSERTS)
77+ assert (n >= 0x10000)
78+#endif
79+ (x1,x2,x3,x4)
6680 where
6781 n = ord c
6882 x1 = fromIntegral $ (n `shiftR` 18) + 0xF0
Data/Text/Foreign.hs+9−2
@@ -1,4 +1,4 @@
1−{-# LANGUAGE BangPatterns #-}
1+{-# LANGUAGE BangPatterns, CPP #-}
22-- |
33-- Module : Data.Text.Foreign
44-- Copyright : (c) Bryan O'Sullivan 2009
@@ -25,7 +25,9 @@ module Data.Text.Foreign
2525 , unsafeCopyToPtr
2626 ) where
2727
28+#if defined(ASSERTS)
2829import Control.Exception (assert)
30+#endif
2931import Control.Monad.ST (unsafeIOToST)
3032import Data.Text.Internal (Text(..), empty)
3133import qualified Data.Text.Array as A
@@ -53,7 +55,11 @@ fromPtr :: Ptr Word16 -- ^ source array
5355 -> Int -- ^ length of source array (in 'Word16' units)
5456 -> IO Text
5557fromPtr _ 0 = return empty
56−fromPtr ptr len = assert (len > 0) $ return (Text arr 0 len)
58+fromPtr ptr len =
59+#if defined(ASSERTS)
60+ assert (len > 0) $
61+#endif
62+ return $! Text arr 0 len
5763 where
5864 arr = A.run (A.unsafeNew len >>= copy)
5965 copy marr = loop ptr 0
@@ -68,6 +74,7 @@ fromPtr ptr len = assert (len > 0) $ return (Text arr 0 len)
6874-- 'unsafeCopyToPtr'.
6975lengthWord16 :: Text -> Int
7076lengthWord16 (Text _arr _off len) = len
77+{-# INLINE lengthWord16 #-}
7178
7279-- | /O(n)/ Copy a 'Text' to an array. The array is assumed to be big
7380-- enough to hold the contents of the entire 'Text'.
Data/Text/Fusion.hs+1−2
@@ -47,9 +47,8 @@ import Prelude (Bool(..), Char, Maybe(..), Monad(..), Int,
4747 Num(..), Ord(..), ($), (&&),
4848 fromIntegral, otherwise)
4949import Data.Bits ((.&.))
50−import Data.Char (ord)
5150import Data.Text.Internal (Text(..))
52−import Data.Text.UnsafeChar (unsafeChr, unsafeWrite)
51+import Data.Text.UnsafeChar (ord, unsafeChr, unsafeWrite)
5352import Data.Text.UnsafeShift (shiftL, shiftR)
5453import qualified Data.Text.Array as A
5554import qualified Data.Text.Fusion.Common as S
Data/Text/Fusion/Size.hs+13−2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
12{-# OPTIONS_GHC -fno-warn-missing-methods #-}
23-- |
34-- Module : Data.Text.Fusion.Internal
@@ -26,7 +27,9 @@ module Data.Text.Fusion.Size
2627 , isEmpty
2728 ) where
2829
30+#if defined(ASSERTS)
2931import Control.Exception (assert)
32+#endif
3033
3134data Size = Exact {-# UNPACK #-} !Int -- ^ Exact size.
3235 | Max {-# UNPACK #-} !Int -- ^ Upper bound on size.
@@ -34,11 +37,19 @@ data Size = Exact {-# UNPACK #-} !Int -- ^ Exact size.
3437 deriving (Eq, Show)
3538
3639exactSize :: Int -> Size
37−exactSize n = assert (n >= 0) Exact n
40+exactSize n =
41+#if defined(ASSERTS)
42+ assert (n >= 0)
43+#endif
44+ Exact n
3845{-# INLINE exactSize #-}
3946
4047maxSize :: Int -> Size
41−maxSize n = assert (n >= 0) Max n
48+maxSize n =
49+#if defined(ASSERTS)
50+ assert (n >= 0)
51+#endif
52+ Max n
4253{-# INLINE maxSize #-}
4354
4455unknownSize :: Size
Data/Text/Internal.hs+12−8
@@ -1,4 +1,4 @@
1−{-# LANGUAGE DeriveDataTypeable #-}
1+{-# LANGUAGE CPP, DeriveDataTypeable #-}
22
33-- |
44-- Module : Data.Text.Internal
@@ -28,7 +28,9 @@ module Data.Text.Internal
2828 , showText
2929 ) where
3030
31+#if defined(ASSERTS)
3132import Control.Exception (assert)
33+#endif
3234import qualified Data.Text.Array as A
3335import Data.Typeable (Typeable)
3436
@@ -42,13 +44,15 @@ data Text = Text
4244-- | Smart constructor.
4345text :: A.Array -> Int -> Int -> Text
4446text arr off len =
45− assert (len >= 0) .
46− assert (off >= 0) .
47− assert (alen == 0 || len == 0 || off < alen) .
48− assert (len == 0 || c < 0xDC00 || c > 0xDFFF) $
49− Text arr off len
50− where c = A.unsafeIndex arr off
51− alen = A.length arr
47+#if defined(ASSERTS)
48+ let c = A.unsafeIndex arr off
49+ alen = A.length arr
50+ in assert (len >= 0) .
51+ assert (off >= 0) .
52+ assert (alen == 0 || len == 0 || off < alen) .
53+ assert (len == 0 || c < 0xDC00 || c > 0xDFFF) $
54+#endif
55+ Text arr off len
5256{-# INLINE text #-}
5357
5458-- | /O(1)/ The empty 'Text'.
Data/Text/Lazy/Builder.hs+13−5
@@ -1,4 +1,4 @@
1−{-# LANGUAGE BangPatterns, Rank2Types #-}
1+{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}
22
33-----------------------------------------------------------------------------
44-- |
@@ -29,7 +29,9 @@ module Data.Text.Lazy.Builder
2929 , flush
3030 ) where
3131
32+#if defined(ASSERTS)
3233import Control.Exception (assert)
34+#endif
3335import Control.Monad.ST (ST, runST)
3436import Data.Bits ((.&.))
3537import Data.Char (ord)
@@ -259,8 +261,10 @@ newBuffer size = do
259261-- | Unsafely copy the elements of an array.
260262unsafeCopy :: A.Array -> Int -> A.MArray s -> Int -> Int -> ST s ()
261263unsafeCopy src sidx dest didx count =
264+#if defined(ASSERTS)
262265 assert (sidx + count <= A.length src) .
263266 assert (didx + count <= A.length dest) $
267+#endif
264268 copy_loop sidx didx 0
265269 where
266270 copy_loop !i !j !c
@@ -274,12 +278,16 @@ unsafeCopy src sidx dest didx count =
274278unsafeWrite :: A.MArray s -> Int -> Char -> ST s Int
275279unsafeWrite marr i c
276280 | n < 0x10000 = do
277− assert (i >= 0) . assert (i < A.length marr) $
278− A.unsafeWrite marr i (fromIntegral n)
281+#if defined(ASSERTS)
282+ assert (i >= 0) . assert (i < A.length marr) $ return ()
283+#endif
284+ A.unsafeWrite marr i (fromIntegral n)
279285 return 1
280286 | otherwise = do
281− assert (i >= 0) . assert (i < A.length marr - 1) $
282− A.unsafeWrite marr i lo
287+#if defined(ASSERTS)
288+ assert (i >= 0) . assert (i < A.length marr - 1) $ return ()
289+#endif
290+ A.unsafeWrite marr i lo
283291 A.unsafeWrite marr (i+1) hi
284292 return 2
285293 where n = ord c
Data/Text/Lazy/Encoding/Fusion.hs+8−2
@@ -1,4 +1,4 @@
1−{-# LANGUAGE BangPatterns, Rank2Types #-}
1+{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}
22
33-- |
44-- Module : Data.Text.Lazy.Encoding.Fusion
@@ -43,7 +43,9 @@ import System.IO.Unsafe (unsafePerformIO)
4343import Foreign.ForeignPtr (withForeignPtr, ForeignPtr)
4444import Foreign.Storable (pokeByteOff)
4545import Data.ByteString.Internal (mallocByteString, memcpy)
46+#if defined(ASSERTS)
4647import Control.Exception (assert)
48+#endif
4749import qualified Data.ByteString.Internal as B
4850
4951data S = S0
@@ -123,7 +125,11 @@ unstreamChunks chunkSize (Stream next s0 len0) = chunk s0 (upperBound 4 len0)
123125 loop n' (off+1) s fp'
124126 trimUp fp off = B.PS fp 0 off
125127 copy0 :: ForeignPtr Word8 -> Int -> Int -> IO (ForeignPtr Word8)
126− copy0 !src !srcLen !destLen = assert (srcLen <= destLen) $ do
128+ copy0 !src !srcLen !destLen =
129+#if defined(ASSERTS)
130+ assert (srcLen <= destLen) $
131+#endif
132+ do
127133 dest <- mallocByteString destLen
128134 withForeignPtr src $ \src' ->
129135 withForeignPtr dest $ \dest' ->
Data/Text/Unsafe.hs+25−20
@@ -21,7 +21,9 @@ module Data.Text.Unsafe
2121 , unsafeTail
2222 ) where
2323
24+#if defined(ASSERTS)
2425import Control.Exception (assert)
26+#endif
2527import Data.Text.Encoding.Utf16 (chr2)
2628import Data.Text.Internal (Text(..))
2729import Data.Text.UnsafeChar (unsafeChr)
@@ -40,11 +42,11 @@ import GHC.Base (realWorld#)
4042-- omits the check for the empty case, so there is an obligation on
4143-- the programmer to provide a proof that the 'Text' is non-empty.
4244unsafeHead :: Text -> Char
43−unsafeHead (Text arr off len)
45+unsafeHead (Text arr off _len)
4446 | m < 0xD800 || m > 0xDBFF = unsafeChr m
4547 | otherwise = chr2 m n
46− where m = assert (len > 0) $ A.unsafeIndex arr off
47− n = assert (len > 1) $ A.unsafeIndex arr (off+1)
48+ where m = A.unsafeIndex arr off
49+ n = A.unsafeIndex arr (off+1)
4850{-# INLINE unsafeHead #-}
4951
5052-- | /O(1)/ A variant of 'tail' for non-empty 'Text'. 'unsafeHead'
@@ -52,42 +54,45 @@ unsafeHead (Text arr off len)
5254-- the programmer to provide a proof that the 'Text' is non-empty.
5355unsafeTail :: Text -> Text
5456unsafeTail t@(Text arr off len) =
55− assert (d <= len) $ Text arr (off+d) (len-d)
57+#if defined(ASSERTS)
58+ assert (d <= len) $
59+#endif
60+ Text arr (off+d) (len-d)
5661 where d = iter_ t 0
5762{-# INLINE unsafeTail #-}
5863
59−-- | /O(1)/ Iterate one step forwards through a UTF-16 array,
60−-- returning the current character and the delta to add to give the
61−-- next offset to iterate at.
64+-- | /O(1)/ Iterate (unsafely) one step forwards through a UTF-16
65+-- array, returning the current character and the delta to add to give
66+-- the next offset to iterate at.
6267iter :: Text -> Int -> (Char,Int)
63−iter (Text arr off len) i
68+iter (Text arr off _len) i
6469 | m < 0xD800 || m > 0xDBFF = (unsafeChr m, 1)
6570 | otherwise = (chr2 m n, 2)
66− where m = assert (i < len) $ A.unsafeIndex arr j
67− n = assert (i + 1 < len) $ A.unsafeIndex arr k
68− j = assert (i >= 0) $ off + i
69− k = j + 1
71+ where m = A.unsafeIndex arr j
72+ n = A.unsafeIndex arr k
73+ j = off + i
74+ k = j + 1
7075{-# INLINE iter #-}
7176
7277-- | /O(1)/ Iterate one step through a UTF-16 array, returning the
7378-- delta to add to give the next offset to iterate at.
7479iter_ :: Text -> Int -> Int
75−iter_ (Text arr off len) i | m < 0xD800 || m > 0xDBFF = 1
76− | otherwise = 2
77− where m = assert (i >= 0 && i < len) $ A.unsafeIndex arr (off+i)
80+iter_ (Text arr off _len) i | m < 0xD800 || m > 0xDBFF = 1
81+ | otherwise = 2
82+ where m = A.unsafeIndex arr (off+i)
7883{-# INLINE iter_ #-}
7984
8085-- | /O(1)/ Iterate one step backwards through a UTF-16 array,
8186-- returning the current character and the delta to add (i.e. a
8287-- negative number) to give the next offset to iterate at.
8388reverseIter :: Text -> Int -> (Char,Int)
84−reverseIter (Text arr off len) i
89+reverseIter (Text arr off _len) i
8590 | m < 0xDC00 || m > 0xDFFF = (unsafeChr m, -1)
8691 | otherwise = (chr2 n m, -2)
87− where m = assert (i < len) $ A.unsafeIndex arr j
88− n = assert (i - 1 >= 0) $ A.unsafeIndex arr k
89− j = assert (i >= 0) $ off + i
90− k = j - 1
92+ where m = A.unsafeIndex arr j
93+ n = A.unsafeIndex arr k
94+ j = off + i
95+ k = j - 1
9196{-# INLINE reverseIter #-}
9297
9398-- | Just like unsafePerformIO, but we inline it. Big performance gains as
Data/Text/UnsafeChar.hs+18−8
@@ -1,4 +1,4 @@
1−{-# LANGUAGE MagicHash #-}
1+{-# LANGUAGE CPP, MagicHash #-}
22
33-- |
44-- Module : Data.Text.UnsafeChar
@@ -15,22 +15,28 @@
1515-- Fast character manipulation functions.
1616module Data.Text.UnsafeChar
1717 (
18− unsafeChr
18+ ord
19+ , unsafeChr
1920 , unsafeChr8
2021 , unsafeChr32
2122 , unsafeWrite
2223 -- , unsafeWriteRev
2324 ) where
2425
26+#ifdef ASSERTS
2527import Control.Exception (assert)
28+#endif
2629import Control.Monad.ST (ST)
2730import Data.Bits ((.&.))
28−import Data.Char (ord)
2931import Data.Text.UnsafeShift (shiftR)
30−import GHC.Exts (Char(..), chr#, word2Int#)
32+import GHC.Exts (Char(..), Int(..), chr#, ord#, word2Int#)
3133import GHC.Word (Word8(..), Word16(..), Word32(..))
3234import qualified Data.Text.Array as A
3335
36+ord :: Char -> Int
37+ord (C# c#) = I# (ord# c#)
38+{-# INLINE ord #-}
39+
3440unsafeChr :: Word16 -> Char
3541unsafeChr (W16# w#) = C# (chr# (word2Int# w#))
3642{-# INLINE unsafeChr #-}
@@ -46,12 +52,16 @@ unsafeChr32 (W32# w#) = C# (chr# (word2Int# w#))
4652unsafeWrite :: A.MArray s -> Int -> Char -> ST s Int
4753unsafeWrite marr i c
4854 | n < 0x10000 = do
49− assert (i >= 0) . assert (i < A.length marr) $
50− A.unsafeWrite marr i (fromIntegral n)
55+#if defined(ASSERTS)
56+ assert (i >= 0) . assert (i < A.length marr) $ return ()
57+#endif
58+ A.unsafeWrite marr i (fromIntegral n)
5159 return $! i+1
5260 | otherwise = do
53− assert (i >= 0) . assert (i < A.length marr - 1) $
54− A.unsafeWrite marr i lo
61+#if defined(ASSERTS)
62+ assert (i >= 0) . assert (i < A.length marr - 1) $ return ()
63+#endif
64+ A.unsafeWrite marr i lo
5565 A.unsafeWrite marr (i+1) hi
5666 return $! i+2
5767 where n = ord c
text.cabal+1
@@ -85,3 +85,4 @@ library
8585 ghc-options: -fwarn-tabs
8686 if flag(developer)
8787 ghc-options: -Werror
88+ cpp-options: -DASSERTS