1{-# OPTIONS_GHC -Wall #-}
2module Validate (module') where
4import Control.Monad (foldM, when)
5import qualified Data.Map as Map
6import qualified Data.Set as Set
7import qualified Data.Foldable as F
8import qualified Data.Traversable as T
10import AST.Expression.General as Expr
11import qualified AST.Effects as Fx
12import qualified AST.Expression.Source as Source
13import qualified AST.Expression.Valid as Valid
14import qualified AST.Declaration as D
15import qualified AST.Module as Module
16import qualified AST.Module.Name as ModuleName
17import qualified AST.Pattern as Pattern
18import qualified AST.Type as Type
19import qualified Elm.Compiler.Imports as Imports
20import qualified Elm.Package as Package
21import Elm.Utils ((|>))
22import qualified Reporting.Annotation as A
23import qualified Reporting.Error.Syntax as Error
24import qualified Reporting.Region as R
25import qualified Reporting.Result as Result
32module' :: Module.Source -> Result.Result wrn Error.Error Module.Valid
33module' (Module.Module name path info) =
35 (ModuleName.Canonical pkgName _) =
38 (Module.Source tag settings docs exports imports decls) =
41 do validDecls <- declarations decls
42 validEffects <- validateEffects tag settings validDecls
44 return $ Module.Module name path $
45 Module.Valid docs exports (addDefaults pkgName imports) validDecls validEffects
54 -> [Module.UserImport]
55 -> ([Module.DefaultImport], [Module.UserImport])
56addDefaults pkgName imports =
58 if pkgName == Package.coreName then
71 -> Module.SourceSettings
73 -> Result.Result wrn Error.Error Fx.Effects
74validateEffects tag settings@(A.A _ pairs) decls =
77 do noSettings Error.SettingsOnNormalModule settings
81 do noSettings Error.SettingsOnForeignModule settings
84 Module.Effect tagRegion ->
86 collectSettings (A.A region setting, userValue) dict =
87 Map.insertWith (++) setting [(region, userValue)] dict
90 foldr collectSettings Map.empty pairs
92 do managerType <- toManagerType tagRegion settingsDict
93 (r0, r1, r2) <- checkManagerImpl tagRegion managerType noInfo decls
94 return (Fx.Effect (Fx.Info tagRegion r0 r1 r2 managerType))
99 -> Module.SourceSettings
100 -> Result.Result wrn Error.Error ()
101noSettings errorMsg (A.A region settings) =
107 Result.throw region errorMsg
112 -> Map.Map String [(R.Region, A.Located String)]
113 -> Result.Result wrn Error.Error Fx.ManagerType
114toManagerType tagRegion settingsDict =
116 toErrors name entries =
117 map (\entry -> A.A (fst entry) (Error.BadSettingOnEffectModule name)) entries
121 |> Map.delete "command"
122 |> Map.delete "subscription"
123 |> Map.mapWithKey toErrors
127 do when (not (null errors)) (Result.throwMany errors)
129 (,) <$> extractOne "command" settingsDict
130 <*> extractOne "subscription" settingsDict
133 (Nothing, Nothing) ->
134 Result.throw tagRegion Error.NoSettingsOnEffectModule
136 (Just cmd, Nothing) ->
137 return (Fx.CmdManager cmd)
139 (Nothing, Just sub) ->
140 return (Fx.SubManager sub)
142 (Just cmd, Just sub) ->
143 return (Fx.FxManager cmd sub)
148 -> Map.Map String [(R.Region, A.Located String)]
149 -> Result.Result w Error.Error (Maybe (A.Located String))
150extractOne name settingsDict =
151 case Map.lookup name settingsDict of
156 error "Empty lists should never be added to the dictionary of effect module settings."
158 Just [(_, userType)] ->
159 return (Just userType)
161 Just ((region, _) : _) ->
162 Result.throw region (Error.DuplicateSettingOnEffectModule name)
173 , _init :: Maybe R.Region
174 , _onEffects :: Maybe R.Region
175 , _onSelfMsg :: Maybe R.Region
181 ManagerInfo False False Nothing Nothing Nothing
189 -> Result.Result w Error.Error (R.Region, R.Region, R.Region)
190checkManagerImpl tagRegion managerType info decls =
194 (ManagerInfo cmdMap subMap init onEffects onSelfMsg) = info
197 <$> requireMaps tagRegion managerType cmdMap subMap
198 <*> requireRegion tagRegion "init" init
199 <*> requireRegion tagRegion "onEffects" onEffects
200 <*> requireRegion tagRegion "onSelfMsg" onSelfMsg
203 case getDefInfo decl of
204 Just ("init", region) ->
205 checkManagerImpl tagRegion managerType (info { _init = Just region }) rest
207 Just ("onEffects", region) ->
208 checkManagerImpl tagRegion managerType (info { _onEffects = Just region }) rest
210 Just ("onSelfMsg", region) ->
211 checkManagerImpl tagRegion managerType (info { _onSelfMsg = Just region }) rest
213 Just ("cmdMap", _) ->
214 checkManagerImpl tagRegion managerType (info { _cmdMap = True }) rest
216 Just ("subMap", _) ->
217 checkManagerImpl tagRegion managerType (info { _subMap = True }) rest
220 checkManagerImpl tagRegion managerType info rest
223getDefInfo :: D.Valid -> Maybe (String, R.Region)
226 A.A region (D.Def (Valid.Definition (A.A _ (Pattern.Var name)) _ _)) ->
227 Just (name, fst region)
233requireMaps :: R.Region -> Fx.ManagerType -> Bool -> Bool -> Result.Result w Error.Error ()
234requireMaps tagRegion managerType hasCmdMap hasSubMap =
237 when (not hasIt) (Result.throw tagRegion (Error.MissingManagerOnEffectModule name))
241 check hasCmdMap "cmdMap"
244 check hasSubMap "subMap"
248 <$> check hasCmdMap "cmdMap"
249 <*> check hasSubMap "subMap"
252requireRegion :: R.Region -> String -> Maybe R.Region -> Result.Result w Error.Error R.Region
253requireRegion tagRegion name maybeRegion =
259 Result.throw tagRegion (Error.MissingManagerOnEffectModule name)
267 A.Annotated (R.Region, Maybe (A.Located String)) a
271 :: [D.CommentOr (A.Located a)]
272 -> Result.Result wrn Error.Error [Commented a]
273collapseComments listWithComments =
274 case listWithComments of
278 D.Comment msg : D.Whatever (A.A region a) : rest ->
281 A.A (region, Just msg) a
283 fmap (entry:) (collapseComments rest)
285 D.Comment (A.A region _) : D.Comment _ : _ ->
286 Result.throw region Error.CommentOnComment
288 [D.Comment (A.A region _)] ->
289 Result.throw region Error.CommentOnNothing
291 D.Whatever (A.A region a) : rest ->
294 A.A (region, Nothing) a
296 fmap (entry:) (collapseComments rest)
300-- VALIDATE STRUCTURED SOURCE
303declarations :: [D.Source] -> Result.Result wrn Error.Error [D.Valid]
304declarations sourceDecls =
306 collapseComments sourceDecls
312 (declDuplicates validDecls : map findBadTypeVars validDecls)
318-- VALIDATE DECLARATIONS
322 :: [Commented D.Source']
323 -> Result.Result wrn Error.Error [D.Valid]
324validateDecls commentedDecls =
325 case commentedDecls of
329 A.A (region, maybeComment) decl : rest ->
334 A.A (region, fmap A.drop maybeComment) validDecl
336 fmap (entry:) (validateDecls rest)
339 D.Union name tvars ctors ->
340 addRest (D.Union name tvars ctors)
342 D.Alias name tvars alias ->
343 addRest (D.Alias name tvars alias)
345 D.Fixity assoc prec op ->
346 addRest (D.Fixity assoc prec op)
349 validateDeclsHelp maybeComment def rest
353 :: Maybe (A.Located String)
355 -> [Commented D.Source']
356 -> Result.Result wrn Error.Error [D.Valid]
357validateDeclsHelp maybeComment (A.A region def) decls =
360 (region, fmap A.drop maybeComment)
362 makeDef pat expr maybeType =
363 D.Def (Valid.Definition pat expr maybeType)
366 Source.Definition pat expr ->
368 <$> validateDef makeDef ann pat expr Nothing
369 <*> validateDecls decls
371 Source.Annotation name tipe ->
373 A.A (_, Just (A.A commentRegion _)) _ : _ ->
374 Result.throw commentRegion (Error.CommentAfterAnnotation name)
376 A.A _ (D.Def (A.A _ (Source.Definition pat expr))) : rest
377 | Pattern.isVar name pat ->
379 <$> validateDef makeDef ann pat expr (Just tipe)
380 <*> validateDecls rest
383 Result.throw region (Error.TypeWithoutDefinition name)
387-- VALIDATE DEFINITIONS
390definitions :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
391definitions sourceDefs =
392 do validDefs <- definitionsHelp sourceDefs
393 let patterns = map (\(Valid.Definition p _ _) -> p) validDefs
394 defDuplicates patterns
398definitionsHelp :: [Source.Def] -> Result.Result wrn Error.Error [Valid.Def]
399definitionsHelp sourceDefs =
404 A.A region (Source.Definition pat expr) : rest ->
406 <$> fmap A.drop (validateDef Valid.Definition region pat expr Nothing)
407 <*> definitionsHelp rest
409 A.A r1 (Source.Annotation name tipe) : rest ->
411 A.A r2 (Source.Definition pat expr) : rest'
412 | Pattern.isVar name pat ->
414 <$> fmap A.drop (validateDef Valid.Definition (R.merge r1 r2) pat expr (Just tipe))
415 <*> definitionsHelp rest'
418 Result.throw r1 (Error.TypeWithoutDefinition name)
422 :: (Pattern.Raw -> Valid.Expr -> Maybe Type.Raw -> def)
427 -> Result.Result wrn Error.Error (A.Annotated annotation def)
428validateDef makeDef annotation pat expr maybeType =
429 do validExpr <- expression expr
430 validateDefPattern pat validExpr
431 return $ A.A annotation (makeDef pat validExpr maybeType)
434validateDefPattern :: Pattern.Raw -> Valid.Expr -> Result.Result wrn Error.Error ()
435validateDefPattern pattern body =
436 case fst (Expr.collectLambdas body) of
442 A.A _ (Pattern.Var _) ->
447 (A.A start _) = pattern
448 (A.A end _) = last args
450 Result.throw (R.merge start end) (Error.BadFunctionName (length args))
454-- VALIDATE EXPRESSIONS
457expression :: Source.Expr -> Result.Result wrn Error.Error Valid.Expr
458expression (A.A ann sourceExpression) =
460 case sourceExpression of
464 Lambda pattern body ->
466 <$> validatePattern pattern
469 Binop op leftExpr rightExpr ->
471 <$> expression leftExpr
472 <*> expression rightExpr
477 <*> T.traverse (\(p,b) -> (,) <$> validatePattern p <*> expression b) branches
480 Data name <$> T.traverse expression args
485 Range lowExpr highExpr ->
487 <$> expression lowExpr
488 <*> expression highExpr
490 ExplicitList expressions ->
492 <$> T.traverse expression expressions
494 App funcExpr argExpr ->
496 <$> expression funcExpr
497 <*> expression argExpr
499 If branches finally ->
501 <$> T.traverse both branches
502 <*> expression finally
504 Access record field ->
506 <$> expression record
509 Update record fields ->
511 <$> expression record
512 <*> T.traverse second fields
516 checkDups seenFields (field,_) =
517 if Set.member field seenFields then
518 Result.throw ann (Error.DuplicateFieldName field)
521 return (Set.insert field seenFields)
523 do _ <- foldM checkDups Set.empty fields
524 Record <$> T.traverse second fields
531 Cmd moduleName typeName ->
532 return (Cmd moduleName typeName)
534 Sub moduleName typeName ->
535 return (Sub moduleName typeName)
537 SaveEnv moduleName effects ->
538 return (SaveEnv moduleName effects)
540 GLShader uid src gltipe ->
541 return (GLShader uid src gltipe)
544second :: (a, Source.Expr) -> Result.Result wrn Error.Error (a, Valid.Expr)
545second (value, expr) =
546 (,) value <$> expression expr
550 :: (Source.Expr, Source.Expr)
551 -> Result.Result wrn Error.Error (Valid.Expr, Valid.Expr)
553 (,) <$> expression expr1 <*> expression expr2
560validatePattern :: Pattern.Raw -> Result.Result wrn Error.Error Pattern.Raw
561validatePattern pattern =
562 do detectDuplicates Error.BadPattern (Pattern.boundVars pattern)
571 :: (String -> Error.Error)
572 -> [A.Located String]
573 -> Result.Result wrn Error.Error ()
574detectDuplicates tag names =
575 let add (A.A region name) dict =
576 Map.insertWith (++) name [region] dict
579 Map.toList (foldr add Map.empty pairs)
581 check (name, regions) =
584 Result.throw region (tag name)
589 F.traverse_ check (makeGroups names)
592defDuplicates :: [Pattern.Raw] -> Result.Result wrn Error.Error ()
593defDuplicates patterns =
594 concatMap Pattern.boundVars patterns
595 |> detectDuplicates Error.DuplicateDefinition
598declDuplicates :: [D.Valid] -> Result.Result wrn Error.Error ()
599declDuplicates decls =
601 (valueLists, typeLists) =
602 unzip (map extractValues decls)
605 <$> detectDuplicates Error.DuplicateValueDeclaration (concat valueLists)
606 <*> detectDuplicates Error.DuplicateTypeDeclaration (concat typeLists)
609extractValues :: D.Valid -> ([A.Located String], [A.Located String])
610extractValues (A.A (region, _) decl) =
612 D.Def (Valid.Definition pattern _ _) ->
613 ( Pattern.boundVars pattern
617 D.Union name _ ctors ->
618 ( map (A.A region . fst) ctors
622 D.Alias name _ (A.A _ (Type.RRecord _ _)) ->
639-- UNBOUND TYPE VARIABLES
642findBadTypeVars :: D.Valid -> Result.Result wrn Error.Error ()
643findBadTypeVars (A.A (region,_) decl) =
648 D.Union name boundVars ctors ->
649 case diff boundVars (concatMap freeVars (concatMap snd ctors)) of
655 (Error.UnboundTypeVarsInUnion name boundVars unbound)
657 D.Alias name boundVars tipe ->
658 case diff boundVars (freeVars tipe) of
664 (Error.UnboundTypeVarsInAlias name boundVars unbound)
668 (Error.UnusedTypeVarsInAlias name boundVars unused)
672 (Error.MessyTypeVarsInAlias name boundVars unused unbound)
678diff :: [String] -> [A.Located String] -> ([String], [String])
685 Set.fromList (map A.drop right)
687 ( Set.toList (Set.difference leftSet rightSet)
688 , Set.toList (Set.difference rightSet leftSet)
693freeVars :: Type.Raw -> [A.Located String]
694freeVars (A.A region tipe) =
696 Type.RLambda t1 t2 ->
697 freeVars t1 ++ freeVars t2
706 concatMap freeVars (t:ts)
708 Type.RRecord fields ext ->
709 maybe [] freeVars ext
710 ++ concatMap (freeVars . snd) fields
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list