{-# LANGUAGE GADTs #-} -- | -- Functions for replacing fully applied type synonyms -- module Language.PureScript.TypeChecker.Synonyms ( SynonymMap , KindMap , replaceAllTypeSynonyms , replaceAllTypeSynonymsM ) where import Prelude.Compat import Control.Monad.Error.Class (MonadError(..)) import Control.Monad.State import Data.Maybe (fromMaybe) import qualified Data.Map as M import Data.Text (Text) import Language.PureScript.Environment import Language.PureScript.Errors import Language.PureScript.Names import Language.PureScript.TypeChecker.Monad import Language.PureScript.Types -- | Type synonym information (arguments with kinds, aliased type), indexed by name type SynonymMap = M.Map (Qualified (ProperName 'TypeName)) ([(Text, Maybe SourceType)], SourceType) type KindMap = M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind) replaceAllTypeSynonyms' :: SynonymMap -> KindMap -> SourceType -> Either MultipleErrors SourceType replaceAllTypeSynonyms' syns kinds = everywhereOnTypesTopDownM try where try :: SourceType -> Either MultipleErrors SourceType try t = fromMaybe t <$> go (fst $ getAnnForType t) 0 [] [] t go :: SourceSpan -> Int -> [SourceType] -> [SourceType] -> SourceType -> Either MultipleErrors (Maybe SourceType) go ss c kargs args (TypeConstructor _ ctor) | Just (synArgs, body) <- M.lookup ctor syns , c == length synArgs , kindArgs <- lookupKindArgs ctor , length kargs == length kindArgs = let repl = replaceAllTypeVars (zip (map fst synArgs) args <> zip kindArgs kargs) body in Just <$> try repl | Just (synArgs, _) <- M.lookup ctor syns , length synArgs > c = throwError . errorMessage' ss $ PartiallyAppliedSynonym ctor go ss c kargs args (TypeApp _ f arg) = go ss (c + 1) kargs (arg : args) f go ss c kargs args (KindApp _ f arg) = go ss c (arg : kargs) args f go _ _ _ _ _ = return Nothing lookupKindArgs :: Qualified (ProperName 'TypeName) -> [Text] lookupKindArgs ctor = fromMaybe [] $ fmap (fmap (fst . snd) . fst) . completeBinderList . fst =<< M.lookup ctor kinds -- | Replace fully applied type synonyms replaceAllTypeSynonyms :: (e ~ MultipleErrors, MonadState CheckState m, MonadError e m) => SourceType -> m SourceType replaceAllTypeSynonyms d = do env <- getEnv either throwError return $ replaceAllTypeSynonyms' (typeSynonyms env) (types env) d -- | Replace fully applied type synonyms by explicitly providing a 'SynonymMap'. replaceAllTypeSynonymsM :: MonadError MultipleErrors m => SynonymMap -> KindMap -> SourceType -> m SourceType replaceAllTypeSynonymsM syns kinds = either throwError pure . replaceAllTypeSynonyms' syns kinds