@@ -1,19 +1,6 @@
1−-----------------------------------------------------------------------------
3−-- Module : Language.PureScript.Error
4−-- Copyright : (c) 2013-15 Phil Freeman, (c) 2014-15 Gary Burgess
5−-- License : MIT (http://opensource.org/licenses/MIT)
7−-- Maintainer : Phil Freeman <paf31@cantab.net>
8−-- Stability : experimental
13−-----------------------------------------------------------------------------
15{-# LANGUAGE GeneralizedNewtypeDeriving #-}
1{-# LANGUAGE GeneralizedNewtypeDeriving #-}
16{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE RecordWildCards #-}
17{-# LANGUAGE MultiParamTypeClasses #-}
4{-# LANGUAGE MultiParamTypeClasses #-}
19module Language.PureScript.Errors where
6module Language.PureScript.Errors where
@@ -24,7 +11,6 @@ import Prelude.Compat
24import Data.Ord (comparing)
11import Data.Ord (comparing)
25import Data.Either (lefts, rights)
12import Data.Either (lefts, rights)
26import Data.List (intercalate, transpose, nub, nubBy, sortBy)
13import Data.List (intercalate, transpose, nub, nubBy, sortBy)
27−import Data.Function (on)
28import Data.Foldable (fold)
14import Data.Foldable (fold)
30import qualified Data.Map as M
16import qualified Data.Map as M
@@ -33,7 +19,7 @@ import Control.Monad
33import Control.Monad.Writer
19import Control.Monad.Writer
34import Control.Monad.Error.Class (MonadError(..))
20import Control.Monad.Error.Class (MonadError(..))
35import Control.Monad.Trans.State.Lazy
21import Control.Monad.Trans.State.Lazy
36−import Control.Arrow (first, (&&&))
22+import Control.Arrow ((&&&))
38import Language.PureScript.Crash
24import Language.PureScript.Crash
39import Language.PureScript.AST
25import Language.PureScript.AST
@@ -143,6 +129,15 @@ data SimpleErrorMessage
143 | UnusedDctorImport ProperName
129 | UnusedDctorImport ProperName
144 | UnusedDctorExplicitImport ProperName [ProperName]
130 | UnusedDctorExplicitImport ProperName [ProperName]
145 | DeprecatedQualifiedSyntax ModuleName ModuleName
131 | DeprecatedQualifiedSyntax ModuleName ModuleName
132+ | DeprecatedClassImport ModuleName ProperName
133+ | DeprecatedClassExport ProperName
134+ | RedundantUnqualifiedImport ModuleName ImportDeclarationType
135+ | DuplicateSelectiveImport ModuleName
136+ | DuplicateImport ModuleName ImportDeclarationType (Maybe ModuleName)
137+ | DuplicateImportRef String
138+ | DuplicateExportRef String
139+ | IntOutOfRange Integer String Integer Integer
140+ | RedundantEmptyHidingImport ModuleName
146 deriving (Show)
141 deriving (Show)
148-- | Error message hints, providing more detailed information about failure.
143-- | Error message hints, providing more detailed information about failure.
@@ -278,6 +273,15 @@ errorCode em = case unwrapErrorMessage em of
278 UnusedDctorImport{} -> "UnusedDctorImport"
273 UnusedDctorImport{} -> "UnusedDctorImport"
279 UnusedDctorExplicitImport{} -> "UnusedDctorExplicitImport"
274 UnusedDctorExplicitImport{} -> "UnusedDctorExplicitImport"
280 DeprecatedQualifiedSyntax{} -> "DeprecatedQualifiedSyntax"
275 DeprecatedQualifiedSyntax{} -> "DeprecatedQualifiedSyntax"
276+ DeprecatedClassImport{} -> "DeprecatedClassImport"
277+ DeprecatedClassExport{} -> "DeprecatedClassExport"
278+ RedundantUnqualifiedImport{} -> "RedundantUnqualifiedImport"
279+ DuplicateSelectiveImport{} -> "DuplicateSelectiveImport"
280+ DuplicateImport{} -> "DuplicateImport"
281+ DuplicateImportRef{} -> "DuplicateImportRef"
282+ DuplicateExportRef{} -> "DuplicateExportRef"
283+ IntOutOfRange{} -> "IntOutOfRange"
284+ RedundantEmptyHidingImport{} -> "RedundantEmptyHidingImport"
@@ -311,11 +315,16 @@ onErrorMessages f = MultipleErrors . map f . runMultipleErrors
311addHint :: ErrorMessageHint -> MultipleErrors -> MultipleErrors
315addHint :: ErrorMessageHint -> MultipleErrors -> MultipleErrors
312addHint hint = onErrorMessages $ \(ErrorMessage hints se) -> ErrorMessage (hint : hints) se
316addHint hint = onErrorMessages $ \(ErrorMessage hints se) -> ErrorMessage (hint : hints) se
314−-- | The various types of things which might need to be relabelled in errors messages.
315−data LabelType = TypeLabel | SkolemLabel String deriving (Show, Read, Eq, Ord)
317-- | A map from rigid type variable name/unknown variable pairs to new variables.
318-- | A map from rigid type variable name/unknown variable pairs to new variables.
318−type UnknownMap = M.Map (LabelType, Int) Int
319+data TypeMap = TypeMap
320+ { umSkolemMap :: M.Map Int (String, Int, Maybe SourceSpan)
321+ , umNextSkolem :: Int
322+ , umUnknownMap :: M.Map Int Int
323+ , umNextUnknown :: Int
326+defaultUnknownMap :: TypeMap
327+defaultUnknownMap = TypeMap M.empty 0 M.empty 0
320-- | How critical the issue is
329-- | How critical the issue is
321data Level = Error | Warning deriving Show
330data Level = Error | Warning deriving Show
@@ -326,48 +335,72 @@ data Level = Error | Warning deriving Show
326unwrapErrorMessage :: ErrorMessage -> SimpleErrorMessage
335unwrapErrorMessage :: ErrorMessage -> SimpleErrorMessage
327unwrapErrorMessage (ErrorMessage _ se) = se
336unwrapErrorMessage (ErrorMessage _ se) = se
329−replaceUnknowns :: Type -> State UnknownMap Type
338+replaceUnknowns :: Type -> State TypeMap Type
330replaceUnknowns = everywhereOnTypesM replaceTypes
339replaceUnknowns = everywhereOnTypesM replaceTypes
332− lookupTable :: (LabelType, Int) -> UnknownMap -> (Int, UnknownMap)
333− lookupTable x m = case M.lookup x m of
334− Nothing -> let i = length (filter (on (==) fst x) (M.keys m)) in (i, M.insert x i m)
337− replaceTypes :: Type -> State UnknownMap Type
341+ replaceTypes :: Type -> State TypeMap Type
338− replaceTypes (TUnknown u) = state $ first TUnknown . lookupTable (TypeLabel, u)
342+ replaceTypes (TUnknown u) = do
344+ case M.lookup u (umUnknownMap m) of
346+ let u' = umNextUnknown m
347+ put $ m { umUnknownMap = M.insert u u' (umUnknownMap m), umNextUnknown = u' + 1 }
348+ return (TUnknown u')
349+ Just u' -> return (TUnknown u')
339− replaceTypes (Skolem name s sko) = state $ first (flip (Skolem name) sko) . lookupTable (SkolemLabel name, s)
350+ replaceTypes (Skolem name s sko ss) = do
352+ case M.lookup s (umSkolemMap m) of
354+ let s' = umNextSkolem m
355+ put $ m { umSkolemMap = M.insert s (name, s', ss) (umSkolemMap m), umNextSkolem = s' + 1 }
356+ return (Skolem name s' sko ss)
357+ Just (_, s', _) -> return (Skolem name s' sko ss)
340 replaceTypes other = return other
358 replaceTypes other = return other
342onTypesInErrorMessageM :: (Applicative m) => (Type -> m Type) -> ErrorMessage -> m ErrorMessage
360onTypesInErrorMessageM :: (Applicative m) => (Type -> m Type) -> ErrorMessage -> m ErrorMessage
343onTypesInErrorMessageM f (ErrorMessage hints simple) = ErrorMessage <$> traverse gHint hints <*> gSimple simple
361onTypesInErrorMessageM f (ErrorMessage hints simple) = ErrorMessage <$> traverse gHint hints <*> gSimple simple
345− gSimple (InfiniteType t) = InfiniteType <$> f t
363+ gSimple (InfiniteType t) = InfiniteType <$> f t
346− gSimple (TypesDoNotUnify t1 t2) = TypesDoNotUnify <$> f t1 <*> f t2
364+ gSimple (TypesDoNotUnify t1 t2) = TypesDoNotUnify <$> f t1 <*> f t2
347− gSimple (ConstrainedTypeUnified t1 t2) = ConstrainedTypeUnified <$> f t1 <*> f t2
365+ gSimple (ConstrainedTypeUnified t1 t2) = ConstrainedTypeUnified <$> f t1 <*> f t2
348− gSimple (ExprDoesNotHaveType e t) = ExprDoesNotHaveType e <$> f t
366+ gSimple (ExprDoesNotHaveType e t) = ExprDoesNotHaveType e <$> f t
349− gSimple (CannotApplyFunction t e) = CannotApplyFunction <$> f t <*> pure e
367+ gSimple (CannotApplyFunction t e) = CannotApplyFunction <$> f t <*> pure e
350− gSimple (InvalidInstanceHead t) = InvalidInstanceHead <$> f t
368+ gSimple (InvalidInstanceHead t) = InvalidInstanceHead <$> f t
369+ gSimple (NoInstanceFound cl ts) = NoInstanceFound cl <$> traverse f ts
370+ gSimple (OverlappingInstances cl ts insts) = OverlappingInstances cl <$> traverse f ts <*> pure insts
371+ gSimple (PossiblyInfiniteInstance cl ts) = PossiblyInfiniteInstance cl <$> traverse f ts
372+ gSimple (CannotDerive cl ts) = CannotDerive cl <$> traverse f ts
373+ gSimple (ExpectedType ty k) = ExpectedType <$> f ty <*> pure k
374+ gSimple (OrphanInstance nm cl ts) = OrphanInstance nm cl <$> traverse f ts
375+ gSimple (WildcardInferredType ty) = WildcardInferredType <$> f ty
376+ gSimple (MissingTypeDeclaration nm ty) = MissingTypeDeclaration nm <$> f ty
351− gSimple other = pure other
378+ gSimple other = pure other
352− gHint (ErrorInSubsumption t1 t2) = ErrorInSubsumption <$> f t1 <*> f t2
380+ gHint (ErrorInSubsumption t1 t2) = ErrorInSubsumption <$> f t1 <*> f t2
353− gHint (ErrorUnifyingTypes t1 t2) = ErrorUnifyingTypes <$> f t1 <*> f t2
381+ gHint (ErrorUnifyingTypes t1 t2) = ErrorUnifyingTypes <$> f t1 <*> f t2
354− gHint (ErrorCheckingType e t) = ErrorCheckingType e <$> f t
382+ gHint (ErrorCheckingType e t) = ErrorCheckingType e <$> f t
355− gHint (ErrorCheckingKind t) = ErrorCheckingKind <$> f t
383+ gHint (ErrorCheckingKind t) = ErrorCheckingKind <$> f t
356− gHint (ErrorInApplication e1 t1 e2) = ErrorInApplication e1 <$> f t1 <*> pure e2
384+ gHint (ErrorInApplication e1 t1 e2) = ErrorInApplication e1 <$> f t1 <*> pure e2
385+ gHint (ErrorInInstance cl ts) = ErrorInInstance cl <$> traverse f ts
357− gHint other = pure other
386+ gHint other = pure other
360-- Pretty print a single error, simplifying if necessary
389-- Pretty print a single error, simplifying if necessary
362−prettyPrintSingleError :: Bool -> Level -> ErrorMessage -> State UnknownMap Box.Box
391+prettyPrintSingleError :: Bool -> Level -> ErrorMessage -> State TypeMap Box.Box
392+prettyPrintSingleError full level e = do
363−prettyPrintSingleError full level e = prettyPrintErrorMessage <$> onTypesInErrorMessageM replaceUnknowns (if full then e else simplifyErrorMessage e)
393+ em <- onTypesInErrorMessageM replaceUnknowns (if full then e else simplifyErrorMessage e)
395+ return (prettyPrintErrorMessage um em)
366 -- Pretty print an ErrorMessage
398 -- Pretty print an ErrorMessage
367− prettyPrintErrorMessage :: ErrorMessage -> Box.Box
399+ prettyPrintErrorMessage :: TypeMap -> ErrorMessage -> Box.Box
368− prettyPrintErrorMessage (ErrorMessage hints simple) =
400+ prettyPrintErrorMessage typeMap (ErrorMessage hints simple) =
370 [ foldr renderHint (indent (renderSimpleErrorMessage simple)) hints
402 [ foldr renderHint (indent (renderSimpleErrorMessage simple)) hints
403+ , Box.moveDown 1 typeInformation
371 , Box.moveDown 1 $ paras [ line $ "See " ++ wikiUri ++ " for more information, "
404 , Box.moveDown 1 $ paras [ line $ "See " ++ wikiUri ++ " for more information, "
372 , line $ "or to contribute content related to this " ++ levelText ++ "."
405 , line $ "or to contribute content related to this " ++ levelText ++ "."
@@ -376,6 +409,23 @@ prettyPrintSingleError full level e = prettyPrintErrorMessage <$> onTypesInError
376 wikiUri :: String
409 wikiUri :: String
377 wikiUri = "https://github.com/purescript/purescript/wiki/Error-Code-" ++ errorCode e
410 wikiUri = "https://github.com/purescript/purescript/wiki/Error-Code-" ++ errorCode e
412+ typeInformation :: Box.Box
413+ typeInformation | not (null types) = Box.hsep 1 Box.left [ line "where", paras types]
414+ | otherwise = Box.emptyBox 0 0
417+ types = map skolemInfo (M.elems (umSkolemMap typeMap)) ++
418+ map unknownInfo (M.elems (umUnknownMap typeMap))
420+ skolemInfo :: (String, Int, Maybe SourceSpan) -> Box.Box
421+ skolemInfo (name, s, ss) =
423+ line (name ++ show s ++ " is a rigid type variable")
424+ : foldMap (return . line . (" bound at " ++) . displayStartEndPos) ss
426+ unknownInfo :: Int -> Box.Box
427+ unknownInfo u = line $ "_" ++ show u ++ " is an unknown type"
379 renderSimpleErrorMessage :: SimpleErrorMessage -> Box.Box
429 renderSimpleErrorMessage :: SimpleErrorMessage -> Box.Box
380 renderSimpleErrorMessage (CannotGetFileInfo path) =
430 renderSimpleErrorMessage (CannotGetFileInfo path) =
381 paras [ line "Unable to read file info: "
431 paras [ line "Unable to read file info: "
@@ -576,7 +626,16 @@ prettyPrintSingleError full level e = prettyPrintErrorMessage <$> onTypesInError
576 , indent $ Box.hsep 1 Box.left [ line (showQualified runProperName nm)
626 , indent $ Box.hsep 1 Box.left [ line (showQualified runProperName nm)
577 , Box.vcat Box.left (map typeAtomAsBox ts)
627 , Box.vcat Box.left (map typeAtomAsBox ts)
629+ , paras [ line "The instance head contains unknown type variables. Consider adding a type annotation."
630+ | any containsUnknowns ts
634+ containsUnknowns :: Type -> Bool
635+ containsUnknowns = everythingOnTypes (||) go
637+ go TUnknown{} = True
580 renderSimpleErrorMessage (PossiblyInfiniteInstance nm ts) =
639 renderSimpleErrorMessage (PossiblyInfiniteInstance nm ts) =
581 paras [ line "Type class instance for"
640 paras [ line "Type class instance for"
582 , indent $ Box.hsep 1 Box.left [ line (showQualified runProperName nm)
641 , indent $ Box.hsep 1 Box.left [ line (showQualified runProperName nm)
@@ -715,8 +774,50 @@ prettyPrintSingleError full level e = prettyPrintErrorMessage <$> onTypesInError
715 , indent $ paras $ map (line .runProperName) names ]
774 , indent $ paras $ map (line .runProperName) names ]
717 renderSimpleErrorMessage (DeprecatedQualifiedSyntax name qualName) =
776 renderSimpleErrorMessage (DeprecatedQualifiedSyntax name qualName) =
777+ paras [ line $ "Import uses the deprecated 'qualified' syntax:"
778+ , indent $ line $ "import qualified " ++ runModuleName name ++ " as " ++ runModuleName qualName
779+ , line "Should instead use the form:"
718− paras [ line $ "The import of type " ++ runModuleName name ++ " as " ++ runModuleName qualName ++ " uses the deprecated 'import qualified' syntax."
780+ , indent $ line $ "import " ++ runModuleName name ++ " as " ++ runModuleName qualName
781+ , line $ "The deprecated syntax will be removed in PureScript 0.9."
784+ renderSimpleErrorMessage (DeprecatedClassImport mn name) =
785+ paras [ line $ "Class import from " ++ runModuleName mn ++ " uses deprecated syntax that omits the 'class' keyword:"
786+ , indent $ line $ runProperName name
787+ , line "Should instead use the form:"
788+ , indent $ line $ "class " ++ runProperName name
719− , line $ "This syntax form will be removed in PureScript 0.9." ]
789+ , line $ "The deprecated syntax will be removed in PureScript 0.9."
792+ renderSimpleErrorMessage (DeprecatedClassExport name) =
793+ paras [ line $ "Class export uses deprecated syntax that omits the 'class' keyword:"
794+ , indent $ line $ runProperName name
795+ , line "Should instead use the form:"
796+ , indent $ line $ "class " ++ runProperName name
797+ , line $ "The deprecated syntax will be removed in PureScript 0.9."
800+ renderSimpleErrorMessage (RedundantUnqualifiedImport name imp) =
801+ line $ "Import of " ++ prettyPrintImport name imp Nothing ++ " is redundant due to a whole-module import"
803+ renderSimpleErrorMessage (DuplicateSelectiveImport name) =
804+ line $ "There is an existing import of " ++ runModuleName name ++ ", consider merging the import lists"
806+ renderSimpleErrorMessage (DuplicateImport name imp qual) =
807+ line $ "Duplicate import of " ++ prettyPrintImport name imp qual
809+ renderSimpleErrorMessage (DuplicateImportRef ref) =
810+ line $ "Import list contains multiple references to " ++ ref
812+ renderSimpleErrorMessage (DuplicateExportRef ref) =
813+ line $ "Export list contains multiple references to " ++ ref
815+ renderSimpleErrorMessage (IntOutOfRange value backend lo hi) =
816+ paras [ line $ "Integer value " ++ show value ++ " is out of range for the " ++ backend ++ " backend."
817+ , line $ "Acceptable values fall within the range " ++ show lo ++ " to " ++ show hi ++ " (inclusive)." ]
819+ renderSimpleErrorMessage (RedundantEmptyHidingImport mn) =
820+ line $ "The import for module " ++ runModuleName mn ++ " is redundant as all members have been explicitly hidden."
721 renderHint :: ErrorMessageHint -> Box.Box -> Box.Box
822 renderHint :: ErrorMessageHint -> Box.Box -> Box.Box
722 renderHint (ErrorUnifyingTypes t1 t2) detail =
823 renderHint (ErrorUnifyingTypes t1 t2) detail =
@@ -849,11 +950,25 @@ prettyPrintSingleError full level e = prettyPrintErrorMessage <$> onTypesInError
849 -- Pretty print and export declaration
950 -- Pretty print and export declaration
850 prettyPrintExport :: DeclarationRef -> String
951 prettyPrintExport :: DeclarationRef -> String
851 prettyPrintExport (TypeRef pn _) = runProperName pn
952 prettyPrintExport (TypeRef pn _) = runProperName pn
953+ prettyPrintExport ref = prettyPrintRef ref
955+ prettyPrintRef :: DeclarationRef -> String
956+ prettyPrintRef (TypeRef pn Nothing) = runProperName pn ++ "(..)"
957+ prettyPrintRef (TypeRef pn (Just dctors)) = runProperName pn ++ "(" ++ intercalate ", " (map runProperName dctors) ++ ")"
852− prettyPrintExport (ValueRef ident) = showIdent ident
958+ prettyPrintRef (ValueRef ident) = showIdent ident
853− prettyPrintExport (TypeClassRef pn) = runProperName pn
959+ prettyPrintRef (TypeClassRef pn) = runProperName pn
960+ prettyPrintRef (ProperRef pn) = runProperName pn
854− prettyPrintExport (TypeInstanceRef ident) = showIdent ident
961+ prettyPrintRef (TypeInstanceRef ident) = showIdent ident
855− prettyPrintExport (ModuleRef name) = "module " ++ runModuleName name
962+ prettyPrintRef (ModuleRef name) = "module " ++ runModuleName name
856− prettyPrintExport (PositionedDeclarationRef _ _ ref) = prettyPrintExport ref
963+ prettyPrintRef (PositionedDeclarationRef _ _ ref) = prettyPrintExport ref
965+ prettyPrintImport :: ModuleName -> ImportDeclarationType -> Maybe ModuleName -> String
966+ prettyPrintImport mn idt qual =
968+ Implicit -> runModuleName mn
969+ Explicit refs -> runModuleName mn ++ " (" ++ intercalate ", " (map prettyPrintRef refs) ++ ")"
970+ Hiding refs -> runModuleName mn ++ " hiding (" ++ intercalate "," (map prettyPrintRef refs) ++ ")"
971+ in i ++ maybe "" (\q -> " as " ++ runModuleName q) qual
858 -- | Simplify an error message
973 -- | Simplify an error message
859 simplifyErrorMessage :: ErrorMessage -> ErrorMessage
974 simplifyErrorMessage :: ErrorMessage -> ErrorMessage
@@ -878,6 +993,7 @@ prettyPrintSingleError full level e = prettyPrintErrorMessage <$> onTypesInError
878 hintCategory ErrorUnifyingTypes{} = CheckHint
993 hintCategory ErrorUnifyingTypes{} = CheckHint
879 hintCategory ErrorInSubsumption{} = CheckHint
994 hintCategory ErrorInSubsumption{} = CheckHint
880 hintCategory ErrorInApplication{} = CheckHint
995 hintCategory ErrorInApplication{} = CheckHint
996+ hintCategory ErrorCheckingKind{} = CheckHint
881 hintCategory PositionedError{} = PositionHint
997 hintCategory PositionedError{} = PositionHint
882 hintCategory _ = OtherHint
998 hintCategory _ = OtherHint
@@ -895,13 +1011,13 @@ prettyPrintMultipleWarnings full = renderBox . prettyPrintMultipleWarningsBox fu
896-- | Pretty print warnings as a Box
1012-- | Pretty print warnings as a Box
897prettyPrintMultipleWarningsBox :: Bool -> MultipleErrors -> Box.Box
1013prettyPrintMultipleWarningsBox :: Bool -> MultipleErrors -> Box.Box
898−prettyPrintMultipleWarningsBox full = flip evalState M.empty . prettyPrintMultipleErrorsWith Warning "Warning found:" "Warning" full
1014+prettyPrintMultipleWarningsBox full = flip evalState defaultUnknownMap . prettyPrintMultipleErrorsWith Warning "Warning found:" "Warning" full
900-- | Pretty print errors as a Box
1016-- | Pretty print errors as a Box
901prettyPrintMultipleErrorsBox :: Bool -> MultipleErrors -> Box.Box
1017prettyPrintMultipleErrorsBox :: Bool -> MultipleErrors -> Box.Box
902−prettyPrintMultipleErrorsBox full = flip evalState M.empty . prettyPrintMultipleErrorsWith Error "Error found:" "Error" full
1018+prettyPrintMultipleErrorsBox full = flip evalState defaultUnknownMap . prettyPrintMultipleErrorsWith Error "Error found:" "Error" full
904−prettyPrintMultipleErrorsWith :: Level -> String -> String -> Bool -> MultipleErrors -> State UnknownMap Box.Box
1020+prettyPrintMultipleErrorsWith :: Level -> String -> String -> Bool -> MultipleErrors -> State TypeMap Box.Box
905prettyPrintMultipleErrorsWith level intro _ full (MultipleErrors [e]) = do
1021prettyPrintMultipleErrorsWith level intro _ full (MultipleErrors [e]) = do
906 result <- prettyPrintSingleError full level e
1022 result <- prettyPrintSingleError full level e
907 return $
1023 return $