diff --git a/flatparse.cabal b/flatparse.cabal
--- a/flatparse.cabal
+++ b/flatparse.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           flatparse
-version:        0.4.0.1
+version:        0.4.0.2
 synopsis:       High-performance parsing from strict bytestrings
 description:    @Flatparse@ is a high-performance parsing library for strict bytestring input. See the README for more information:
                 <https://github.com/AndrasKovacs/flatparse>.
diff --git a/src/FlatParse/Basic.hs b/src/FlatParse/Basic.hs
--- a/src/FlatParse/Basic.hs
+++ b/src/FlatParse/Basic.hs
@@ -386,9 +386,10 @@
         _      -> error "FlatParse.Basic.validPos: got a non-OK result, impossible"
 {-# inline validPos #-}
 
--- | Compute corresponding line and column numbers for each `Pos` in a list. Throw an error
---   on invalid positions. Note: computing lines and columns may traverse the `B.ByteString`,
---   but it traverses it only once regardless of the length of the position list.
+-- | Compute corresponding line and column numbers for each `Pos` in a list,
+--   assuming UTF8 encoding. Throw an error on invalid positions. Note:
+--   computing lines and columns may traverse the `B.ByteString`, but it
+--   traverses it only once regardless of the length of the position list.
 posLineCols :: B.ByteString -> [Pos] -> [(Int, Int)]
 posLineCols str poss =
   let go !line !col [] = pure []
@@ -404,7 +405,7 @@
             go line (col + 1) ((i, pos):poss)
 
       sorted :: [(Int, Pos)]
-      sorted = sortBy (comparing snd) (zip [0..] poss)
+      sorted = sortBy (\(_, i) (_, j) -> compare j i) (zip [0..] poss)
 
   in case runParser (go 0 0 sorted) str of
        OK res _ -> snd <$> sortBy (comparing fst) res
diff --git a/src/FlatParse/Basic/Parser.hs b/src/FlatParse/Basic/Parser.hs
--- a/src/FlatParse/Basic/Parser.hs
+++ b/src/FlatParse/Basic/Parser.hs
@@ -34,8 +34,7 @@
 
 -- | @ParserT st e a@ is a parser with a state token type @st@, an error type
 --   @e@ and a return type @a@. The different state token types support
---   different embededded effects; see `Parser`, `ParserIO` and `ParserST`
---   below.
+--   different embedded effects; see `Parser`, `ParserIO` and `ParserST` below.
 newtype ParserT (st :: ZeroBitType) e a =
     ParserT { runParserT# :: ForeignPtrContents -> Addr# -> Addr# -> st -> Res# st e a }
 
diff --git a/src/FlatParse/Basic/Text.hs b/src/FlatParse/Basic/Text.hs
--- a/src/FlatParse/Basic/Text.hs
+++ b/src/FlatParse/Basic/Text.hs
@@ -96,8 +96,11 @@
     :: (Char -> Bool) -> (Char -> ParserT st e r) -> ParserT st e r
 withSatisfy f p = ParserT \fp eob s st ->
     case runParserT# anyChar fp eob s st of
-      OK# st c s | f c -> runParserT# (p c) fp eob s st
-      (# st, _ #)      -> Fail# st
+      -- This is OK# unfolded, to silence incomplete pattern warnings
+      -- in GHC <= 8.8.4.
+      (# st, (# (# c, s #) | | #) #) | f c -> runParserT# (p c) fp eob s st
+
+      (# st, _ #)                          -> Fail# st
 {-# inline withSatisfy #-}
 
 -- | Parse a UTF-8 'Char' for which a predicate holds.
diff --git a/src/FlatParse/Stateful/Parser.hs b/src/FlatParse/Stateful/Parser.hs
--- a/src/FlatParse/Stateful/Parser.hs
+++ b/src/FlatParse/Stateful/Parser.hs
@@ -34,7 +34,7 @@
 
 -- | @ParserT st r e a@ is a parser with a state token type @st@, a reader
 --   environment @r@, an error type @e@ and a return type @a@. The different
---   state token types support different embededded effects; see `Parser`,
+--   state token types support different embedded effects; see `Parser`,
 --   `ParserIO` and `ParserST` below.
 newtype ParserT (st :: ZeroBitType) r e a =
     ParserT { runParserT# :: ForeignPtrContents -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a }
diff --git a/src/FlatParse/Stateful/Text.hs b/src/FlatParse/Stateful/Text.hs
--- a/src/FlatParse/Stateful/Text.hs
+++ b/src/FlatParse/Stateful/Text.hs
@@ -96,8 +96,10 @@
     :: (Char -> Bool) -> (Char -> ParserT st r e ret) -> ParserT st r e ret
 withSatisfy f p = ParserT \fp !r eob s n st ->
     case runParserT# anyChar fp r eob s n st of
-      OK# st c s n | f c -> runParserT# (p c) fp r eob s n st
-      (# st, _ #)        -> Fail# st
+      -- This is OK# unfolded, to silence incomplete pattern warnings
+      -- in GHC <= 8.8.4.
+      (# st, (# (# c, s, n #) | | #) #) | f c -> runParserT# (p c) fp r eob s n st
+      (# st, _ #)                             -> Fail# st
 {-# inline withSatisfy #-}
 
 -- | Parse a UTF-8 'Char' for which a predicate holds.
diff --git a/test/Test.hs b/test/Test.hs
--- a/test/Test.hs
+++ b/test/Test.hs
@@ -645,7 +645,13 @@
       pure ()
 
     describe "posLineCols" $ do
-      pure ()
+      let str = FB.strToUtf8 "monkey"
+
+      it "empty"    $ FB.posLineCols str [] `shouldBe` []
+      it "single"   $ FB.posLineCols str [FB.Pos 0] `shouldBe` [(0,6)]
+      it "two"      $ FB.posLineCols str [FB.Pos 0, FB.Pos 1] `shouldBe` [(0,6), (0,5)]
+      it "three"    $ FB.posLineCols str [FB.Pos 3, FB.Pos 5, FB.Pos 4] `shouldBe` [(0,3),(0,1),(0,2)]
+      it "emptystr" $ FB.posLineCols mempty [] `shouldBe` []
 
     describe "unsafeSpanToByteString" $ do
       pure ()
