-
Notifications
You must be signed in to change notification settings - Fork 9
Description
Compiling glgen with GHC 9.8.1 reveals a number of -Wx-partial warnings caused by uses of the partial head and tail functions:
Details
[1 of 7] Compiling Registry ( src/Registry.hs, interpreted )
src/Registry.hs:96:3: warning: [GHC-63394] [-Wx-partial]
In the use of ‘head’
(imported from Prelude, but defined in Just GHC.List):
"This is a partial function, it throws an error on empty lists. Use pattern matching or Data.List.uncons instead. Consider refactoring to use Data.List.NonEmpty."
|
96 | head . filter ((== command) . commandName) $ registryCommands registry
| ^^^^
src/Registry.hs:100:3: warning: [GHC-63394] [-Wx-partial]
In the use of ‘head’
(imported from Prelude, but defined in Just GHC.List):
"This is a partial function, it throws an error on empty lists. Use pattern matching or Data.List.uncons instead. Consider refactoring to use Data.List.NonEmpty."
|
100 | head . filter ((== enum) . enumName) $ registryEnums registry
| ^^^^
[2 of 7] Compiling Parser ( src/Parser.hs, interpreted )
src/Parser.hs:120:27: warning: [GHC-63394] [-Wx-partial]
In the use of ‘head’
(imported from Prelude, but defined in Just GHC.List):
"This is a partial function, it throws an error on empty lists. Use pattern matching or Data.List.uncons instead. Consider refactoring to use Data.List.NonEmpty."
|
120 | parseFile file = return . head =<< runX (readDocument [withRemoveWS yes] file >>> parse)
| ^^^^
[3 of 7] Compiling Utils ( src/Utils.hs, interpreted )
[4 of 7] Compiling Module ( src/Module.hs, interpreted )
[5 of 7] Compiling Generator ( src/Generator.hs, interpreted )
src/Generator.hs:48:47: warning: [GHC-63394] [-Wx-partial]
In the use of ‘tail’
(imported from Prelude, but defined in Just GHC.List):
"This is a partial function, it throws an error on empty lists. Replace it with drop 1, or use pattern matching or Data.List.uncons instead. Consider refactoring to use Data.List.NonEmpty."
|
48 | saneEnum = ("GL_"++) . List.intercalate "_" . tail . splitOn "_"
| ^^^^
src/Generator.hs:517:46: warning: [GHC-63394] [-Wx-partial]
In the use of ‘tail’
(imported from Prelude, but defined in Just GHC.List):
"This is a partial function, it throws an error on empty lists. Replace it with drop 1, or use pattern matching or Data.List.uncons instead. Consider refactoring to use Data.List.NonEmpty."
|
517 | [ "gl_" ++ (List.intercalate "_" . tail $ splitOn "_" en)
| ^^^^
src/Generator.hs:553:26: warning: [GHC-63394] [-Wx-partial]
In the use of ‘tail’
(imported from Prelude, but defined in Just GHC.List):
"This is a partial function, it throws an error on empty lists. Replace it with drop 1, or use pattern matching or Data.List.uncons instead. Consider refactoring to use Data.List.NonEmpty."
|
553 | | parts@(_:_) <- tail (splitOn "_" en) ->
| ^^^^
src/Generator.hs:576:29: warning: [GHC-63394] [-Wx-partial]
In the use of ‘head’
(imported from Prelude, but defined in Just GHC.List):
"This is a partial function, it throws an error on empty lists. Use pattern matching or Data.List.uncons instead. Consider refactoring to use Data.List.NonEmpty."
|
576 | . filter (\x -> grp == (head . tail . splitOn "_" $ snd x))
| ^^^^
src/Generator.hs:576:36: warning: [GHC-63394] [-Wx-partial]
In the use of ‘tail’
(imported from Prelude, but defined in Just GHC.List):
"This is a partial function, it throws an error on empty lists. Replace it with drop 1, or use pattern matching or Data.List.uncons instead. Consider refactoring to use Data.List.NonEmpty."
|
576 | . filter (\x -> grp == (head . tail . splitOn "_" $ snd x))
| ^^^^
src/Generator.hs:583:12: warning: [GHC-63394] [-Wx-partial]
In the use of ‘head’
(imported from Prelude, but defined in Just GHC.List):
"This is a partial function, it throws an error on empty lists. Use pattern matching or Data.List.uncons instead. Consider refactoring to use Data.List.NonEmpty."
|
583 | . map (head . tail . splitOn "_" . snd)
| ^^^^
src/Generator.hs:583:19: warning: [GHC-63394] [-Wx-partial]
In the use of ‘tail’
(imported from Prelude, but defined in Just GHC.List):
"This is a partial function, it throws an error on empty lists. Replace it with drop 1, or use pattern matching or Data.List.uncons instead. Consider refactoring to use Data.List.NonEmpty."
|
583 | . map (head . tail . splitOn "_" . snd)
| ^^^^
Most of this code is probably safe due to the assumption that the inputs are always structured in a certain way. We should document these assumptions and refactor the code to provide more specific error messages if these assumptions are violated.
Once possible thing that we could do to avoid some uses of head and tail is to change the type of Utils.splitOn slightly. Currently, it is:
Line 23 in fa022ee
| splitOn :: Eq a => [a] -> [a] -> [[a]] |
But I think it could just as well be:
splitOn :: Eq a => [a] -> [a] -> NonEmpty [a] If we made this change, then several calls to Prelude.{head,tail} above could be replaced with Data.List.NonEmpty.{head,tail}, which are total. This would require one small change to the behavior of splitOn itself:
-splitOn :: Eq a => [a] -> [a] -> [[a]]
-splitOn _ [] = []
+splitOn :: Eq a => [a] -> [a] -> NonEmpty [a]
+splitOn _ [] = [] :| []But I think this is worth doing anyway, as the behavior of Utils.splitOn differs from the splitOn functions in the split and text packages when the second argument is empty. Making this change to Utils.splitOn brings it in line with the behavior of the splitOn functions in split and text. (I don't think glgen ever calls splitOn on an empty list, but better safe than sorry.)