@@ -1,19 +1,6 @@
1−-----------------------------------------------------------------------------
2−--
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)
6−--
7−-- Maintainer : Phil Freeman <paf31@cantab.net>
8−-- Stability : experimental
9−-- Portability :
10−--
11−-- |
12−--
13−-----------------------------------------------------------------------------
14−
151{-# LANGUAGE GeneralizedNewtypeDeriving #-}
162{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE RecordWildCards #-}
174{-# LANGUAGE MultiParamTypeClasses #-}
185
196module Language.PureScript.Errors where
@@ -24,7 +11,6 @@ import Prelude.Compat
2411import Data.Ord (comparing)
2512import Data.Either (lefts, rights)
2613import Data.List (intercalate, transpose, nub, nubBy, sortBy)
27−import Data.Function (on)
2814import Data.Foldable (fold)
2915
3016import qualified Data.Map as M
@@ -33,7 +19,7 @@ import Control.Monad
3319import Control.Monad.Writer
3420import Control.Monad.Error.Class (MonadError(..))
3521import Control.Monad.Trans.State.Lazy
36−import Control.Arrow (first, (&&&))
22+import Control.Arrow ((&&&))
3723
3824import Language.PureScript.Crash
3925import Language.PureScript.AST
@@ -143,6 +129,15 @@ data SimpleErrorMessage
143129 | UnusedDctorImport ProperName
144130 | UnusedDctorExplicitImport ProperName [ProperName]
145131 | 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
146141 deriving (Show)
147142
148143-- | Error message hints, providing more detailed information about failure.
@@ -278,6 +273,15 @@ errorCode em = case unwrapErrorMessage em of
278273 UnusedDctorImport{} -> "UnusedDctorImport"
279274 UnusedDctorExplicitImport{} -> "UnusedDctorExplicitImport"
280275 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"
281285
282286
283287-- |
@@ -311,11 +315,16 @@ onErrorMessages f = MultipleErrors . map f . runMultipleErrors
311315addHint :: ErrorMessageHint -> MultipleErrors -> MultipleErrors
312316addHint hint = onErrorMessages $ \(ErrorMessage hints se) -> ErrorMessage (hint : hints) se
313317
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)
316−
317318-- | 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
324+ } deriving Show
325+
326+defaultUnknownMap :: TypeMap
327+defaultUnknownMap = TypeMap M.empty 0 M.empty 0
319328
320329-- | How critical the issue is
321330data Level = Error | Warning deriving Show
@@ -326,48 +335,72 @@ data Level = Error | Warning deriving Show
326335unwrapErrorMessage :: ErrorMessage -> SimpleErrorMessage
327336unwrapErrorMessage (ErrorMessage _ se) = se
328337
329−replaceUnknowns :: Type -> State UnknownMap Type
338+replaceUnknowns :: Type -> State TypeMap Type
330339replaceUnknowns = everywhereOnTypesM replaceTypes
331340 where
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)
335− Just i -> (i, m)
336−
337− replaceTypes :: Type -> State UnknownMap Type
338− replaceTypes (TUnknown u) = state $ first TUnknown . lookupTable (TypeLabel, u)
339− replaceTypes (Skolem name s sko) = state $ first (flip (Skolem name) sko) . lookupTable (SkolemLabel name, s)
341+ replaceTypes :: Type -> State TypeMap Type
342+ replaceTypes (TUnknown u) = do
343+ m <- get
344+ case M.lookup u (umUnknownMap m) of
345+ Nothing -> do
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')
350+ replaceTypes (Skolem name s sko ss) = do
351+ m <- get
352+ case M.lookup s (umSkolemMap m) of
353+ Nothing -> do
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)
340358 replaceTypes other = return other
341359
342360onTypesInErrorMessageM :: (Applicative m) => (Type -> m Type) -> ErrorMessage -> m ErrorMessage
343361onTypesInErrorMessageM f (ErrorMessage hints simple) = ErrorMessage <$> traverse gHint hints <*> gSimple simple
344362 where
345− gSimple (InfiniteType t) = InfiniteType <$> f t
346− gSimple (TypesDoNotUnify t1 t2) = TypesDoNotUnify <$> f t1 <*> f t2
347− gSimple (ConstrainedTypeUnified t1 t2) = ConstrainedTypeUnified <$> f t1 <*> f t2
348− gSimple (ExprDoesNotHaveType e t) = ExprDoesNotHaveType e <$> f t
349− gSimple (CannotApplyFunction t e) = CannotApplyFunction <$> f t <*> pure e
350− gSimple (InvalidInstanceHead t) = InvalidInstanceHead <$> f t
351− gSimple other = pure other
352− gHint (ErrorInSubsumption t1 t2) = ErrorInSubsumption <$> f t1 <*> f t2
353− gHint (ErrorUnifyingTypes t1 t2) = ErrorUnifyingTypes <$> f t1 <*> f t2
354− gHint (ErrorCheckingType e t) = ErrorCheckingType e <$> f t
355− gHint (ErrorCheckingKind t) = ErrorCheckingKind <$> f t
356− gHint (ErrorInApplication e1 t1 e2) = ErrorInApplication e1 <$> f t1 <*> pure e2
357− gHint other = pure other
363+ gSimple (InfiniteType t) = InfiniteType <$> f t
364+ gSimple (TypesDoNotUnify t1 t2) = TypesDoNotUnify <$> f t1 <*> f t2
365+ gSimple (ConstrainedTypeUnified t1 t2) = ConstrainedTypeUnified <$> f t1 <*> f t2
366+ gSimple (ExprDoesNotHaveType e t) = ExprDoesNotHaveType e <$> f t
367+ gSimple (CannotApplyFunction t e) = CannotApplyFunction <$> f t <*> pure e
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
377+
378+ gSimple other = pure other
379+
380+ gHint (ErrorInSubsumption t1 t2) = ErrorInSubsumption <$> f t1 <*> f t2
381+ gHint (ErrorUnifyingTypes t1 t2) = ErrorUnifyingTypes <$> f t1 <*> f t2
382+ gHint (ErrorCheckingType e t) = ErrorCheckingType e <$> f t
383+ gHint (ErrorCheckingKind t) = ErrorCheckingKind <$> f t
384+ gHint (ErrorInApplication e1 t1 e2) = ErrorInApplication e1 <$> f t1 <*> pure e2
385+ gHint (ErrorInInstance cl ts) = ErrorInInstance cl <$> traverse f ts
386+ gHint other = pure other
358387
359388-- |
360389-- Pretty print a single error, simplifying if necessary
361390--
362−prettyPrintSingleError :: Bool -> Level -> ErrorMessage -> State UnknownMap Box.Box
363−prettyPrintSingleError full level e = prettyPrintErrorMessage <$> onTypesInErrorMessageM replaceUnknowns (if full then e else simplifyErrorMessage e)
391+prettyPrintSingleError :: Bool -> Level -> ErrorMessage -> State TypeMap Box.Box
392+prettyPrintSingleError full level e = do
393+ em <- onTypesInErrorMessageM replaceUnknowns (if full then e else simplifyErrorMessage e)
394+ um <- get
395+ return (prettyPrintErrorMessage um em)
364396 where
365397
366398 -- Pretty print an ErrorMessage
367− prettyPrintErrorMessage :: ErrorMessage -> Box.Box
368− prettyPrintErrorMessage (ErrorMessage hints simple) =
369− paras $
399+ prettyPrintErrorMessage :: TypeMap -> ErrorMessage -> Box.Box
400+ prettyPrintErrorMessage typeMap (ErrorMessage hints simple) =
401+ paras
370402 [ foldr renderHint (indent (renderSimpleErrorMessage simple)) hints
403+ , Box.moveDown 1 typeInformation
371404 , Box.moveDown 1 $ paras [ line $ "See " ++ wikiUri ++ " for more information, "
372405 , line $ "or to contribute content related to this " ++ levelText ++ "."
373406 ]
@@ -376,6 +409,23 @@ prettyPrintSingleError full level e = prettyPrintErrorMessage <$> onTypesInError
376409 wikiUri :: String
377410 wikiUri = "https://github.com/purescript/purescript/wiki/Error-Code-" ++ errorCode e
378411
412+ typeInformation :: Box.Box
413+ typeInformation | not (null types) = Box.hsep 1 Box.left [ line "where", paras types]
414+ | otherwise = Box.emptyBox 0 0
415+ where
416+ types :: [Box.Box]
417+ types = map skolemInfo (M.elems (umSkolemMap typeMap)) ++
418+ map unknownInfo (M.elems (umUnknownMap typeMap))
419+
420+ skolemInfo :: (String, Int, Maybe SourceSpan) -> Box.Box
421+ skolemInfo (name, s, ss) =
422+ paras $
423+ line (name ++ show s ++ " is a rigid type variable")
424+ : foldMap (return . line . (" bound at " ++) . displayStartEndPos) ss
425+
426+ unknownInfo :: Int -> Box.Box
427+ unknownInfo u = line $ "_" ++ show u ++ " is an unknown type"
428+
379429 renderSimpleErrorMessage :: SimpleErrorMessage -> Box.Box
380430 renderSimpleErrorMessage (CannotGetFileInfo path) =
381431 paras [ line "Unable to read file info: "
@@ -576,7 +626,16 @@ prettyPrintSingleError full level e = prettyPrintErrorMessage <$> onTypesInError
576626 , indent $ Box.hsep 1 Box.left [ line (showQualified runProperName nm)
577627 , Box.vcat Box.left (map typeAtomAsBox ts)
578628 ]
629+ , paras [ line "The instance head contains unknown type variables. Consider adding a type annotation."
630+ | any containsUnknowns ts
631+ ]
579632 ]
633+ where
634+ containsUnknowns :: Type -> Bool
635+ containsUnknowns = everythingOnTypes (||) go
636+ where
637+ go TUnknown{} = True
638+ go _ = False
580639 renderSimpleErrorMessage (PossiblyInfiniteInstance nm ts) =
581640 paras [ line "Type class instance for"
582641 , indent $ Box.hsep 1 Box.left [ line (showQualified runProperName nm)
@@ -715,8 +774,50 @@ prettyPrintSingleError full level e = prettyPrintErrorMessage <$> onTypesInError
715774 , indent $ paras $ map (line .runProperName) names ]
716775
717776 renderSimpleErrorMessage (DeprecatedQualifiedSyntax name qualName) =
718− paras [ line $ "The import of type " ++ runModuleName name ++ " as " ++ runModuleName qualName ++ " uses the deprecated 'import qualified' syntax."
719− , line $ "This syntax form will be removed in PureScript 0.9." ]
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:"
780+ , indent $ line $ "import " ++ runModuleName name ++ " as " ++ runModuleName qualName
781+ , line $ "The deprecated syntax will be removed in PureScript 0.9."
782+ ]
783+
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
789+ , line $ "The deprecated syntax will be removed in PureScript 0.9."
790+ ]
791+
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."
798+ ]
799+
800+ renderSimpleErrorMessage (RedundantUnqualifiedImport name imp) =
801+ line $ "Import of " ++ prettyPrintImport name imp Nothing ++ " is redundant due to a whole-module import"
802+
803+ renderSimpleErrorMessage (DuplicateSelectiveImport name) =
804+ line $ "There is an existing import of " ++ runModuleName name ++ ", consider merging the import lists"
805+
806+ renderSimpleErrorMessage (DuplicateImport name imp qual) =
807+ line $ "Duplicate import of " ++ prettyPrintImport name imp qual
808+
809+ renderSimpleErrorMessage (DuplicateImportRef ref) =
810+ line $ "Import list contains multiple references to " ++ ref
811+
812+ renderSimpleErrorMessage (DuplicateExportRef ref) =
813+ line $ "Export list contains multiple references to " ++ ref
814+
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)." ]
818+
819+ renderSimpleErrorMessage (RedundantEmptyHidingImport mn) =
820+ line $ "The import for module " ++ runModuleName mn ++ " is redundant as all members have been explicitly hidden."
720821
721822 renderHint :: ErrorMessageHint -> Box.Box -> Box.Box
722823 renderHint (ErrorUnifyingTypes t1 t2) detail =
@@ -849,11 +950,25 @@ prettyPrintSingleError full level e = prettyPrintErrorMessage <$> onTypesInError
849950 -- Pretty print and export declaration
850951 prettyPrintExport :: DeclarationRef -> String
851952 prettyPrintExport (TypeRef pn _) = runProperName pn
852− prettyPrintExport (ValueRef ident) = showIdent ident
853− prettyPrintExport (TypeClassRef pn) = runProperName pn
854− prettyPrintExport (TypeInstanceRef ident) = showIdent ident
855− prettyPrintExport (ModuleRef name) = "module " ++ runModuleName name
856− prettyPrintExport (PositionedDeclarationRef _ _ ref) = prettyPrintExport ref
953+ prettyPrintExport ref = prettyPrintRef ref
954+
955+ prettyPrintRef :: DeclarationRef -> String
956+ prettyPrintRef (TypeRef pn Nothing) = runProperName pn ++ "(..)"
957+ prettyPrintRef (TypeRef pn (Just dctors)) = runProperName pn ++ "(" ++ intercalate ", " (map runProperName dctors) ++ ")"
958+ prettyPrintRef (ValueRef ident) = showIdent ident
959+ prettyPrintRef (TypeClassRef pn) = runProperName pn
960+ prettyPrintRef (ProperRef pn) = runProperName pn
961+ prettyPrintRef (TypeInstanceRef ident) = showIdent ident
962+ prettyPrintRef (ModuleRef name) = "module " ++ runModuleName name
963+ prettyPrintRef (PositionedDeclarationRef _ _ ref) = prettyPrintExport ref
964+
965+ prettyPrintImport :: ModuleName -> ImportDeclarationType -> Maybe ModuleName -> String
966+ prettyPrintImport mn idt qual =
967+ let i = case idt of
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
857972
858973 -- | Simplify an error message
859974 simplifyErrorMessage :: ErrorMessage -> ErrorMessage
@@ -878,6 +993,7 @@ prettyPrintSingleError full level e = prettyPrintErrorMessage <$> onTypesInError
878993 hintCategory ErrorUnifyingTypes{} = CheckHint
879994 hintCategory ErrorInSubsumption{} = CheckHint
880995 hintCategory ErrorInApplication{} = CheckHint
996+ hintCategory ErrorCheckingKind{} = CheckHint
881997 hintCategory PositionedError{} = PositionHint
882998 hintCategory _ = OtherHint
883999
@@ -895,13 +1011,13 @@ prettyPrintMultipleWarnings full = renderBox . prettyPrintMultipleWarningsBox fu
8951011
8961012-- | Pretty print warnings as a Box
8971013prettyPrintMultipleWarningsBox :: 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
8991015
9001016-- | Pretty print errors as a Box
9011017prettyPrintMultipleErrorsBox :: 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
9031019
904−prettyPrintMultipleErrorsWith :: Level -> String -> String -> Bool -> MultipleErrors -> State UnknownMap Box.Box
1020+prettyPrintMultipleErrorsWith :: Level -> String -> String -> Bool -> MultipleErrors -> State TypeMap Box.Box
9051021prettyPrintMultipleErrorsWith level intro _ full (MultipleErrors [e]) = do
9061022 result <- prettyPrintSingleError full level e
9071023 return $