Better error messages for top level declarations (module, import)
Summary
I think there's some room for improvement for error messages on top level declarations[^1] (module, import).
[^1]: Also the word 'top level declaration' could be made more helpful by giving some detailed explanation. Because I didn't know what does that mean and had to stackoverflow it and got 'gatekeeped'.
Typos
Reproduction
improt Data.List
main = putStrLn "Hello, World"
main = putStrLn "Hello, World"
improt Data.List
modul main
main = putStrLn "Hello, World"
Current Message
test.hs:1:1: error:
Parse error: module header, import declaration
or top-level declaration expected.
|
1 | improt Data.List
| ^^^^^^^^^^^^^^^^
Suggestion
test.hs:1:1:
error:
Parse error: module header, import declaration
or top-level declaration expected.
|
1 | improt Data.List
| ^^^^^^^^^^^^^^^^
hint:
Perhaps you meant ‘import’ (typo of improt) to import a module?
|
1 | import Data.List
| ~~~~~~
https://github.com/ghc/ghc/blob/4926af7b018212356e9966685717c24a8da04030/compiler/GHC/Tc/Errors/Ppr.hs#L5989-L5991 Addressing it might be more complicated than I've anticipated as the error is actually from template haskell type checker...
Non-top-level imports
main = putStrLn "Hello, World"
import Data.List
Current Message
test.hs:3:1: error: parse error on input ‘import’
|
3 | import Data.List
| ^^^^^^
Suggestion
test.hs:3:1:
error:
Import statement must be placed at the top of the source code.
|
3 | import Data.List
| ^^^^^^
hint:
Moving it to the top of the file will make the statement valid.
1 | import Data.List
| ~~~~~~~~~~~~~~~~
2 | main = putStrLn "Hello, World"
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Missing where in modules
module Foo
main = putStrLn "Hello, World"
Current Message
test.hs:2:1: error: parse error on input ‘main’
|
2 | main = putStrLn "Hello, World"
|
Suggestion
test.hs:1:8:
error:
Module declaration must end with ‘where’.
|
1 | module Foo
| ^^^^^^^^^^
hint:
Adding ‘where’ at the end of module statement will finish it.
|
1 | module Foo where
| ~~~~~
Module names in lowercase
module foo where
main = putStrLn "Hello, World"
Current Message
test.hs:1:8: error: parse error on input ‘foo’
|
1 | module foo where
|
Suggestion
test.hs:1:8:
error:
module name ‘foo’ must be in PascalCase.
|
1 | module foo where
| ^^^
hint:
Perhaps you wanted to capitalize the first letter?
|
1 | module Foo where
| ~~~
Import statement before module statement
Reproduction
import Data.List
module Foo where
main = putStrLn "Hello, World"
Current Message
test.hs:2:1: error: parse error on input ‘module’
|
2 | module Foo where
| ^^^^^^
Suggestion
test.hs:2:1:
error:
‘module’ statement must be the first statement of the program.
1 | import Data.List
2 | module Foo where
| ^^^^^^
hint:
Move the ‘module’ statement to the top of file.
1 | module Foo where
| ~~~~~~~~~~~~~~~~
2 | import Data.List
| ~~~~~~~~~~~~~~~~
Top-level declarations
Reproduction
foo
Current Message
test.hs:1:1: error:
Parse error: module header, import declaration
or top-level declaration expected.
|
1 | foo
| ^^^
Suggestion
test.hs:1:1:
error:
Sorry, I can't figure out what ‘foo’ is.
Only following declarations are allowed on top level:
- module header (e.g: module Main where)
- import declaration (e.g: import Data.List)
- top-level declaration (e.g: myvalue = 4)
And ‘foo’ is not one of them.
|
1 | foo
| ^^^
hint:
I wasn't able to find anything about ‘foo’.
Perhaps you wanted to write a top-level declaration for ‘foo’?
For example, if you wanted to declare
‘foo’ to be equivalent to number ‘3’:
|
1 | foo = 3
| ~~~~~~~
...Or perhaps your cat ran over the keyboard?
Then you may want to delete ‘foo’.
|
1 |
| ~~~
Top-level declaration and a typo
Reproduction
foo = 4
fooo
Current Message
test.hs:2:1: error:
Parse error: module header, import declaration
or top-level declaration expected.
|
2 | foo
| ^^^
Suggestion
test.hs:2:1:
error:
‘fooo’ (possible typo of ‘foo’) is an expression,
However only following declarations are allowed on top level:
- module header (e.g: module Main where)
- import declaration (e.g: import Data.List)
- top-level declaration (e.g: myvalue = 4)
2 | fooo
| ^^^
hint:
Found similar declaration ‘foo’ on line 1:
1 | foo = 4
| ~~~~~~~
Perhaps you meant to add a type declaration to ‘foo’?
1 | foo = 4
|
2 | foo :: Integer
| ~~~~~~~~~~ (type inferred from context)
...Or perhaps your cat ran over the keyboard?
Then you may want to delete ‘fooo’.
|
2 |
| ~~~
System Info
- Kubuntu 23.04
- GHC 9.4.5 (confirmed source code hasn't changed on master)
Others
The list got a bit long, maybe i should separate them to separate issues with tasklist?
This is a subset of what https://gitlab.haskell.org/ghc/ghc/-/issues/24351 would provide.