git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Type suggestions (#2076)

* Expose missing type declaration suggestion * Tighten span for type wildcard warnings

commit5a349845e148fc03d27c372e990b40b0eb0c4bc3 authorNicholas Wolverson <nicholas.wolverson@gmail.com> dateSun 1 May 2016, 23:05 (10 years ago) parent69f8b3e
16 files changed+72−32
src/Language/PureScript/Docs/Convert.hs+4−3 src/Language/PureScript/Docs/Convert/Single.hs+1−1 src/Language/PureScript/Docs/RenderedCode/Render.hs+1−1 src/Language/PureScript/Errors.hs+14 src/Language/PureScript/Errors/JSON.hs+14−6 src/Language/PureScript/Parser/Common.hs+8 src/Language/PureScript/Parser/Declarations.hs+4−7 src/Language/PureScript/Parser/Types.hs+7−1 src/Language/PureScript/Pretty/Types.hs+1−1 src/Language/PureScript/TypeChecker/Kinds.hs+1−1 src/Language/PureScript/TypeChecker/Unify.hs+2−2 src/Language/PureScript/Types.hs+2−2 tests/Language/PureScript/Ide/FilterSpec.hs+1−1 tests/Language/PureScript/Ide/ImportsSpec.hs+5−2 tests/Language/PureScript/Ide/MatcherSpec.hs+1−1 tests/Language/PureScript/Ide/ReexportsSpec.hs+6−3
src/Language/PureScript/Docs/Convert.hs+4−3
@@ -107,8 +107,9 @@ typeCheckIfNecessary modules convertedModules =
107107 else pure convertedModules
108108
109109 where
110− hasWildcards =
111− any ((==) (ValueDeclaration P.TypeWildcard) . declInfo) . modDeclarations
110+ hasWildcards = any (isWild . declInfo) . modDeclarations
111+ isWild (ValueDeclaration P.TypeWildcard{}) = True
112+ isWild _ = False
112113
113114 go = do
114115 checkEnv <- snd <$> typeCheck modules
@@ -147,7 +148,7 @@ insertValueTypes ::
147148insertValueTypes env m =
148149 m { modDeclarations = map go (modDeclarations m) }
149150 where
150− go (d@Declaration { declInfo = ValueDeclaration P.TypeWildcard }) =
151+ go (d@Declaration { declInfo = ValueDeclaration P.TypeWildcard{} }) =
151152 let
152153 ident = parseIdent (declTitle d)
153154 ty = lookupName ident
src/Language/PureScript/Docs/Convert/Single.hs+1−1
@@ -140,7 +140,7 @@ convertDeclaration (P.ValueDeclaration _ _ _ (Right (P.TypedValue _ _ ty))) titl
140140convertDeclaration (P.ValueDeclaration {}) title =
141141 -- If no explicit type declaration was provided, insert a wildcard, so that
142142 -- the actual type will be added during type checking.
143− basicDeclaration title (ValueDeclaration P.TypeWildcard)
143+ basicDeclaration title (ValueDeclaration P.TypeWildcard{})
144144convertDeclaration (P.ExternDeclaration _ ty) title =
145145 basicDeclaration title (ValueDeclaration ty)
146146convertDeclaration (P.DataDeclaration dtype _ args ctors) title =
src/Language/PureScript/Docs/RenderedCode/Render.hs+1−1
@@ -32,7 +32,7 @@ import Language.PureScript.Docs.Utils.MonoidExtras
3232typeLiterals :: Pattern () Type RenderedCode
3333typeLiterals = mkPattern match
3434 where
35− match TypeWildcard =
35+ match TypeWildcard{} =
3636 Just (syntax "_")
3737 match (TypeVar var) =
3838 Just (ident var)
src/Language/PureScript/Errors.hs+14
@@ -1,6 +1,7 @@
11{-# LANGUAGE GeneralizedNewtypeDeriving #-}
22{-# LANGUAGE FlexibleContexts #-}
33{-# LANGUAGE MultiParamTypeClasses #-}
4+{-# LANGUAGE NamedFieldPuns #-}
45
56module Language.PureScript.Errors where
67
@@ -462,6 +463,8 @@ errorSuggestion err = case err of
462463 ImplicitImport mn refs -> suggest $ importSuggestion mn refs Nothing
463464 ImplicitQualifiedImport mn asModule refs -> suggest $ importSuggestion mn refs (Just asModule)
464465 HidingImport mn refs -> suggest $ importSuggestion mn refs Nothing
466+ MissingTypeDeclaration ident ty -> suggest $ showIdent ident ++ " :: " ++ prettyPrintType ty
467+ WildcardInferredType ty -> suggest $ prettyPrintType ty
465468 _ -> Nothing
466469
467470 where
@@ -476,6 +479,17 @@ errorSuggestion err = case err of
476479 qstr (Just mn) = " as " ++ runModuleName mn
477480 qstr Nothing = ""
478481
482+suggestionSpan :: ErrorMessage -> Maybe SourceSpan
483+suggestionSpan e =
484+ getSpan (unwrapErrorMessage e) <$> errorSpan e
485+ where
486+ startOnly SourceSpan{spanName, spanStart} = SourceSpan {spanName, spanStart, spanEnd = spanStart}
487+
488+ getSpan simple ss =
489+ case simple of
490+ MissingTypeDeclaration{} -> startOnly ss
491+ _ -> ss
492+
479493showSuggestion :: SimpleErrorMessage -> String
480494showSuggestion suggestion = case errorSuggestion suggestion of
481495 Just (ErrorSuggestion x) -> x
src/Language/PureScript/Errors/JSON.hs+14−6
@@ -30,7 +30,10 @@ data ErrorPosition = ErrorPosition
3030 , endColumn :: Int
3131 } deriving (Show, Eq, Ord)
3232
33−data ErrorSuggestion = ErrorSuggestion { replacement :: String } deriving (Show, Eq)
33+data ErrorSuggestion = ErrorSuggestion
34+ { replacement :: String
35+ , replaceRange :: Maybe ErrorPosition
36+ } deriving (Show, Eq)
3437
3538data JSONError = JSONError
3639 { position :: Maybe ErrorPosition
@@ -40,7 +43,7 @@ data JSONError = JSONError
4043 , filename :: Maybe String
4144 , moduleName :: Maybe String
4245 , suggestion :: Maybe ErrorSuggestion
43− } deriving (Show, Eq)
46+ } deriving (Show, Eq)
4447
4548data JSONResult = JSONResult
4649 { warnings :: [JSONError]
@@ -64,7 +67,7 @@ toJSONError verbose level e =
6467 (P.wikiUri e)
6568 (P.spanName <$> sspan)
6669 (P.runModuleName <$> P.errorModule e)
67− (toSuggestion <$> P.errorSuggestion (P.unwrapErrorMessage e))
70+ (toSuggestion e)
6871 where
6972 sspan :: Maybe P.SourceSpan
7073 sspan = P.errorSpan e
@@ -75,6 +78,11 @@ toJSONError verbose level e =
7578 (P.sourcePosColumn (P.spanStart ss))
7679 (P.sourcePosLine (P.spanEnd ss))
7780 (P.sourcePosColumn (P.spanEnd ss))
78− toSuggestion :: P.ErrorSuggestion -> ErrorSuggestion
79−-- TODO: Adding a newline because source spans chomp everything up to the next character
80− toSuggestion (P.ErrorSuggestion s) = ErrorSuggestion $ if null s then s else s ++ "\n"
81+ toSuggestion :: P.ErrorMessage -> Maybe ErrorSuggestion
82+ toSuggestion em =
83+ case P.errorSuggestion $ P.unwrapErrorMessage em of
84+ Nothing -> Nothing
85+ Just s -> Just $ ErrorSuggestion (suggestionText s) (toErrorPosition <$> P.suggestionSpan em)
86+
87+ -- TODO: Adding a newline because source spans chomp everything up to the next character
88+ suggestionText (P.ErrorSuggestion s) = if null s then s else s ++ "\n"
src/Language/PureScript/Parser/Common.hs+8
@@ -13,6 +13,8 @@ import Language.PureScript.Parser.Lexer
1313import Language.PureScript.Parser.State
1414import Language.PureScript.Names
1515
16+import Language.PureScript.AST.SourcePos
17+
1618import qualified Text.Parsec as P
1719
1820properName :: TokenParser (ProperName a)
@@ -120,3 +122,9 @@ readComments = P.lookAhead $ ptComments <$> P.anyToken
120122--
121123runTokenParser :: FilePath -> TokenParser a -> [PositionedToken] -> Either P.ParseError a
122124runTokenParser filePath p = P.runParser p (ParseState 0) filePath
125+
126+-- |
127+-- Convert from Parsec sourcepos
128+--
129+toSourcePos :: P.SourcePos -> SourcePos
130+toSourcePos pos = SourcePos (P.sourceLine pos) (P.sourceColumn pos)
src/Language/PureScript/Parser/Declarations.hs+4−7
@@ -52,7 +52,7 @@ withSourceSpan f p = do
5252 comments <- C.readComments
5353 x <- p
5454 end <- P.getPosition
55− let sp = SourceSpan (P.sourceName start) (toSourcePos start) (toSourcePos end)
55+ let sp = SourceSpan (P.sourceName start) (C.toSourcePos start) (C.toSourcePos end)
5656 return $ f sp comments x
5757
5858kindedIdent :: TokenParser (String, Maybe Kind)
@@ -248,7 +248,7 @@ parseModule = do
248248 reserved "where"
249249 decls <- mark (P.many (same *> parseDeclaration))
250250 end <- P.getPosition
251− let ss = SourceSpan (P.sourceName start) (toSourcePos start) (toSourcePos end)
251+ let ss = SourceSpan (P.sourceName start) (C.toSourcePos start) (C.toSourcePos end)
252252 return $ Module ss comments name decls exports
253253
254254-- | Parse a collection of modules in parallel
@@ -275,13 +275,10 @@ parseModulesFromFiles toFilePath input = do
275275toPositionedError :: P.ParseError -> ErrorMessage
276276toPositionedError perr = ErrorMessage [ PositionedError (SourceSpan name start end) ] (ErrorParsingModule perr)
277277 where
278− name = (P.sourceName . P.errorPos) perr
279− start = (toSourcePos . P.errorPos) perr
278+ name = (P.sourceName . P.errorPos) perr
279+ start = (C.toSourcePos . P.errorPos) perr
280280 end = start
281281
282−toSourcePos :: P.SourcePos -> SourcePos
283−toSourcePos pos = SourcePos (P.sourceLine pos) (P.sourceColumn pos)
284−
285282-- |
286283-- Parse a collection of modules
287284--
src/Language/PureScript/Parser/Types.hs+7−1
@@ -15,6 +15,8 @@ import Language.PureScript.Parser.Kinds
1515import Language.PureScript.Parser.Lexer
1616import Language.PureScript.Environment
1717
18+import Language.PureScript.AST.SourcePos
19+
1820import qualified Text.Parsec as P
1921import qualified Text.Parsec.Expr as P
2022
@@ -25,7 +27,11 @@ parseObject :: TokenParser Type
2527parseObject = braces $ TypeApp tyObject <$> parseRow
2628
2729parseTypeWildcard :: TokenParser Type
28−parseTypeWildcard = underscore >> return TypeWildcard
30+parseTypeWildcard = do
31+ start <- P.getPosition
32+ let end = P.incSourceColumn start 1
33+ underscore
34+ return $ TypeWildcard (SourceSpan (P.sourceName start) (toSourcePos start) (toSourcePos end))
2935
3036parseTypeVariable :: TokenParser Type
3137parseTypeVariable = do
src/Language/PureScript/Pretty/Types.hs+1−1
@@ -28,7 +28,7 @@ import Text.PrettyPrint.Boxes hiding ((<+>))
2828typeLiterals :: Pattern () Type Box
2929typeLiterals = mkPattern match
3030 where
31− match TypeWildcard = Just $ text "_"
31+ match TypeWildcard{} = Just $ text "_"
3232 match (TypeVar var) = Just $ text var
3333 match (PrettyPrintObject row) = Just $ prettyPrintRowWith '{' '}' row
3434 match (TypeConstructor ctor) = Just $ text $ runProperName $ disqualify ctor
src/Language/PureScript/TypeChecker/Kinds.hs+1−1
@@ -235,7 +235,7 @@ infer' other = (, []) <$> go other
235235 k' <- go ty
236236 unifyKinds k k'
237237 return k'
238− go TypeWildcard = freshKind
238+ go TypeWildcard{} = freshKind
239239 go (TypeVar v) = do
240240 Just moduleName <- checkCurrentModule <$> get
241241 lookupTypeVariable moduleName (Qualified Nothing (ProperName v))
src/Language/PureScript/TypeChecker/Unify.hs+2−2
@@ -209,9 +209,9 @@ replaceVarWithUnknown ident ty = do
209209replaceTypeWildcards :: (MonadWriter MultipleErrors m, MonadState CheckState m) => Type -> m Type
210210replaceTypeWildcards = everywhereOnTypesM replace
211211 where
212− replace TypeWildcard = do
212+ replace (TypeWildcard ss) = do
213213 t <- freshType
214− tell . errorMessage $ WildcardInferredType t
214+ warnWithPosition ss $ tell . errorMessage $ WildcardInferredType t
215215 return t
216216 replace other = return other
217217
src/Language/PureScript/Types.hs+2−2
@@ -43,7 +43,7 @@ data Type
4343 -- |
4444 -- A type wildcard, as would appear in a partial type synonym
4545 --
46− | TypeWildcard
46+ | TypeWildcard (SourceSpan)
4747 -- |
4848 -- A type constructor
4949 --
@@ -237,7 +237,7 @@ containsWildcards :: Type -> Bool
237237containsWildcards = everythingOnTypes (||) go
238238 where
239239 go :: Type -> Bool
240− go TypeWildcard = True
240+ go TypeWildcard{} = True
241241 go _ = False
242242
243243--
tests/Language/PureScript/Ide/FilterSpec.hs+1−1
@@ -8,7 +8,7 @@ import qualified Language.PureScript as P
88import Test.Hspec
99
1010value :: Text -> ExternDecl
11−value s = ValueDeclaration s P.TypeWildcard
11+value s = ValueDeclaration s $ P.TypeWildcard $ P.SourceSpan "" (P.SourcePos 0 0) (P.SourcePos 0 0)
1212
1313modules :: [Module]
1414modules =
tests/Language/PureScript/Ide/ImportsSpec.hs+5−2
@@ -36,6 +36,9 @@ listImport = testParseImport "import Data.List as List"
3636consoleImport = testParseImport "import Control.Monad.Eff.Console (log) as Console"
3737maybeImport = testParseImport "import Data.Maybe (Maybe(Just))"
3838
39+wildcard :: P.Type
40+wildcard = P.TypeWildcard $ P.SourceSpan "" (P.SourcePos 0 0) (P.SourcePos 0 0)
41+
3942spec :: Spec
4043spec = do
4144 describe "determining the importsection" $ do
@@ -65,9 +68,9 @@ spec = do
6568 describe "import commands" $ do
6669 let simpleFileImports = let (_, _, i, _) = splitSimpleFile in i
6770 addValueImport i mn is =
68− prettyPrintImportSection (addExplicitImport' (ValueDeclaration i P.TypeWildcard) mn is)
71+ prettyPrintImportSection (addExplicitImport' (ValueDeclaration i wildcard) mn is)
6972 addDtorImport i t mn is =
70− prettyPrintImportSection (addExplicitImport' (DataConstructor i t P.TypeWildcard) mn is)
73+ prettyPrintImportSection (addExplicitImport' (DataConstructor i t wildcard) mn is)
7174 it "adds an implicit unqualified import" $
7275 shouldBe
7376 (addImplicitImport' simpleFileImports (P.moduleNameFromString "Data.Map"))
tests/Language/PureScript/Ide/MatcherSpec.hs+1−1
@@ -10,7 +10,7 @@ import qualified Language.PureScript as P
1010import Test.Hspec
1111
1212value :: Text -> ExternDecl
13−value s = ValueDeclaration s P.TypeWildcard
13+value s = ValueDeclaration s $ P.TypeWildcard $ P.SourceSpan "" (P.SourcePos 0 0) (P.SourcePos 0 0)
1414
1515completions :: [Match]
1616completions = [
tests/Language/PureScript/Ide/ReexportsSpec.hs+6−3
@@ -9,12 +9,15 @@ import Language.PureScript.Ide.Types
99import qualified Language.PureScript as P
1010import Test.Hspec
1111
12+wildcard :: P.Type
13+wildcard = P.TypeWildcard $ P.SourceSpan "" (P.SourcePos 0 0) (P.SourcePos 0 0)
14+
1215decl1 :: ExternDecl
13−decl1 = ValueDeclaration "filter" P.TypeWildcard
16+decl1 = ValueDeclaration "filter" wildcard
1417decl2 :: ExternDecl
15−decl2 = ValueDeclaration "map" P.TypeWildcard
18+decl2 = ValueDeclaration "map" wildcard
1619decl3 :: ExternDecl
17−decl3 = ValueDeclaration "catMaybe" P.TypeWildcard
20+decl3 = ValueDeclaration "catMaybe" wildcard
1821dep1 :: ExternDecl
1922dep1 = Dependency "Test.Foo" [] (Just "T")
2023dep2 :: ExternDecl