error-messages icon indicating copy to clipboard operation
error-messages copied to clipboard

Better error messages for top level declarations (module, import)

Open scarf005 opened this issue 2 years ago • 1 comments

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?

scarf005 avatar Jul 11 '23 09:07 scarf005

This is a subset of what https://gitlab.haskell.org/ghc/ghc/-/issues/24351 would provide.

cbrt-x avatar May 20 '24 18:05 cbrt-x