{- | Module : $Header$ Description : Different checks on a Curry module Copyright : (c) 2011 - 2013 Björn Peemöller 2016 - 2017 Finn Teegen License : BSD-3-clause Maintainer : bjp@informatik.uni-kiel.de Stability : experimental Portability : portable This module subsumes the different checks to be performed on a Curry module during compilation, e.g. type checking. -} module Checks where import qualified Checks.InstanceCheck as INC (instanceCheck) import qualified Checks.InterfaceCheck as IC (interfaceCheck) import qualified Checks.ImportSyntaxCheck as ISC (importCheck) import qualified Checks.DeriveCheck as DC (deriveCheck) import qualified Checks.ExportCheck as EC (exportCheck, expandExports) import qualified Checks.ExtensionCheck as EXC (extensionCheck) import qualified Checks.KindCheck as KC (kindCheck) import qualified Checks.PrecCheck as PC (precCheck) import qualified Checks.SyntaxCheck as SC (syntaxCheck) import qualified Checks.TypeCheck as TC (typeCheck) import qualified Checks.TypeSyntaxCheck as TSC (typeSyntaxCheck) import qualified Checks.WarnCheck as WC (warnCheck) import Curry.Base.Monad import Curry.Syntax (Module (..), Interface (..), ImportSpec) import Base.Messages import Base.Types import CompilerEnv import CompilerOpts type Check m a = Options -> CompEnv a -> CYT m (CompEnv a) interfaceCheck :: Monad m => Check m Interface interfaceCheck _ (env, intf) | null msgs = ok (env, intf) | otherwise = failMessages msgs where msgs = IC.interfaceCheck (opPrecEnv env) (tyConsEnv env) (classEnv env) (instEnv env) (valueEnv env) intf importCheck :: Monad m => Interface -> Maybe ImportSpec -> CYT m (Maybe ImportSpec) importCheck intf is | null msgs = ok is' | otherwise = failMessages msgs where (is', msgs) = ISC.importCheck intf is -- |Check for enabled language extensions. -- -- * Declarations: remain unchanged -- * Environment: The enabled language extensions are updated extensionCheck :: Monad m => Check m (Module a) extensionCheck opts (env, mdl) | null msgs = ok (env { extensions = exts }, mdl) | otherwise = failMessages msgs where (exts, msgs) = EXC.extensionCheck opts mdl -- |Check the type syntax of type definitions and signatures. -- -- * Declarations: Nullary type constructors and type variables are -- disambiguated -- * Environment: remains unchanged typeSyntaxCheck :: Monad m => Check m (Module a) typeSyntaxCheck _ (env, mdl) | null msgs = ok (env { extensions = exts }, mdl') | otherwise = failMessages msgs where ((mdl', exts), msgs) = TSC.typeSyntaxCheck (extensions env) (tyConsEnv env) mdl -- |Check the kinds of type definitions and signatures. -- -- * Declarations: remain unchanged -- * Environment: The type constructor and class environment are updated kindCheck :: Monad m => Check m (Module a) kindCheck _ (env, mdl) | null msgs = ok (env { tyConsEnv = tcEnv', classEnv = clsEnv' }, mdl) | otherwise = failMessages msgs where ((tcEnv', clsEnv'), msgs) = KC.kindCheck (tyConsEnv env) (classEnv env) mdl -- |Check for a correct syntax. -- -- * Declarations: Nullary data constructors and variables are -- disambiguated, variables are renamed -- * Environment: remains unchanged syntaxCheck :: Monad m => Check m (Module ()) syntaxCheck _ (env, mdl) | null msgs = ok (env { extensions = exts }, mdl') | otherwise = failMessages msgs where ((mdl', exts), msgs) = SC.syntaxCheck (extensions env) (tyConsEnv env) (valueEnv env) mdl -- |Check the precedences of infix operators. -- -- * Declarations: Expressions are reordered according to the specified -- precedences -- * Environment: The operator precedence environment is updated precCheck :: Monad m => Check m (Module a) precCheck _ (env, Module spi ps m es is ds) | null msgs = ok (env { opPrecEnv = pEnv' }, Module spi ps m es is ds') | otherwise = failMessages msgs where (ds', pEnv', msgs) = PC.precCheck (moduleIdent env) (opPrecEnv env) ds -- |Check the deriving clauses. -- -- * Declarations: remain unchanged -- * Environment: remain unchanged deriveCheck :: Monad m => Check m (Module a) deriveCheck _ (env, mdl) = case DC.deriveCheck (tyConsEnv env) mdl of msgs | null msgs -> ok (env, mdl) | otherwise -> failMessages msgs -- |Check the instances. -- -- * Declarations: remain unchanged -- * Environment: The instance environment is updated instanceCheck :: Monad m => Check m (Module a) instanceCheck _ (env, Module spi ps m es is ds) | null msgs = ok (env { instEnv = inEnv' }, Module spi ps m es is ds) | otherwise = failMessages msgs where (inEnv', msgs) = INC.instanceCheck (moduleIdent env) (tyConsEnv env) (classEnv env) (instEnv env) ds -- |Apply the correct typing of the module. -- -- * Declarations: Type annotations are added to all expressions. -- * Environment: The value environment is updated. typeCheck :: Monad m => Options -> CompEnv (Module a) -> CYT m (CompEnv (Module PredType)) typeCheck _ (env, Module spi ps m es is ds) | null msgs = ok (env { valueEnv = vEnv' }, Module spi ps m es is ds') | otherwise = failMessages msgs where (ds', vEnv', msgs) = TC.typeCheck (moduleIdent env) (tyConsEnv env) (valueEnv env) (classEnv env) (instEnv env) ds -- |Check the export specification exportCheck :: Monad m => Check m (Module a) exportCheck _ (env, mdl@(Module _ _ _ es _ _)) | null msgs = ok (env, mdl) | otherwise = failMessages msgs where msgs = EC.exportCheck (moduleIdent env) (aliasEnv env) (tyConsEnv env) (valueEnv env) es -- |Check the export specification expandExports :: Monad m => Options -> CompEnv (Module a) -> m (CompEnv (Module a)) expandExports _ (env, Module spi ps m es is ds) = return (env, Module spi ps m (Just es') is ds) where es' = EC.expandExports (moduleIdent env) (aliasEnv env) (tyConsEnv env) (valueEnv env) es -- |Check for warnings. warnCheck :: Options -> CompilerEnv -> Module a -> [Message] warnCheck opts env mdl = WC.warnCheck (optWarnOpts opts) (optCaseMode opts) (aliasEnv env) (valueEnv env) (tyConsEnv env) (classEnv env) mdl