purescript-0.15.15: src/Language/PureScript/Sugar/TypeDeclarations.hs
-- |
-- This module implements the desugaring pass which replaces top-level type
-- declarations with type annotations on the corresponding expression.
--
module Language.PureScript.Sugar.TypeDeclarations
( desugarTypeDeclarationsModule
) where
import Prelude
import Control.Monad (unless)
import Control.Monad.Error.Class (MonadError(..))
import Language.PureScript.AST (Declaration(..), ErrorMessageHint(..), Expr(..), GuardedExpr(..), KindSignatureFor(..), pattern MkUnguarded, Module(..), RoleDeclarationData(..), TypeDeclarationData(..), TypeInstanceBody(..), pattern ValueDecl, declSourceSpan, everywhereOnValuesTopDownM)
import Language.PureScript.Names (Ident, coerceProperName)
import Language.PureScript.Environment (DataDeclType(..), NameKind)
import Language.PureScript.Errors (MultipleErrors, SimpleErrorMessage(..), addHint, errorMessage', rethrow)
-- |
-- Replace all top level type declarations in a module with type annotations
--
desugarTypeDeclarationsModule
:: forall m
. MonadError MultipleErrors m
=> Module
-> m Module
desugarTypeDeclarationsModule (Module modSS coms name ds exps) =
rethrow (addHint (ErrorInModule name)) $ do
checkKindDeclarations ds
checkRoleDeclarations Nothing ds
Module modSS coms name <$> desugarTypeDeclarations ds <*> pure exps
where
desugarTypeDeclarations :: [Declaration] -> m [Declaration]
desugarTypeDeclarations (TypeDeclaration (TypeDeclarationData sa name' ty) : d : rest) = do
(_, nameKind, val) <- fromValueDeclaration d
desugarTypeDeclarations (ValueDecl sa name' nameKind [] [MkUnguarded (TypedValue True val ty)] : rest)
where
fromValueDeclaration :: Declaration -> m (Ident, NameKind, Expr)
fromValueDeclaration (ValueDecl _ name'' nameKind [] [MkUnguarded val])
| name' == name'' = return (name'', nameKind, val)
fromValueDeclaration d' =
throwError . errorMessage' (declSourceSpan d') $ OrphanTypeDeclaration name'
desugarTypeDeclarations [TypeDeclaration (TypeDeclarationData (ss, _) name' _)] =
throwError . errorMessage' ss $ OrphanTypeDeclaration name'
desugarTypeDeclarations (ValueDecl sa name' nameKind bs val : rest) = do
let (_, f, _) = everywhereOnValuesTopDownM return go return
f' = mapM (\(GuardedExpr g e) -> GuardedExpr g <$> f e)
(:) <$> (ValueDecl sa name' nameKind bs <$> f' val)
<*> desugarTypeDeclarations rest
where
go (Let w ds' val') = Let w <$> desugarTypeDeclarations ds' <*> pure val'
go other = return other
desugarTypeDeclarations (TypeInstanceDeclaration sa na ch idx nm deps cls args (ExplicitInstance ds') : rest) =
(:) <$> (TypeInstanceDeclaration sa na ch idx nm deps cls args . ExplicitInstance <$> desugarTypeDeclarations ds')
<*> desugarTypeDeclarations rest
desugarTypeDeclarations (d:rest) = (:) d <$> desugarTypeDeclarations rest
desugarTypeDeclarations [] = return []
checkKindDeclarations :: [Declaration] -> m ()
checkKindDeclarations (KindDeclaration sa kindFor name' _ : d : rest) = do
unless (matchesDeclaration d) . throwError . errorMessage' (fst sa) $ OrphanKindDeclaration name'
checkKindDeclarations rest
where
matchesDeclaration :: Declaration -> Bool
matchesDeclaration (DataDeclaration _ Data name'' _ _) = kindFor == DataSig && name' == name''
matchesDeclaration (DataDeclaration _ Newtype name'' _ _) = kindFor == NewtypeSig && name' == name''
matchesDeclaration (TypeSynonymDeclaration _ name'' _ _) = kindFor == TypeSynonymSig && name' == name''
matchesDeclaration (TypeClassDeclaration _ name'' _ _ _ _) = kindFor == ClassSig && name' == coerceProperName name''
matchesDeclaration _ = False
checkKindDeclarations (KindDeclaration sa _ name' _ : _) = do
throwError . errorMessage' (fst sa) $ OrphanKindDeclaration name'
checkKindDeclarations (_ : rest) = checkKindDeclarations rest
checkKindDeclarations [] = return ()
checkRoleDeclarations :: Maybe Declaration -> [Declaration] -> m ()
checkRoleDeclarations Nothing (RoleDeclaration RoleDeclarationData{..} : _) =
throwError . errorMessage' (fst rdeclSourceAnn) $ OrphanRoleDeclaration rdeclIdent
checkRoleDeclarations (Just (RoleDeclaration (RoleDeclarationData _ name' _))) ((RoleDeclaration RoleDeclarationData{..}) : _) | name' == rdeclIdent =
throwError . errorMessage' (fst rdeclSourceAnn) $ DuplicateRoleDeclaration rdeclIdent
checkRoleDeclarations (Just d) (rd@(RoleDeclaration RoleDeclarationData{..}) : rest) = do
unless (matchesDeclaration d) . throwError . errorMessage' (fst rdeclSourceAnn) $ OrphanRoleDeclaration rdeclIdent
unless (isSupported d) . throwError . errorMessage' (fst rdeclSourceAnn) $ UnsupportedRoleDeclaration
checkRoleDeclarations (Just rd) rest
where
isSupported :: Declaration -> Bool
isSupported DataDeclaration{} = True
isSupported ExternDataDeclaration{} = True
isSupported _ = False
matchesDeclaration :: Declaration -> Bool
matchesDeclaration (DataDeclaration _ _ name' _ _) = rdeclIdent == name'
matchesDeclaration (ExternDataDeclaration _ name' _) = rdeclIdent == name'
matchesDeclaration (TypeSynonymDeclaration _ name' _ _) = rdeclIdent == name'
matchesDeclaration (TypeClassDeclaration _ name' _ _ _ _) = rdeclIdent == coerceProperName name'
matchesDeclaration _ = False
checkRoleDeclarations _ (d : rest) = checkRoleDeclarations (Just d) rest
checkRoleDeclarations _ [] = return ()