From 9f21550c5800e2773688471a85a0d5c8cd657691 Mon Sep 17 00:00:00 2001 From: Jeremy Fleischman Date: Sun, 17 May 2026 11:47:27 -0700 Subject: [PATCH] Fix warnings (that will be) introduced by ghc upgrade MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're upgrading to GHC 9.10.3, and it will start to emit warnings about risky use of partial functions. AFAICT, the old code wasn't wrong (we were always checking for empty list before trying to call `head` on it, for example), but it's nice when a compiler can check things for us! ``` $ cabal build ... src/Nixfmt/Types.hs:375:68: warning: [GHC-63394] [-Wx-partial] In the use of ‘head’ (imported from Prelude, but defined in GHC.Internal.List): "This is a partial function, it throws an error on empty lists. Use pattern matching, 'Data.List.uncons' or 'Data.Maybe.listToMaybe' instead. Consider refactoring to use "Data.List.NonEmpty"." | 375 | (List _ items _) | Prelude.length (unItems items) == 1 -> case Prelude.head (unItems items) of | ^^^^^^^^^^^^ src/Nixfmt/Types.hs:384:69: warning: [GHC-63394] [-Wx-partial] In the use of ‘head’ (imported from Prelude, but defined in GHC.Internal.List): "This is a partial function, it throws an error on empty lists. Use pattern matching, 'Data.List.uncons' or 'Data.Maybe.listToMaybe' instead. Consider refactoring to use "Data.List.NonEmpty"." | 384 | (Set _ _ items _) | Prelude.length (unItems items) == 1 -> case Prelude.head (unItems items) of | ^^^^^^^^^^^^ [3 of 8] Compiling Nixfmt.Predoc ( src/Nixfmt/Predoc.hs, dist-newstyle/build/x86_64-linux/ghc-9.10.3/nixfmt-1.2.0/build/Nixfmt/Predoc.o, dist-newstyle/build/x86_64-linux/ghc-9.10.3/nixfmt-1.2.0/build/Nixfmt/Predoc.dyn_o ) src/Nixfmt/Predoc.hs:169:35: warning: [GHC-63394] [-Wx-partial] In the use of ‘head’ (imported from Prelude, but defined in GHC.Internal.List): "This is a partial function, it throws an error on empty lists. Use pattern matching, 'Data.List.uncons' or 'Data.Maybe.listToMaybe' instead. Consider refactoring to use "Data.List.NonEmpty"." | 169 | if p /= [] && (isSoftSpacing (head p) || isSoftSpacing (last p)) | ^^^^ src/Nixfmt/Predoc.hs:634:27: warning: [GHC-63394] [-Wx-partial] In the use of ‘head’ (imported from Prelude, but defined in GHC.Internal.List): "This is a partial function, it throws an error on empty lists. Use pattern matching, 'Data.List.uncons' or 'Data.Maybe.listToMaybe' instead. Consider refactoring to use "Data.List.NonEmpty"." | 634 | grp' = case head grp of | ^^^^ src/Nixfmt/Predoc.hs:635:30: warning: [GHC-63394] [-Wx-partial] In the use of ‘tail’ (imported from Prelude, but defined in GHC.Internal.List): "This is a partial function, it throws an error on empty lists. Replace it with 'drop' 1, or use pattern matching or 'GHC.Internal.Data.List.uncons' instead. Consider refactoring to use "Data.List.NonEmpty"." | 635 | Spacing _ -> tail grp | ^^^^ src/Nixfmt/Predoc.hs:636:70: warning: [GHC-63394] [-Wx-partial] In the use of ‘tail’ (imported from Prelude, but defined in GHC.Internal.List): "This is a partial function, it throws an error on empty lists. Replace it with 'drop' 1, or use pattern matching or 'GHC.Internal.Data.List.uncons' instead. Consider refactoring to use "Data.List.NonEmpty"." | 636 | Group ann ((Spacing _) : inner) -> Group ann inner : tail grp | ^^^^ ``` Co-authored-by: Dyego Aurélio --- src/Nixfmt/Predoc.hs | 14 ++++++++------ src/Nixfmt/Types.hs | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Nixfmt/Predoc.hs b/src/Nixfmt/Predoc.hs index 9741a5c3..d265bb37 100644 --- a/src/Nixfmt/Predoc.hs +++ b/src/Nixfmt/Predoc.hs @@ -166,9 +166,11 @@ trailing t = [Text 0 0 Trailing t] group :: (HasCallStack) => (Pretty a) => a -> Doc group x = pure . Group RegularG $ - if p /= [] && (isSoftSpacing (head p) || isSoftSpacing (last p)) - then error $ "group should not start or end with whitespace, use `group'` if you are sure; " <> show p - else p + case p of + (headP : _) + | isSoftSpacing headP || isSoftSpacing (last p) -> + error $ "group should not start or end with whitespace, use `group'` if you are sure; " <> show p + _ -> p where p = pretty x @@ -631,9 +633,9 @@ layoutGreedy tw iw doc = Text.concat $ evalState (go [Group RegularG doc] []) (0 then let -- We know that the last printed character was a line break (cc == 0), -- therefore drop any leading whitespace within the group to avoid duplicate newlines - grp' = case head grp of - Spacing _ -> tail grp - Group ann ((Spacing _) : inner) -> Group ann inner : tail grp + grp' = case grp of + Spacing _ : tl -> tl + Group ann ((Spacing _) : inner) : tl -> Group ann inner : tl _ -> grp (nl, off) = nextIndent grp' diff --git a/src/Nixfmt/Types.hs b/src/Nixfmt/Types.hs index 1ddac3d0..d964eadd 100644 --- a/src/Nixfmt/Types.hs +++ b/src/Nixfmt/Types.hs @@ -372,7 +372,7 @@ instance LanguageElement Term where walkSubprograms = \case -- Map each item to a singleton list, then handle that - (List _ items _) | Prelude.length (unItems items) == 1 -> case Prelude.head (unItems items) of + (List _ (Items [singleItem]) _) -> case singleItem of (Item item) -> [Term item] (Comments _) -> [] (List open items close) -> @@ -381,7 +381,7 @@ instance LanguageElement Term where [Term (List (stripTrivia open) (Items [Item item]) (stripTrivia close))] Comments c -> [Term (List (stripTrivia open) (Items [Comments c]) (stripTrivia close))] - (Set _ _ items _) | Prelude.length (unItems items) == 1 -> case Prelude.head (unItems items) of + (Set _ _ (Items [singleItem]) _) -> case singleItem of (Item (Inherit _ from sels _)) -> (Term <$> maybeToList from) ++ concatMap walkSubprograms sels (Item (Assignment sels _ expr _)) ->