packages feed

hoq-0.1.0.0: src/TypeChecking/Definitions/Functions.hs

{-# LANGUAGE RecursiveDo #-}

module TypeChecking.Definitions.Functions
    ( typeCheckFunction
    ) where

import Control.Monad
import Control.Monad.Fix
import Data.Maybe

import Syntax.Expr as E
import Syntax.Term as T
import Syntax.ErrorDoc
import TypeChecking.Monad
import TypeChecking.Context
import TypeChecking.Expressions
import TypeChecking.Definitions.Patterns
import TypeChecking.Definitions.Coverage
import TypeChecking.Definitions.Conditions
import TypeChecking.Definitions.Termination
import Normalization

typeCheckFunction :: MonadFix m => PIdent -> Expr -> [((Int, Int), [ParPat], Maybe Expr)] -> TCM m ()
typeCheckFunction p@(PIdent (lc,name)) ety clauses = mdo
    (ty, Type u _) <- typeCheck ety Nothing
    lvl <- case u of
            T.Universe lvl -> return lvl
            _              -> throwError [emsgLC (getPos ety) "" $ pretty "Expected a type" $$
                                                                   pretty "Actual type:" <+> prettyOpen Nil ty]
    addFunctionCheck p (FunCall lc name clauses') (Type ty lvl)
    clausesAndPats <- forW clauses $ \(lc,pats,mexpr) ->  do
        (bf, TermsInCtx ctx _ ty', rtpats) <- typeCheckPatterns Nil (Type (nf WHNF ty) lvl) pats
        case (bf,mexpr) of
            (True,  Nothing) -> return Nothing
            (False, Nothing) -> do
                let msg = "The right hand side can be omitted only if the absurd pattern is given"
                warn [emsgLC lc msg enull]
                return Nothing
            (True, Just expr) -> do
                let msg = "If the absurd pattern is given the right hand side must be omitted"
                warn [emsgLC (getPos expr) msg enull]
                return Nothing
            (False, Just expr) -> do
                (term, _) <- typeCheckCtx ctx expr (Just ty')
                let scope = closed (abstractTermInCtx ctx term)
                throwErrors (checkTermination name rtpats scope)
                return $ Just ((rtpats, scope), (lc, rtpats))
    let clauses' = map fst clausesAndPats
    case checkCoverage (map snd clausesAndPats) of
        Nothing -> when (length clausesAndPats == length (filter (\(_,_,me) -> isJust me) clauses)) $
                warn [emsgLC lc "Incomplete pattern matching" enull]
        Just uc -> warn $ map (\lc -> emsgLC lc "Unreachable clause" enull) uc
    warn $ checkConditions lc (Closed $ FunCall lc name clauses') (map fst clausesAndPats)