Commit bc2289e1 authored by MikeIzbicki's avatar MikeIzbicki Committed by Austin Seipp
Browse files

ghc generates more user-friendly error messages

Test Plan: Compiled ghc fine.  Opened ghci and fed it invalid code.  It gave the improved error messages in response.

Reviewers: austin

Subscribers: thomie, simonpj, spacekitteh, rwbarton, simonmar, carter

Differential Revision: https://phabricator.haskell.org/D201
parent d87fa343
...@@ -2144,6 +2144,8 @@ srcParseErr dflags buf len ...@@ -2144,6 +2144,8 @@ srcParseErr dflags buf len
else ptext (sLit "parse error on input") <+> quotes (text token) else ptext (sLit "parse error on input") <+> quotes (text token)
$$ ppWhen (not th_enabled && token == "$") -- #7396 $$ ppWhen (not th_enabled && token == "$") -- #7396
(text "Perhaps you intended to use TemplateHaskell") (text "Perhaps you intended to use TemplateHaskell")
$$ ppWhen (token == "<-")
(text "Perhaps this statement should be within a 'do' block?")
where token = lexemeToString (offsetBytes (-len) buf) len where token = lexemeToString (offsetBytes (-len) buf) len
th_enabled = xopt Opt_TemplateHaskell dflags th_enabled = xopt Opt_TemplateHaskell dflags
......
...@@ -1577,6 +1577,37 @@ exp10 :: { LHsExpr RdrName } ...@@ -1577,6 +1577,37 @@ exp10 :: { LHsExpr RdrName }
-- hdaume: core annotation -- hdaume: core annotation
| fexp { $1 } | fexp { $1 }
-- parsing error messages go below here
| '\\' apat apats opt_asig '->' {% parseErrorSDoc (combineLocs $1 $5) $ text
"parse error in lambda: no expression after '->'"
}
| '\\' {% parseErrorSDoc (getLoc $1) $ text
"parse error: naked lambda expression '\'"
}
| 'let' binds 'in' {% parseErrorSDoc (combineLocs $1 $2) $ text
"parse error in let binding: missing expression after 'in'"
}
| 'let' binds {% parseErrorSDoc (combineLocs $1 $2) $ text
"parse error in let binding: missing required 'in'"
}
| 'let' {% parseErrorSDoc (getLoc $1) $ text
"parse error: naked let binding"
}
| 'if' exp optSemi 'then' exp optSemi 'else' {% hintIf (combineLocs $1 $5) "else clause empty" }
| 'if' exp optSemi 'then' exp optSemi {% hintIf (combineLocs $1 $5) "missing required else clause" }
| 'if' exp optSemi 'then' {% hintIf (combineLocs $1 $2) "then clause empty" }
| 'if' exp optSemi {% hintIf (combineLocs $1 $2) "missing required then and else clauses" }
| 'if' {% hintIf (getLoc $1) "naked if statement" }
| 'case' exp 'of' {% parseErrorSDoc (combineLocs $1 $2) $ text
"parse error in case statement: missing list after '->'"
}
| 'case' exp {% parseErrorSDoc (combineLocs $1 $2) $ text
"parse error in case statement: missing required 'of'"
}
| 'case' {% parseErrorSDoc (getLoc $1) $ text
"parse error: naked case statement"
}
optSemi :: { Bool } optSemi :: { Bool }
: ';' { True } : ';' { True }
| {- empty -} { False } | {- empty -} { False }
...@@ -2377,6 +2408,14 @@ hintMultiWayIf span = do ...@@ -2377,6 +2408,14 @@ hintMultiWayIf span = do
unless mwiEnabled $ parseErrorSDoc span $ unless mwiEnabled $ parseErrorSDoc span $
text "Multi-way if-expressions need MultiWayIf turned on" text "Multi-way if-expressions need MultiWayIf turned on"
-- Hint about if usage for beginners
hintIf :: SrcSpan -> String -> P (LHsExpr RdrName)
hintIf span msg = do
mwiEnabled <- liftM ((Opt_MultiWayIf `xopt`) . dflags) getPState
if mwiEnabled
then parseErrorSDoc span $ text $ "parse error in if statement"
else parseErrorSDoc span $ text $ "parse error in if statement: "++msg
-- Hint about explicit-forall, assuming UnicodeSyntax is on -- Hint about explicit-forall, assuming UnicodeSyntax is on
hintExplicitForall :: SrcSpan -> P () hintExplicitForall :: SrcSpan -> P ()
hintExplicitForall span = do hintExplicitForall span = do
......
...@@ -1089,10 +1089,22 @@ mk_dict_err fam_envs ctxt (ct, (matches, unifiers, safe_haskell)) ...@@ -1089,10 +1089,22 @@ mk_dict_err fam_envs ctxt (ct, (matches, unifiers, safe_haskell))
, nest 19 (ptext (sLit "to") <+> quotes (ppr ty2)) ] , nest 19 (ptext (sLit "to") <+> quotes (ppr ty2)) ]
-- The nesting makes the types line up -- The nesting makes the types line up
| null givens && null matches | null givens && null matches
= ptext (sLit "No instance for") <+> pprParendType pred = ptext (sLit "No instance for")
<+> pprParendType pred
$$ if type_has_arrow pred
then nest 2 $ ptext (sLit "(maybe you haven't applied enough arguments to a function?)")
else empty
| otherwise | otherwise
= ptext (sLit "Could not deduce") <+> pprParendType pred = ptext (sLit "Could not deduce") <+> pprParendType pred
type_has_arrow (TyVarTy _) = False
type_has_arrow (AppTy t1 t2) = type_has_arrow t1 || type_has_arrow t2
type_has_arrow (TyConApp _ ts) = or $ map type_has_arrow ts
type_has_arrow (FunTy _ _) = True
type_has_arrow (ForAllTy _ t) = type_has_arrow t
type_has_arrow (LitTy _) = False
drv_fixes = case orig of drv_fixes = case orig of
DerivOrigin -> [drv_fix] DerivOrigin -> [drv_fix]
DerivOriginDC {} -> [drv_fix] DerivOriginDC {} -> [drv_fix]
......
annfail08.hs:9:1: annfail08.hs:9:1:
No instance for (Data.Data.Data (a0 -> a0)) No instance for (Data.Data.Data (a0 -> a0))
(maybe you haven't applied enough arguments to a function?)
arising from an annotation arising from an annotation
In the annotation: {-# ANN f (id + 1) #-} In the annotation: {-# ANN f (id + 1) #-}
annfail08.hs:9:15: annfail08.hs:9:15:
No instance for (Num (a0 -> a0)) arising from a use of ‘+’ No instance for (Num (a0 -> a0))
(maybe you haven't applied enough arguments to a function?)
arising from a use of ‘+’
In the annotation: {-# ANN f (id + 1) #-} In the annotation: {-# ANN f (id + 1) #-}
drvfail007.hs:4:38: drvfail007.hs:4:38:
No instance for (Eq (Int -> Int)) No instance for (Eq (Int -> Int))
(maybe you haven't applied enough arguments to a function?)
arising from the first field of ‘Foo’ (type ‘Int -> Int’) arising from the first field of ‘Foo’ (type ‘Int -> Int’)
Possible fix: Possible fix:
use a standalone 'deriving instance' declaration, use a standalone 'deriving instance' declaration,
......
<interactive>:5:1: <interactive>:5:1:
No instance for (Show (t -> t1)) arising from a use of ‘print’ No instance for (Show (t -> t1))
(maybe you haven't applied enough arguments to a function?)
arising from a use of ‘print’
In a stmt of an interactive GHCi command: print it In a stmt of an interactive GHCi command: print it
...@@ -27,7 +27,9 @@ ...@@ -27,7 +27,9 @@
In an equation for ‘c’: c (C2 x) = True In an equation for ‘c’: c (C2 x) = True
../../typecheck/should_run/Defer01.hs:28:5: Warning: ../../typecheck/should_run/Defer01.hs:28:5: Warning:
No instance for (Num (a -> a)) arising from the literal ‘1’ No instance for (Num (a -> a))
(maybe you haven't applied enough arguments to a function?)
arising from the literal ‘1’
In the expression: 1 In the expression: 1
In an equation for ‘d’: d = 1 In an equation for ‘d’: d = 1
...@@ -133,7 +135,9 @@ ...@@ -133,7 +135,9 @@
In the first argument of ‘c’, namely ‘(C2 True)’ In the first argument of ‘c’, namely ‘(C2 True)’
In the first argument of ‘print’, namely ‘(c (C2 True))’ In the first argument of ‘print’, namely ‘(c (C2 True))’
*** Exception: ../../typecheck/should_run/Defer01.hs:28:5: *** Exception: ../../typecheck/should_run/Defer01.hs:28:5:
No instance for (Num (a -> a)) arising from the literal ‘1’ No instance for (Num (a -> a))
(maybe you haven't applied enough arguments to a function?)
arising from the literal ‘1’
In the expression: 1 In the expression: 1
In an equation for ‘d’: d = 1 In an equation for ‘d’: d = 1
(deferred type error) (deferred type error)
......
mdofail005.hs:11:14: parse error on input ‘<-’ mdofail005.hs:11:14:
parse error on input ‘<-’
Perhaps this statement should be within a 'do' block?
ParserNoLambdaCase.hs:3:6: parse error on input ‘case’ ParserNoLambdaCase.hs:3:5: parse error: naked lambda expression ''
readFail020.hs:3:16: parse error on input ‘}’ readFail020.hs:3:5:
parse error in let binding: missing required 'in'
readFail040.hs:7:11: parse error on input ‘<-’ readFail040.hs:7:11:
parse error on input ‘<-’
Perhaps this statement should be within a 'do' block?
rebindable6.hs:106:17: rebindable6.hs:106:17:
No instance for (HasSeq (IO a -> t0 -> IO b)) No instance for (HasSeq (IO a -> t0 -> IO b))
(maybe you haven't applied enough arguments to a function?)
arising from a do statement arising from a do statement
The type variable ‘t0’ is ambiguous The type variable ‘t0’ is ambiguous
Relevant bindings include Relevant bindings include
...@@ -24,6 +25,7 @@ rebindable6.hs:106:17: ...@@ -24,6 +25,7 @@ rebindable6.hs:106:17:
rebindable6.hs:107:17: rebindable6.hs:107:17:
No instance for (HasFail ([Prelude.Char] -> t1)) No instance for (HasFail ([Prelude.Char] -> t1))
(maybe you haven't applied enough arguments to a function?)
arising from a do statement arising from a do statement
The type variable ‘t1’ is ambiguous The type variable ‘t1’ is ambiguous
Note: there is a potential instance available: Note: there is a potential instance available:
...@@ -42,6 +44,7 @@ rebindable6.hs:107:17: ...@@ -42,6 +44,7 @@ rebindable6.hs:107:17:
rebindable6.hs:108:17: rebindable6.hs:108:17:
No instance for (HasReturn (b -> t1)) No instance for (HasReturn (b -> t1))
(maybe you haven't applied enough arguments to a function?)
arising from a use of ‘return’ arising from a use of ‘return’
The type variable ‘t1’ is ambiguous The type variable ‘t1’ is ambiguous
Relevant bindings include Relevant bindings include
......
T2846b.hs:5:5: T2846b.hs:5:5:
No instance for (Show (Num a0 => a0)) arising from a use of ‘show’ No instance for (Show (Num a0 => a0))
(maybe you haven't applied enough arguments to a function?)
arising from a use of ‘show’
In the expression: show ([1, 2, 3] :: [Num a => a]) In the expression: show ([1, 2, 3] :: [Num a => a])
In an equation for ‘f’: f = show ([1, 2, 3] :: [Num a => a]) In an equation for ‘f’: f = show ([1, 2, 3] :: [Num a => a])
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment