Skip to content

Commit 3171a77

Browse files
authored
Allow errors to carry multiple positions (purescript#3255)
1 parent 13bd530 commit 3171a77

7 files changed

Lines changed: 28 additions & 21 deletions

File tree

src/Language/PureScript/AST/Declarations.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ data ErrorMessageHint
198198
| ErrorInTypeClassDeclaration (ProperName 'ClassName)
199199
| ErrorInForeignImport Ident
200200
| ErrorSolvingConstraint Constraint
201-
| PositionedError SourceSpan
201+
| PositionedError (NEL.NonEmpty SourceSpan)
202202
deriving (Show)
203203

204204
-- | Categories of hints

src/Language/PureScript/Errors.hs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ import qualified Text.PrettyPrint.Boxes as Box
4747
newtype ErrorSuggestion = ErrorSuggestion Text
4848

4949
-- | Get the source span for an error
50-
errorSpan :: ErrorMessage -> Maybe SourceSpan
50+
errorSpan :: ErrorMessage -> Maybe (NEL.NonEmpty SourceSpan)
5151
errorSpan = findHint matchSpan
5252
where
5353
matchSpan (PositionedError ss) = Just ss
@@ -195,7 +195,7 @@ errorMessage err = MultipleErrors [ErrorMessage [] err]
195195

196196
-- | Create an error set from a single simple error message and source annotation
197197
errorMessage' :: SourceSpan -> SimpleErrorMessage -> MultipleErrors
198-
errorMessage' ss err = MultipleErrors [ErrorMessage [PositionedError ss] err]
198+
errorMessage' ss err = MultipleErrors [ErrorMessage [positionedError ss] err]
199199

200200
-- | Create an error set from a single error message
201201
singleError :: ErrorMessage -> MultipleErrors
@@ -327,7 +327,10 @@ errorSuggestion err =
327327

328328
suggestionSpan :: ErrorMessage -> Maybe SourceSpan
329329
suggestionSpan e =
330-
getSpan (unwrapErrorMessage e) <$> errorSpan e
330+
-- The `NEL.head` is a bit arbitrary here, but I don't think we'll
331+
-- have errors-with-suggestions that also have multiple source
332+
-- spans. -garyb
333+
getSpan (unwrapErrorMessage e) . NEL.head <$> errorSpan e
331334
where
332335
startOnly SourceSpan{spanName, spanStart} = SourceSpan {spanName, spanStart, spanEnd = spanStart}
333336

@@ -1108,7 +1111,7 @@ prettyPrintSingleError (PPEOptions codeColor full level showDocs relPath) e = fl
11081111
]
11091112
]
11101113
renderHint (PositionedError srcSpan) detail =
1111-
paras [ line $ "at " <> displaySourceSpan relPath srcSpan
1114+
paras [ line $ "at " <> displaySourceSpan relPath (NEL.head srcSpan)
11121115
, detail
11131116
]
11141117

@@ -1393,7 +1396,10 @@ warnAndRethrowWithPosition :: (MonadError MultipleErrors m, MonadWriter Multiple
13931396
warnAndRethrowWithPosition pos = rethrowWithPosition pos . warnWithPosition pos
13941397

13951398
withPosition :: SourceSpan -> ErrorMessage -> ErrorMessage
1396-
withPosition pos (ErrorMessage hints se) = ErrorMessage (PositionedError pos : hints) se
1399+
withPosition pos (ErrorMessage hints se) = ErrorMessage (positionedError pos : hints) se
1400+
1401+
positionedError :: SourceSpan -> ErrorMessageHint
1402+
positionedError = PositionedError . pure
13971403

13981404
-- | Runs a computation listening for warnings and then escalating any warnings
13991405
-- that match the predicate to error status.

src/Language/PureScript/Errors/JSON.hs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module Language.PureScript.Errors.JSON where
55
import Prelude.Compat
66

77
import qualified Data.Aeson.TH as A
8+
import qualified Data.List.NonEmpty as NEL
89
import Data.Monoid ((<>))
910
import qualified Data.Text as T
1011
import Data.Text (Text)
@@ -31,6 +32,7 @@ data JSONError = JSONError
3132
, filename :: Maybe String
3233
, moduleName :: Maybe Text
3334
, suggestion :: Maybe ErrorSuggestion
35+
, allSpans :: [P.SourceSpan]
3436
} deriving (Show, Eq)
3537

3638
data JSONResult = JSONResult
@@ -43,22 +45,22 @@ $(A.deriveJSON A.defaultOptions ''JSONError)
4345
$(A.deriveJSON A.defaultOptions ''JSONResult)
4446
$(A.deriveJSON A.defaultOptions ''ErrorSuggestion)
4547

46-
4748
toJSONErrors :: Bool -> P.Level -> P.MultipleErrors -> [JSONError]
4849
toJSONErrors verbose level = map (toJSONError verbose level) . P.runMultipleErrors
4950

5051
toJSONError :: Bool -> P.Level -> P.ErrorMessage -> JSONError
5152
toJSONError verbose level e =
52-
JSONError (toErrorPosition <$> sspan)
53+
JSONError (toErrorPosition <$> fmap NEL.head spans)
5354
(P.renderBox (P.prettyPrintSingleError (P.PPEOptions Nothing verbose level False mempty) (P.stripModuleAndSpan e)))
5455
(P.errorCode e)
5556
(P.errorDocUri e)
56-
(P.spanName <$> sspan)
57+
(P.spanName <$> fmap NEL.head spans)
5758
(P.runModuleName <$> P.errorModule e)
5859
(toSuggestion e)
60+
(maybe [] NEL.toList spans)
5961
where
60-
sspan :: Maybe P.SourceSpan
61-
sspan = P.errorSpan e
62+
spans :: Maybe (NEL.NonEmpty P.SourceSpan)
63+
spans = P.errorSpan e
6264

6365
toErrorPosition :: P.SourceSpan -> ErrorPosition
6466
toErrorPosition ss =

src/Language/PureScript/Parser/Declarations.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ parseModuleFromFile toFilePath (k, content) = do
351351

352352
-- | Converts a 'ParseError' into a 'PositionedError'
353353
toPositionedError :: P.ParseError -> ErrorMessage
354-
toPositionedError perr = ErrorMessage [ PositionedError (SourceSpan name start end) ] (ErrorParsingModule perr)
354+
toPositionedError perr = ErrorMessage [ positionedError (SourceSpan name start end) ] (ErrorParsingModule perr)
355355
where
356356
name = (P.sourceName . P.errorPos) perr
357357
start = (toSourcePos . P.errorPos) perr

src/Language/PureScript/TypeChecker.hs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ typeCheckAll moduleName _ = traverse go
233233
where
234234
go :: Declaration -> m Declaration
235235
go (DataDeclaration sa@(ss, _) dtype name args dctors) = do
236-
warnAndRethrow (addHint (ErrorInTypeConstructor name) . addHint (PositionedError ss)) $ do
236+
warnAndRethrow (addHint (ErrorInTypeConstructor name) . addHint (positionedError ss)) $ do
237237
when (dtype == Newtype) $ checkNewtype name dctors
238238
checkDuplicateTypeArguments $ map fst args
239239
ctorKind <- kindsOf True moduleName name args (concatMap snd dctors)
@@ -263,7 +263,7 @@ typeCheckAll moduleName _ = traverse go
263263
toDataDecl (DataDeclaration _ dtype nm args dctors) = Just (dtype, nm, args, dctors)
264264
toDataDecl _ = Nothing
265265
go (TypeSynonymDeclaration sa@(ss, _) name args ty) = do
266-
warnAndRethrow (addHint (ErrorInTypeSynonym name) . addHint (PositionedError ss) ) $ do
266+
warnAndRethrow (addHint (ErrorInTypeSynonym name) . addHint (positionedError ss) ) $ do
267267
checkDuplicateTypeArguments $ map fst args
268268
kind <- kindsOf False moduleName name args [ty]
269269
let args' = args `withKinds` kind
@@ -273,7 +273,7 @@ typeCheckAll moduleName _ = traverse go
273273
internalError "Type declarations should have been removed before typeCheckAlld"
274274
go (ValueDecl sa@(ss, _) name nameKind [] [MkUnguarded val]) = do
275275
env <- getEnv
276-
warnAndRethrow (addHint (ErrorInValueDeclaration name) . addHint (PositionedError ss)) $ do
276+
warnAndRethrow (addHint (ErrorInValueDeclaration name) . addHint (positionedError ss)) $ do
277277
val' <- checkExhaustiveExpr ss env moduleName val
278278
valueIsNotDefined moduleName name
279279
[(_, (val'', ty))] <- typesOf NonRecursiveBindingGroup moduleName [((sa, name), val')]
@@ -304,7 +304,7 @@ typeCheckAll moduleName _ = traverse go
304304
putEnv $ env { kinds = S.insert (Qualified (Just moduleName) name) (kinds env) }
305305
return d
306306
go (d@(ExternDeclaration (ss, _) name ty)) = do
307-
warnAndRethrow (addHint (ErrorInForeignImport name) . addHint (PositionedError ss)) $ do
307+
warnAndRethrow (addHint (ErrorInForeignImport name) . addHint (positionedError ss)) $ do
308308
env <- getEnv
309309
kind <- kindOf ty
310310
guardWith (errorMessage (ExpectedType ty kind)) $ kind == kindType
@@ -315,15 +315,15 @@ typeCheckAll moduleName _ = traverse go
315315
go d@FixityDeclaration{} = return d
316316
go d@ImportDeclaration{} = return d
317317
go d@(TypeClassDeclaration (ss, _) pn args implies deps tys) = do
318-
warnAndRethrow (addHint (ErrorInTypeClassDeclaration pn) . addHint (PositionedError ss)) $ do
318+
warnAndRethrow (addHint (ErrorInTypeClassDeclaration pn) . addHint (positionedError ss)) $ do
319319
env <- getEnv
320320
let qualifiedClassName = Qualified (Just moduleName) pn
321321
guardWith (errorMessage (DuplicateTypeClass pn ss)) $
322322
not (M.member qualifiedClassName (typeClasses env))
323323
addTypeClass qualifiedClassName args implies deps tys
324324
return d
325325
go (d@(TypeInstanceDeclaration (ss, _) ch idx dictName deps className tys body)) =
326-
rethrow (addHint (ErrorInInstance className tys) . addHint (PositionedError ss)) $ do
326+
rethrow (addHint (ErrorInInstance className tys) . addHint (positionedError ss)) $ do
327327
env <- getEnv
328328
let qualifiedDictName = Qualified (Just moduleName) dictName
329329
flip (traverse_ . traverse_) (typeClassDictionaries env) $ \dictionaries ->
@@ -568,4 +568,3 @@ typeCheckModule (Module ss coms mn decls (Just exps)) =
568568
extractMemberName (TypeDeclaration td) = tydeclIdent td
569569
extractMemberName _ = internalError "Unexpected declaration in typeclass member list"
570570
checkClassMembersAreExported _ = return ()
571-

src/Language/PureScript/TypeChecker/Monad.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ rethrowWithPositionTC
127127
=> SourceSpan
128128
-> m a
129129
-> m a
130-
rethrowWithPositionTC pos = withErrorMessageHint (PositionedError pos)
130+
rethrowWithPositionTC pos = withErrorMessageHint (positionedError pos)
131131

132132
warnAndRethrowWithPositionTC
133133
:: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)

src/Language/PureScript/TypeChecker/Skolems.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ skolemEscapeCheck expr@TypedValue{} =
100100
go (scopes, _) (PositionedValue ss _ _) = ((scopes, Just ss), [])
101101
go (scopes, ssUsed) val@(TypedValue _ _ ty) =
102102
( (allScopes, ssUsed)
103-
, [ ErrorMessage (maybe id ((:) . PositionedError) ssUsed [ ErrorInExpression val ]) $
103+
, [ ErrorMessage (maybe id ((:) . positionedError) ssUsed [ ErrorInExpression val ]) $
104104
EscapedSkolem name ssBound ty
105105
| (name, scope, ssBound) <- collectSkolems ty
106106
, notMember scope allScopes

0 commit comments

Comments
 (0)