Make hGetContents throw an exception if an error is encountered
authorSimon Marlow <marlowsd@gmail.com>
Mon, 12 Oct 2009 15:29:55 +0000 (15:29 +0000)
committerSimon Marlow <marlowsd@gmail.com>
Mon, 12 Oct 2009 15:29:55 +0000 (15:29 +0000)
Strictly speaking this breaks Haskell 98 compatibility, which requires
hGetContents to just end the lazy stream silently if an error is
encountered.  However, for a few reasons we think it will make
everyone's life a bit easier if we make this change

 1. Errors will be a lot more common in GHC 6.12.1, in the form
    of Unicode decoding errors.

 2. When Haskell 98 was designed, we didn't know how to throw
    exceptions from inside lazy I/O, but now we do.

 3. If anyone is actually relying on the previous behaviour, their
    code is arguably broken.

GHC/IO/Handle/Text.hs

index ed3a106..ebbacd4 100644 (file)
@@ -355,12 +355,12 @@ hGetContents handle =
 lazyRead :: Handle -> IO String
 lazyRead handle = 
    unsafeInterleaveIO $
-        withHandle "lazyRead" handle $ \ handle_ -> do
+        withHandle "hGetContents" handle $ \ handle_ -> do
         case haType handle_ of
           ClosedHandle     -> return (handle_, "")
           SemiClosedHandle -> lazyReadBuffered handle handle_
           _ -> ioException 
-                  (IOError (Just handle) IllegalOperation "lazyRead"
+                  (IOError (Just handle) IllegalOperation "hGetContents"
                         "illegal handle type" Nothing Nothing)
 
 lazyReadBuffered :: Handle -> Handle__ -> IO (Handle__, [Char])
@@ -377,14 +377,15 @@ lazyReadBuffered h handle_@Handle__{..} = do
             writeIORef haCharBuffer (bufferAdjustL r buf')
             return (handle_, s)
         )
-        -- all I/O errors are discarded.  Additionally, we close the handle.
         (\e -> do (handle_', _) <- hClose_help handle_
                   debugIO ("hGetContents caught: " ++ show e)
                   -- We might have a \r cached in CRLF mode.  So we
                   -- need to check for that and return it:
-                  if not (isEmptyBuffer buf)
-                     then return (handle_', "\r")
-                     else return (handle_', "")
+                  if isEOFError e
+                     then if not (isEmptyBuffer buf)
+                             then return (handle_', "\r")
+                             else return (handle_', "")
+                     else ioError e
         )
 
 -- ensure we have some characters in the buffer