{-# OPTIONS_GHC -Wall #-} module Nitpick.TopLevelTypes (topLevelTypes) where import Prelude hiding (maybe) import qualified Data.Foldable as F import qualified Data.Map as Map import qualified AST.Expression.Valid as Valid import qualified AST.Declaration as Decl import qualified AST.Module.Name as ModuleName import qualified AST.Pattern as P import qualified AST.Type as Type import qualified AST.Variable as Var import qualified Elm.Package as Pkg import qualified Reporting.Annotation as A import qualified Reporting.Error.Type as Error import qualified Reporting.Result as Result import qualified Reporting.Warning as Warning topLevelTypes :: Map.Map String Type.Canonical -> [Decl.ValidDecl] -> Result.Result Warning.Warning Error.Error () topLevelTypes typeEnv validDecls = do F.traverse_ (warnMissingAnnotation typeEnv) validDecls checkMainType typeEnv validDecls -- MISSING ANNOTATIONS warnMissingAnnotation :: Map.Map String Type.Canonical -> Decl.ValidDecl -> Result.Result Warning.Warning Error.Error () warnMissingAnnotation typeEnv (A.A (region,_) decl) = case decl of Decl.Definition (Valid.Definition (A.A _ (P.Var name)) _ Nothing) -> case Map.lookup name typeEnv of Nothing -> return () Just tipe -> Result.warn region (Warning.MissingTypeAnnotation name tipe) _ -> return () -- MAIN TYPE checkMainType :: Map.Map String Type.Canonical -> [Decl.ValidDecl] -> Result.Result w Error.Error () checkMainType typeEnv decls = case decls of A.A (region,_) (Decl.Definition (Valid.Definition (A.A _ (P.Var "main")) _ _)) : _ -> case Map.lookup "main" typeEnv of Nothing -> return () Just typeOfMain -> let tipe = Type.deepDealias typeOfMain in if tipe `elem` validMainTypes then return () else Result.throw region (Error.BadMain typeOfMain) _ : remainingDecls -> checkMainType typeEnv remainingDecls [] -> return () validMainTypes :: [Type.Canonical] validMainTypes = [ element , html , signal element , signal html ] html :: Type.Canonical html = Type.Type (Var.fromModule virtualDom "Node") virtualDom :: ModuleName.Canonical virtualDom = ModuleName.Canonical (Pkg.Name "evancz" "virtual-dom") ["VirtualDom"] element :: Type.Canonical element = core ["Graphics","Element"] "Element" signal :: Type.Canonical -> Type.Canonical signal tipe = Type.App (core ["Signal"] "Signal") [ tipe ] core :: [String] -> String -> Type.Canonical core home name = Type.Type (Var.inCore home name)