@@ -14,6 +14,7 @@
15{-# LANGUAGE GeneralizedNewtypeDeriving #-}
15{-# LANGUAGE GeneralizedNewtypeDeriving #-}
16{-# LANGUAGE FlexibleContexts #-}
16{-# LANGUAGE FlexibleContexts #-}
17+{-# LANGUAGE RecordWildCards #-}
17{-# LANGUAGE MultiParamTypeClasses #-}
18{-# LANGUAGE MultiParamTypeClasses #-}
19module Language.PureScript.Errors where
20module Language.PureScript.Errors where
@@ -24,7 +25,6 @@ import Prelude.Compat
24import Data.Ord (comparing)
25import Data.Ord (comparing)
25import Data.Either (lefts, rights)
26import Data.Either (lefts, rights)
26import Data.List (intercalate, transpose, nub, nubBy, sortBy)
27import Data.List (intercalate, transpose, nub, nubBy, sortBy)
27−import Data.Function (on)
28import Data.Foldable (fold)
28import Data.Foldable (fold)
30import qualified Data.Map as M
30import qualified Data.Map as M
@@ -33,7 +33,7 @@ import Control.Monad
33import Control.Monad.Writer
33import Control.Monad.Writer
34import Control.Monad.Error.Class (MonadError(..))
34import Control.Monad.Error.Class (MonadError(..))
35import Control.Monad.Trans.State.Lazy
35import Control.Monad.Trans.State.Lazy
36−import Control.Arrow (first, (&&&))
36+import Control.Arrow ((&&&))
38import Language.PureScript.Crash
38import Language.PureScript.Crash
39import Language.PureScript.AST
39import Language.PureScript.AST
@@ -311,11 +311,16 @@ onErrorMessages f = MultipleErrors . map f . runMultipleErrors
311addHint :: ErrorMessageHint -> MultipleErrors -> MultipleErrors
311addHint :: ErrorMessageHint -> MultipleErrors -> MultipleErrors
312addHint hint = onErrorMessages $ \(ErrorMessage hints se) -> ErrorMessage (hint : hints) se
312addHint 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.
314-- | A map from rigid type variable name/unknown variable pairs to new variables.
318−type UnknownMap = M.Map (LabelType, Int) Int
315+data TypeMap = TypeMap
316+ { umSkolemMap :: M.Map Int (String, Int, Maybe SourceSpan)
317+ , umNextSkolem :: Int
318+ , umUnknownMap :: M.Map Int Int
319+ , umNextUnknown :: Int
322+defaultUnknownMap :: TypeMap
323+defaultUnknownMap = TypeMap M.empty 0 M.empty 0
320-- | How critical the issue is
325-- | How critical the issue is
321data Level = Error | Warning deriving Show
326data Level = Error | Warning deriving Show
@@ -326,56 +331,80 @@ data Level = Error | Warning deriving Show
326unwrapErrorMessage :: ErrorMessage -> SimpleErrorMessage
331unwrapErrorMessage :: ErrorMessage -> SimpleErrorMessage
327unwrapErrorMessage (ErrorMessage _ se) = se
332unwrapErrorMessage (ErrorMessage _ se) = se
329−replaceUnknowns :: Type -> State UnknownMap Type
334+replaceUnknowns :: Type -> State TypeMap Type
330replaceUnknowns = everywhereOnTypesM replaceTypes
335replaceUnknowns = 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
337+ replaceTypes :: Type -> State TypeMap Type
338− replaceTypes (TUnknown u) = state $ first TUnknown . lookupTable (TypeLabel, u)
338+ replaceTypes (TUnknown u) = do
340+ case M.lookup u (umUnknownMap m) of
342+ let u' = umNextUnknown m
343+ put $ m { umUnknownMap = M.insert u u' (umUnknownMap m), umNextUnknown = u' + 1 }
344+ return (TUnknown u')
345+ Just u' -> return (TUnknown u')
339− replaceTypes (Skolem name s sko) = state $ first (flip (Skolem name) sko) . lookupTable (SkolemLabel name, s)
346+ replaceTypes (Skolem name s sko ss) = do
348+ case M.lookup s (umSkolemMap m) of
350+ let s' = umNextSkolem m
351+ put $ m { umSkolemMap = M.insert s (name, s', ss) (umSkolemMap m), umNextSkolem = s' + 1 }
352+ return (Skolem name s' sko ss)
353+ Just (_, s', _) -> return (Skolem name s' sko ss)
340 replaceTypes other = return other
354 replaceTypes other = return other
342onTypesInErrorMessageM :: (Applicative m) => (Type -> m Type) -> ErrorMessage -> m ErrorMessage
356onTypesInErrorMessageM :: (Applicative m) => (Type -> m Type) -> ErrorMessage -> m ErrorMessage
343onTypesInErrorMessageM f (ErrorMessage hints simple) = ErrorMessage <$> traverse gHint hints <*> gSimple simple
357onTypesInErrorMessageM f (ErrorMessage hints simple) = ErrorMessage <$> traverse gHint hints <*> gSimple simple
345− gSimple (InfiniteType t) = InfiniteType <$> f t
359+ gSimple (InfiniteType t) = InfiniteType <$> f t
346− gSimple (TypesDoNotUnify t1 t2) = TypesDoNotUnify <$> f t1 <*> f t2
360+ gSimple (TypesDoNotUnify t1 t2) = TypesDoNotUnify <$> f t1 <*> f t2
347− gSimple (ConstrainedTypeUnified t1 t2) = ConstrainedTypeUnified <$> f t1 <*> f t2
361+ gSimple (ConstrainedTypeUnified t1 t2) = ConstrainedTypeUnified <$> f t1 <*> f t2
348− gSimple (ExprDoesNotHaveType e t) = ExprDoesNotHaveType e <$> f t
362+ gSimple (ExprDoesNotHaveType e t) = ExprDoesNotHaveType e <$> f t
349− gSimple (CannotApplyFunction t e) = CannotApplyFunction <$> f t <*> pure e
363+ gSimple (CannotApplyFunction t e) = CannotApplyFunction <$> f t <*> pure e
350− gSimple (InvalidInstanceHead t) = InvalidInstanceHead <$> f t
364+ gSimple (InvalidInstanceHead t) = InvalidInstanceHead <$> f t
351− gSimple other = pure other
365+ gSimple other = pure other
352− gHint (ErrorInSubsumption t1 t2) = ErrorInSubsumption <$> f t1 <*> f t2
367+ gHint (ErrorInSubsumption t1 t2) = ErrorInSubsumption <$> f t1 <*> f t2
353− gHint (ErrorUnifyingTypes t1 t2) = ErrorUnifyingTypes <$> f t1 <*> f t2
368+ gHint (ErrorUnifyingTypes t1 t2) = ErrorUnifyingTypes <$> f t1 <*> f t2
354− gHint (ErrorCheckingType e t) = ErrorCheckingType e <$> f t
369+ gHint (ErrorCheckingType e t) = ErrorCheckingType e <$> f t
355− gHint (ErrorCheckingKind t) = ErrorCheckingKind <$> f t
370+ gHint (ErrorCheckingKind t) = ErrorCheckingKind <$> f t
356− gHint (ErrorInApplication e1 t1 e2) = ErrorInApplication e1 <$> f t1 <*> pure e2
371+ gHint (ErrorInApplication e1 t1 e2) = ErrorInApplication e1 <$> f t1 <*> pure e2
357− gHint other = pure other
372+ gHint other = pure other
360-- Pretty print a single error, simplifying if necessary
375-- Pretty print a single error, simplifying if necessary
362−prettyPrintSingleError :: Bool -> Level -> ErrorMessage -> State UnknownMap Box.Box
377+prettyPrintSingleError :: Bool -> Level -> ErrorMessage -> State TypeMap Box.Box
378+prettyPrintSingleError full level e = do
363−prettyPrintSingleError full level e = prettyPrintErrorMessage <$> onTypesInErrorMessageM replaceUnknowns (if full then e else simplifyErrorMessage e)
379+ em <- onTypesInErrorMessageM replaceUnknowns (if full then e else simplifyErrorMessage e)
381+ return (prettyPrintErrorMessage um em)
366 -- Pretty print an ErrorMessage
384 -- Pretty print an ErrorMessage
367− prettyPrintErrorMessage :: ErrorMessage -> Box.Box
385+ prettyPrintErrorMessage :: TypeMap -> ErrorMessage -> Box.Box
368− prettyPrintErrorMessage (ErrorMessage hints simple) =
386+ prettyPrintErrorMessage typeMap (ErrorMessage hints simple) =
370− [ foldr renderHint (indent (renderSimpleErrorMessage simple)) hints
388+ foldr renderHint (indent (renderSimpleErrorMessage simple)) hints
371− , Box.moveDown 1 $ paras [ line $ "See " ++ wikiUri ++ " for more information, "
390+ ++ [ Box.moveDown 1 $ paras [ line $ "See " ++ wikiUri ++ " for more information, "
372− , line $ "or to contribute content related to this " ++ levelText ++ "."
391+ , line $ "or to contribute content related to this " ++ levelText ++ "."
376 wikiUri :: String
395 wikiUri :: String
377 wikiUri = "https://github.com/purescript/purescript/wiki/Error-Code-" ++ errorCode e
396 wikiUri = "https://github.com/purescript/purescript/wiki/Error-Code-" ++ errorCode e
398+ typeInformation :: [Box.Box]
399+ typeInformation = M.elems . M.mapMaybe skolemInfo . umSkolemMap $ typeMap
401+ skolemInfo :: (String, Int, Maybe SourceSpan) -> Maybe Box.Box
402+ skolemInfo (name, s, Just ss) =
403+ Just . Box.moveDown 1 $ paras [ line $ "(" ++ name ++ show s ++ " is a rigid type variable"
404+ , line $ " bound at " ++ displayStartEndPos ss ++ ")"
406+ skolemInfo _ = Nothing
379 renderSimpleErrorMessage :: SimpleErrorMessage -> Box.Box
408 renderSimpleErrorMessage :: SimpleErrorMessage -> Box.Box
380 renderSimpleErrorMessage (CannotGetFileInfo path) =
409 renderSimpleErrorMessage (CannotGetFileInfo path) =
381 paras [ line "Unable to read file info: "
410 paras [ line "Unable to read file info: "
@@ -878,6 +907,7 @@ prettyPrintSingleError full level e = prettyPrintErrorMessage <$> onTypesInError
878 hintCategory ErrorUnifyingTypes{} = CheckHint
907 hintCategory ErrorUnifyingTypes{} = CheckHint
879 hintCategory ErrorInSubsumption{} = CheckHint
908 hintCategory ErrorInSubsumption{} = CheckHint
880 hintCategory ErrorInApplication{} = CheckHint
909 hintCategory ErrorInApplication{} = CheckHint
910+ hintCategory ErrorCheckingKind{} = CheckHint
881 hintCategory PositionedError{} = PositionHint
911 hintCategory PositionedError{} = PositionHint
882 hintCategory _ = OtherHint
912 hintCategory _ = OtherHint
@@ -895,13 +925,13 @@ prettyPrintMultipleWarnings full = renderBox . prettyPrintMultipleWarningsBox fu
896-- | Pretty print warnings as a Box
926-- | Pretty print warnings as a Box
897prettyPrintMultipleWarningsBox :: Bool -> MultipleErrors -> Box.Box
927prettyPrintMultipleWarningsBox :: Bool -> MultipleErrors -> Box.Box
898−prettyPrintMultipleWarningsBox full = flip evalState M.empty . prettyPrintMultipleErrorsWith Warning "Warning found:" "Warning" full
928+prettyPrintMultipleWarningsBox full = flip evalState defaultUnknownMap . prettyPrintMultipleErrorsWith Warning "Warning found:" "Warning" full
900-- | Pretty print errors as a Box
930-- | Pretty print errors as a Box
901prettyPrintMultipleErrorsBox :: Bool -> MultipleErrors -> Box.Box
931prettyPrintMultipleErrorsBox :: Bool -> MultipleErrors -> Box.Box
902−prettyPrintMultipleErrorsBox full = flip evalState M.empty . prettyPrintMultipleErrorsWith Error "Error found:" "Error" full
932+prettyPrintMultipleErrorsBox full = flip evalState defaultUnknownMap . prettyPrintMultipleErrorsWith Error "Error found:" "Error" full
904−prettyPrintMultipleErrorsWith :: Level -> String -> String -> Bool -> MultipleErrors -> State UnknownMap Box.Box
934+prettyPrintMultipleErrorsWith :: Level -> String -> String -> Bool -> MultipleErrors -> State TypeMap Box.Box
905prettyPrintMultipleErrorsWith level intro _ full (MultipleErrors [e]) = do
935prettyPrintMultipleErrorsWith level intro _ full (MultipleErrors [e]) = do
906 result <- prettyPrintSingleError full level e
936 result <- prettyPrintSingleError full level e