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

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
else ptext (sLit "parse error on input") <+> quotes (text token)
$$ ppWhen (not th_enabled && token == "$") -- #7396
(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
th_enabled = xopt Opt_TemplateHaskell dflags
......
......@@ -1577,6 +1577,37 @@ exp10 :: { LHsExpr RdrName }
-- hdaume: core annotation
| 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 }
: ';' { True }
| {- empty -} { False }
......@@ -2377,6 +2408,14 @@ hintMultiWayIf span = do
unless mwiEnabled $ parseErrorSDoc span $
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
hintExplicitForall :: SrcSpan -> P ()
hintExplicitForall span = do
......
......@@ -1089,10 +1089,22 @@ mk_dict_err fam_envs ctxt (ct, (matches, unifiers, safe_haskell))
, nest 19 (ptext (sLit "to") <+> quotes (ppr ty2)) ]
-- The nesting makes the types line up
| 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
= 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
DerivOrigin -> [drv_fix]
DerivOriginDC {} -> [drv_fix]
......
annfail08.hs:9:1:
No instance for (Data.Data.Data (a0 -> a0))
(maybe you haven't applied enough arguments to a function?)
arising from an annotation
In the annotation: {-# ANN f (id + 1) #-}
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) #-}
drvfail007.hs:4:38:
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’)
Possible fix:
use a standalone 'deriving instance' declaration,
......
<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
......@@ -27,7 +27,9 @@
In an equation for ‘c’: c (C2 x) = True
../../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 an equation for ‘d’: d = 1
......@@ -133,7 +135,9 @@
In the first argument of ‘c’, namely ‘(C2 True)’
In the first argument of ‘print’, namely ‘(c (C2 True))’
*** 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 an equation for ‘d’: d = 1
(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:
No instance for (HasSeq (IO a -> t0 -> IO b))
(maybe you haven't applied enough arguments to a function?)
arising from a do statement
The type variable ‘t0’ is ambiguous
Relevant bindings include
......@@ -24,6 +25,7 @@ rebindable6.hs:106:17:
rebindable6.hs:107:17:
No instance for (HasFail ([Prelude.Char] -> t1))
(maybe you haven't applied enough arguments to a function?)
arising from a do statement
The type variable ‘t1’ is ambiguous
Note: there is a potential instance available:
......@@ -42,6 +44,7 @@ rebindable6.hs:107:17:
rebindable6.hs:108:17:
No instance for (HasReturn (b -> t1))
(maybe you haven't applied enough arguments to a function?)
arising from a use of ‘return’
The type variable ‘t1’ is ambiguous
Relevant bindings include
......
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 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