haskell / haskell/error-messages

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

Open
#545 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
No language data
Stars
76
Forks
19
PR merge metrics
No merged PRs in 30d

Description

# 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'](https://stackoverflow.com/a/50197721/13503626).

## Typos

### Reproduction

```hs
improt Data.List
main = putStrLn "Hello, World"
```
```hs
main = putStrLn "Hello, World"
improt Data.List
```
```hs
modul main
main = putStrLn "Hello, World"
```

### Current Message

```hs
test.hs:1:1: error:
Parse error: module header, import declaration
or top-level declaration expected.
|
1 | improt Data.List
| ^^^^^^^^^^^^^^^^
```

### Suggestion

```hs
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

```hs
main = putStrLn "Hello, World"

import Data.List
```

### Current Message

```hs
test.hs:3:1: error: parse error on input ‘import’
|
3 | import Data.List
| ^^^^^^
```

### Suggestion

```hs
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

```hs
module Foo
main = putStrLn "Hello, World"
```

### Current Message

```hs
test.hs:2:1: error: parse error on input ‘main’
|
2 | main = putStrLn "Hello, World"
|
```

### Suggestion

```hs
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

```hs
module foo where
main = putStrLn "Hello, World"
```

### Current Message
```hs
test.hs:1:8: error: parse error on input ‘foo’
|
1 | module foo where
|
```
### Suggestion

```hs
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

```hs
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

```hs
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

```hs
foo
```

### Current Message

```hs
test.hs:1:1: error:
Parse error: module header, import declaration
or top-level declaration expected.
|
1 | foo
| ^^^
```

### Suggestion

```hs
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

```hs
foo = 4
fooo
```

### Current Message

```hs
test.hs:2:1: error:
Parse error: module header, import declaration
or top-level declaration expected.
|
2 | foo
| ^^^
```

### Suggestion

```hs
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?

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.