Skip to content

Commit

Permalink
Merge branch 'haskellfoundation:main' into dylan-thinnes/generate-mac…
Browse files Browse the repository at this point in the history
…hine-readable-spec
  • Loading branch information
dylan-thinnes authored Jun 20, 2024
2 parents 261c084 + ce45359 commit ce50ee6
Show file tree
Hide file tree
Showing 19 changed files with 257 additions and 75 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ issue][new-issue] and someone will help you out.)*
[new-issue]: https://github.com/haskellfoundation/error-message-index/issues/new

1. Change to the `message-index` directory.
2. Execute `runghc create-message-template.hs` and answer the questions.
2. Execute the cabal script `./create-message-template.hs` and answer the questions.
3. Optionally commit the new files and create a draft pull request right away.

The files created by the tool will need further editing, but it's never too
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Today, the Haskell Message Index supports three tools. Any user-facing Haskell-r
| GHC | 9.6.1 | `GHC-` |
| Stack | 2.9.3 | `S-` |
| GHCup | 0.1.19.0 | `GHCup-` |
| Cabal | 3.12 | `Cabal-` |

## Contributing to the Message Index

Expand Down
145 changes: 73 additions & 72 deletions message-index/create-message-template.hs
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
#!/usr/bin/env cabal
{- cabal:
build-depends: base, haskeline >=0.8, directory >= 1.3, filepath >= 1.4
-}
module Main where

import Control.Monad (forM, forM_)
import Control.Monad.IO.Class (liftIO)
import Data.Char (isLower, isSpace, toLower, toUpper)
import Data.Maybe (fromMaybe)
import System.Console.Haskeline
import System.Directory (createDirectory, createDirectoryIfMissing)
import System.FilePath ((<.>), (</>))
import System.IO (BufferMode (..), hSetBuffering, stdout)
import Text.Read (readMaybe)

-------------------------------------------------------------------------------
-- Run this tool with `runghc` on the commandline:

-- $ runghc create-message-template.hs
type ToolM a = InputT IO a

-------------------------------------------------------------------------------
getInputLine' :: String -> ToolM String
getInputLine' s = do
ln <- getInputLine s
pure (fromMaybe "" ln)

-------------------------------------------------------------------------------
-- Querying the user about the diagnostic
Expand All @@ -27,26 +34,28 @@ normalize = fmap toLower . strip

-- Querying for the tool: GHC / GHCup / Stack

data Tool = GHC | GHCup | Stack deriving (Show)
data Tool = GHC | GHCup | Stack | Cabal deriving (Show)

readTool :: IO Tool
readTool :: ToolM Tool
readTool = do
putStrLn "· Which tool's error code do you want to document?"
putStrLn " 1) GHC"
putStrLn " 2) GHCup"
putStrLn " 3) Stack"
putStr "Input (Default = GHC): "
ln <- getLine
outputStrLn "· Which tool's error code do you want to document?"
outputStrLn " 1) GHC"
outputStrLn " 2) GHCup"
outputStrLn " 3) Stack"
outputStrLn " 4) Cabal"
ln <- getInputLine' "Input (Default = GHC): "
case normalize ln of
"1" -> pure GHC
"ghc" -> pure GHC
"2" -> pure GHCup
"ghcup" -> pure GHCup
"3" -> pure Stack
"stack" -> pure Stack
"4" -> pure Cabal
"cabal" -> pure Cabal
"" -> pure GHC
_ -> do
putStrLn "Didn't understand input. Please type a tool name or a number."
outputStrLn "Didn't understand input. Please type a tool name or a number."
readTool

-- Querying for the error code
Expand All @@ -55,80 +64,74 @@ readTool = do
-- to preserve leading 0's.
type ErrorCode = String

readCode :: IO ErrorCode
readCode :: ToolM ErrorCode
readCode = do
putStrLn "· What is the numeric code that you want to document?"
putStrLn "For example, enter \"01234\" if you want to document GHC-01234."
putStr "Input: "
ln <- getLine
outputStrLn "· What is the numeric code that you want to document?"
outputStrLn "For example, enter \"01234\" if you want to document GHC-01234."
ln <- getInputLine' "Input: "
case readMaybe ln :: Maybe Int of
Nothing -> do
putStrLn "Could not parse the input as an integer. Only enter the numeric part of the error."
outputStrLn "Could not parse the input as an integer. Only enter the numeric part of the error."
readCode
Just _ -> pure ln

-- Title
type Title = String

readTitle :: IO Title
readTitle :: ToolM Title
readTitle = do
putStrLn "· What is the title of the error message?"
putStrLn "This is used as the title of the documentation page as well as in links to the page."
putStr "Input: "
getLine
outputStrLn "· What is the title of the error message?"
outputStrLn "This is used as the title of the documentation page as well as in links to the page."
getInputLine' "Input: "

-- Summary
type Summary = String

readSummary :: IO Summary
readSummary :: ToolM Summary
readSummary = do
putStrLn "· Give a short summary of the error message."
putStrLn "This appears on the overview page that lists all the documented errors and warnings."
putStr "Input: "
getLine
outputStrLn "· Give a short summary of the error message."
outputStrLn "This appears on the overview page that lists all the documented errors and warnings."
getInputLine' "Input: "

-- Severity
data Severity = Error | Warning deriving (Show)

readSeverity :: IO Severity
readSeverity :: ToolM Severity
readSeverity = do
putStrLn "· What is the severity of the diagnostic?"
putStrLn " 1) Error"
putStrLn " 2) Warning"
putStr "Input (Default = Error): "
ln <- getLine
outputStrLn "· What is the severity of the diagnostic?"
outputStrLn " 1) Error"
outputStrLn " 2) Warning"
ln <- getInputLine' "Input (Default = Error): "
case normalize ln of
"1" -> pure Error
"error" -> pure Error
"2" -> pure Warning
"warning" -> pure Warning
"" -> pure Error
_ -> do
putStrLn "Please type \"error\" or \"warning\" or a number."
outputStrLn "Please type \"error\" or \"warning\" or a number."
readSeverity

-- Warning flag
type WarningFlag = String

-- | Only ask for a warning flag if Severity = Warning.
readWarningFlag :: Severity -> IO (Maybe WarningFlag)
readWarningFlag :: Severity -> ToolM (Maybe WarningFlag)
readWarningFlag Warning = do
putStrLn "· What is the warning flag which enables this warning?"
putStrLn "For example, enter \"-Wtabs\" if you are documenting GHC's warning about tabs in your source file."
putStrLn "You can leave this blank if you're not sure."
putStr "Input: "
Just <$> getLine
outputStrLn "· What is the warning flag which enables this warning?"
outputStrLn "For example, enter \"-Wtabs\" if you are documenting GHC's warning about tabs in your source file."
outputStrLn "You can leave this blank if you're not sure."
Just <$> getInputLine' "Input: "
readWarningFlag _ = pure Nothing

-- Version
type Version = String

readVersion :: IO Version
readVersion :: ToolM Version
readVersion = do
putStrLn "· Which version of the tool emitted the numeric code (not the message) for the first time?"
putStrLn "Note: For GHC this is most likely 9.6.1."
putStr "Input: "
getLine
outputStrLn "· Which version of the tool emitted the numeric code (not the message) for the first time?"
outputStrLn "Note: For GHC this is most likely 9.6.1."
getInputLine' "Input: "

-- Examples
type Examples = [String]
Expand All @@ -138,23 +141,21 @@ validateExampleName "" = False
validateExampleName str@(s : _) = not (any isSpace str) && isLower s

-- | Only ask for examples if the system is GHC.
readExamples :: Tool -> IO Examples
readExamples :: Tool -> ToolM Examples
readExamples GHC = do
putStrLn "· How many examples should be generated?"
putStr "Input: "
ln <- getLine
outputStrLn "· How many examples should be generated?"
ln <- getInputLine' "Input: "
case readMaybe ln :: Maybe Int of
Nothing -> pure []
Just n -> forM [1 .. n] readExample
readExamples _ = pure []

readExample :: Int -> IO String
readExample :: Int -> ToolM String
readExample i = do
putStrLn ""
putStrLn ("· Give a name for example " <> show i)
putStrLn "The name should not contain spaces and begin with a lowercase letter."
putStr "Input: "
ln <- getLine
outputStrLn ""
outputStrLn ("· Give a name for example " <> show i)
outputStrLn "The name should begin with a lowercase letter and should not contain any spaces."
ln <- getInputLine' "Input: "
if validateExampleName ln then pure ln else readExample i

-- Template
Expand All @@ -170,25 +171,25 @@ data Template = MkTemplate
}
deriving (Show)

readTemplate :: IO Template
readTemplate :: ToolM Template
readTemplate = do
putStrLn "This tool helps you create the scaffolding for a new error message on the error-message-index."
putStrLn "You can leave any of the text fields blank and fill them in by hand later."
putStrLn ""
outputStrLn "This tool helps you create the scaffolding for a new error message on the error-message-index."
outputStrLn "You can leave any of the text fields blank and fill them in by hand later."
outputStrLn ""
sys <- readTool
putStrLn ""
outputStrLn ""
code <- readCode
putStrLn ""
outputStrLn ""
title <- readTitle
putStrLn ""
outputStrLn ""
summary <- readSummary
putStrLn ""
outputStrLn ""
severity <- readSeverity
putStrLn ""
outputStrLn ""
warningflag <- readWarningFlag severity
putStrLn ""
outputStrLn ""
version <- readVersion
putStrLn ""
outputStrLn ""
examples <- readExamples sys
pure (MkTemplate sys code title summary severity warningflag version examples)

Expand All @@ -197,12 +198,12 @@ readTemplate = do
-------------------------------------------------------------------------------

createFiles :: Template -> IO ()
createFiles tmpl = do
createFiles tmpl = liftIO $ do
putStrLn ""
putStrLn "· Creating scaffolding..."

-- Create the new directory "messages/XXX-NNNNNN/" and "messages/XXX-NNNNNN/index.md"
let message_dir = "messages" </> case tool tmpl of { GHC -> "GHC-"; GHCup -> "GHCup-"; Stack -> "S-" } ++ code tmpl
let message_dir = "messages" </> case tool tmpl of { GHC -> "GHC-"; GHCup -> "GHCup-"; Stack -> "S-"; Cabal -> "Cabal-" } ++ code tmpl
createDirectoryIfMissing True message_dir
let index_filename = message_dir </> "index.md"
let toplvl_index =
Expand Down Expand Up @@ -265,5 +266,5 @@ createFiles tmpl = do
main :: IO ()
main = do
hSetBuffering stdout NoBuffering
tmpl <- readTemplate
tmpl <- runInputT defaultSettings readTemplate
createFiles tmpl
9 changes: 9 additions & 0 deletions message-index/messages/GHC-06201/example1/after/A.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module A where

class Calculator a where
add :: a -> a -> a
multiply :: a -> a -> a

instance Calculator Int where
add a b = a + b
multiply a b = a * b
8 changes: 8 additions & 0 deletions message-index/messages/GHC-06201/example1/before/A.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module A where

class Calculator a where
add :: a -> a -> a
multiply :: a -> a -> a

instance Calculator Int where
add a b = a + b
20 changes: 20 additions & 0 deletions message-index/messages/GHC-06201/example1/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
title: No explicit implementation for method instance
---

## Error Message

```
A.hs:7:10: warning: [GHC-06201] [-Wmissing-methods]
• No explicit implementation for
‘multiply’
• In the instance declaration for ‘Calculator Int’
|
7 | instance Calculator Int where
```

## Explanation

The type class `Calculator` requires you to implement two methods: `add` and `multiply`.
However, the example instance `instance Calculator Int` only implements the method `add` and not `multiply`
To fix this, implement the method `multiply`!
10 changes: 10 additions & 0 deletions message-index/messages/GHC-06201/example2/after/A.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module A where

data Box t = SomeBox t

instance Functor Box where
fmap f (SomeBox a) = SomeBox (f a)

instance Applicative Box where
pure a = SomeBox a
SomeBox f <*> SomeBox a = SomeBox (f a)
9 changes: 9 additions & 0 deletions message-index/messages/GHC-06201/example2/before/A.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module A where

data Box t = SomeBox t

instance Functor Box where
fmap f (SomeBox a) = SomeBox (f a)

instance Applicative Box where
pure a = SomeBox a
26 changes: 26 additions & 0 deletions message-index/messages/GHC-06201/example2/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: No explicit implementation for method instance 2
---

## Error Message

```
A.hs:8:10: warning: [GHC-06201] [-Wmissing-methods]
• No explicit implementation for
either ‘<*>’ or ‘liftA2’
• In the instance declaration for ‘Applicative Box’
|
8 | instance Applicative Box where
| ^^^^^^^^^^^^^^^
```

## Explanation

The type class `Applicative` requires you to implement at least two methods:

* `pure`, and
* `liftA2` or `multiply` (can also be both).

Such `or` constraints can be expressed via the [`{-# MINIMAL #-}`](https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/pragmas.html#minimal-pragma) pragma.

To fix this, either implement the method `liftA2` or `<*>`. For this example, we implemented `<*>`, but either or both is fine, too.
9 changes: 9 additions & 0 deletions message-index/messages/GHC-06201/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
title: Missing method in type class instance
summary: A required method is missing from the instance declaration.
severity: warning
flag: -Wmissing-methods
introduced: 9.6.1
---

This warning means that a type class instance is missing some required method implementations.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{-# LANGUAGE DerivingStrategies #-}
module IllegalDerivingStrategy where

newtype Year = MkYear Int
deriving newtype Show
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module IllegalDerivingStrategy where

newtype Year = MkYear Int
deriving newtype Show
Loading

0 comments on commit ce50ee6

Please sign in to comment.