module TypeChecking.Expressions ( typeCheck, typeCheckCtx ) where import Control.Monad import Data.Either import Data.List import Data.Void import Data.Bifunctor import Data.Bitraversable import Data.Traversable(sequenceA) import Syntax as S import Semantics import Semantics.Value as V import Semantics.Pattern as P import Syntax.ErrorDoc import TypeChecking.Monad import TypeChecking.Context as C import TypeChecking.Expressions.Utils import TypeChecking.Expressions.Patterns import TypeChecking.Expressions.Conditions import TypeChecking.Expressions.Coverage import Normalization type Context = Ctx String (Type Semantics) Void intType :: Type Semantics a intType = Type interval (TypeK NoLevel) pathExp :: Sort -> Semantics pathExp k = Semantics (Name Prefix $ Ident "Path") (Path k) pathImp :: Sort -> Semantics pathImp k = Semantics PathImp (Path k) sortPred :: Sort -> Sort sortPred Prop = Contr sortPred Set{} = Prop sortPred k = k prettyOpen' :: Ctx String (Type Semantics) Void a -> Term Semantics (Either k a) -> EDoc (Term Syntax) prettyOpen' ctx term = epretty $ fmap (pretty . either id absurd) $ close ctx $ first syntax term >>= fmap Right . either (const $ capply $ Name Prefix $ Ident "?") return typeCheck :: Monad m => Term (Posn, Syntax) Void -> Maybe (Type Semantics Void) -> TCM m (Term Semantics Void, Type Semantics Void) typeCheck = typeCheckCtx C.Nil typeCheckCtx :: (Monad m, Eq a) => Context a -> Term (Posn, Syntax) Void -> Maybe (Type Semantics a) -> TCM m (Term Semantics a, Type Semantics a) typeCheckCtx ctx term mty = do (te, ty, _) <- typeCheckCtx' ctx term $ fmap (\(Type t k) -> Type (fmap Right t) k) mty return (te, ty) typeCheckCtx' :: (Monad m, Eq a) => Context a -> Term (Posn, Syntax) Void -> Maybe (Type Semantics (Either Argument a)) -> TCM m (Term Semantics a, Type Semantics a, [(Argument, Term Semantics a)]) typeCheckCtx' ctx (Apply (pos, Name ft var) ts) mty = typeCheckName ctx pos ft var ts mty typeCheckCtx' ctx (Apply (_, S.Lam []) [te]) mty = typeCheckCtx' ctx te mty typeCheckCtx' ctx (Apply (pos, S.Lam (v:vs)) [te]) (Just (Type (Apply p@(Semantics (S.Pi e _) (V.Pi k1 k2)) [a,b]) k3)) = case bitraverse Right id a of Left{} -> throwError [inferErrorMsg pos "the argument"] Right a' -> do (te', Type b' k2', tab) <- typeCheckCtx' (Snoc ctx v $ Type a' k1) (Apply (pos, S.Lam vs) [te]) $ Just $ Type (nf WHNF $ fmap sequenceA $ snd $ dropOnePi p a b) k2 let te'' = case te' of Apply (Semantics (S.Lam vs') _) [t] -> Apply (Semantics (S.Lam $ v:vs') V.Lam) [Lambda t] _ -> Apply (Semantics (S.Lam [v]) V.Lam) [Lambda te'] tab' = tab >>= \(kp, term) -> case sequenceA term of Bound -> [] Free t -> [(kp, t)] return (te'', Type (Apply (Semantics (S.Pi e [v]) $ V.Pi k1 k2') [a', Lambda b']) k3, tab') typeCheckCtx' ctx (Apply (pos, S.Lam{}) [_]) (Just (Type (Var Left{} _) _)) = throwError [inferErrorMsg pos "lambda expressions"] typeCheckCtx' ctx (Apply (pos, S.Lam{}) [_]) (Just (Type ty _)) = throwError [Error TypeMismatch $ emsgLC pos "" $ pretty "Expected type:" <+> prettyOpen' ctx ty $$ pretty "But lambda expression has pi type"] typeCheckCtx' ctx (Apply (pos, S.Lam{}) _) _ = throwError [inferErrorMsg pos "the argument"] typeCheckCtx' ctx (Apply (pos, S.Pi e vs) (a:b:ts)) Nothing = do (a', Type ty1 _) <- typeCheckCtx ctx a Nothing k1 <- checkIsType ctx (termPos a) ty1 (b', k2) <- extend ctx vs (Type a' k1) unless (null ts) $ warn [argsErrorMsg pos "A type"] let k = case (k1, k2) of (_, Contr) -> Contr (_, Prop) -> Prop (Set l1, Set l2) -> Set (max l1 l2) (TypeK l1, Set l2) -> Set (max l1 l2) (_, Set l) -> Set l (Set l1, TypeK l2) -> TypeK (max l1 l2) (TypeK l1, TypeK l2) -> TypeK (max l1 l2) (_, TypeK l) -> TypeK l return (Apply (Semantics (S.Pi e vs) (V.Pi k1 k2)) [a', b'], Type (universe k) $ succ k, []) where extend :: (Monad m, Eq a) => Context a -> [String] -> Type Semantics a -> TCM m (Term Semantics a, Sort) extend ctx [] _ = do (te, Type ty _) <- typeCheckCtx ctx b Nothing k <- checkIsType ctx (termPos b) ty return (te, k) extend ctx (v:vs) a = do (te, k) <- extend (Snoc ctx v a) vs (fmap Free a) return (Lambda te, k) typeCheckCtx' ctx (Apply (pos, PathImp) (a1:a2:ts)) Nothing = do unless (null ts) $ warn [argsErrorMsg pos "A type"] (r1, Type t1 k) <- typeCheckCtx ctx a1 Nothing (r2, _) <- typeCheckCtx ctx a2 $ Just $ Type (nf WHNF t1) k return (Apply (pathImp k) [Apply (Semantics (S.Lam ["_"]) V.Lam) [Lambda $ fmap Free t1], r1, r2], Type (universe $ sortPred k) $ succ $ sortPred k, []) typeCheckCtx' ctx (Apply (pos, S.At) (b:c:ts)) mty = do (r1, Type t1 k) <- typeCheckCtx ctx b Nothing (r2, _, tab1) <- typeCheckCtx' ctx c (Just intType) case nf WHNF t1 of Apply (Semantics _ Path{}) [a,b',c'] -> do (tes, ty, tab2) <- typeCheckApps pos (Just $ Operator "@") ctx ts (Type (apps a [r2]) k) mty return (Apply (Semantics S.At V.At) (b':c':r1:r2:tes), ty, tab1 ++ tab2) t1' -> throwError [Error TypeMismatch $ emsgLC pos "" $ pretty "Expected type: Path" $$ pretty "Actual type:" <+> prettyOpen ctx t1'] typeCheckCtx' ctx (Apply (pos, (S.Case (pat:pats))) (expr:terms)) mty = do (exprTerm, exprType) <- typeCheckCtx ctx expr Nothing let (term1:terms1,terms2) = splitAt (length pats + 1) terms typeCheckClause mtype (pat,term) = do (bf, TermInCtx ctx' pat' _) <- typeCheckPattern ctx exprType pat when bf $ warn [Error Other $ emsgLC (termPos pat) "Absurd patterns are not allowed in case constructions" enull] (te, Type ty k, tab) <- typeCheckCtx' (ctx C.+++ ctx') term $ fmap (fmap $ fmap $ liftBase ctx') mtype let tab' = tab >>= \(kp, t) -> case sequenceA $ fmap (toBase ctx') t of Nothing -> [] Just t' -> [(kp, t')] return (P.Clause (Cons pat' P.Nil) te, Type (abstractTerm ctx' ty) k, tab') (clause, Type type1 k, tab1) <- typeCheckClause (if null terms2 then mty else Nothing) (pat,term1) type1' <- case isStationary type1 of Nothing -> throwError [Error Other $ emsgLC pos "Type of expressions in case constructions cannot be dependent" enull] Just r -> return (Type r k) clauses <- mapM (liftM (\(p,_,_) -> p) . typeCheckClause (Just $ nfType WHNF $ fmap Right type1')) (zip pats terms1) (terms2', ty, tab2) <- if null terms2 then return ([], type1', []) else typeCheckApps pos Nothing ctx terms2 type1' mty let clauseToSyntax (P.Clause pats _) p = bimap (\nm -> (termPos p, nm)) id $ head (patternsToTermsSyntax pats) cs = clause:clauses sem = Semantics (S.Case $ zipWith clauseToSyntax cs (pat:pats)) $ V.Case $ map (head . fst . clauseToEval) cs terms' = map (snd . clauseToEval) cs clauses' = zipWith (\p1 p2 -> (termPos p1, p2)) (pat:pats) cs warn $ coverageErrorMsg pos (checkCoverage clauses') warn $ checkConditions ctx (Lambda $ Apply sem $ bvar : map (fmap Free) terms') clauses' return (Apply sem $ exprTerm : terms' ++ terms2', ty, tab1 ++ tab2) where isStationary :: Term a b -> Maybe (Term a b) isStationary (Lambda t) = case sequenceA t of Bound -> Nothing Free t' -> isStationary t' isStationary t = Just t typeCheckCtx' ctx (Apply (pos, (S.FieldAcc _ pid@(PIdent fPos fName))) (expr:exprs)) mty = do (exprTerm, Type exprType _) <- typeCheckCtx ctx expr Nothing case nf WHNF exprType of Apply (Semantics _ (DataType dtID _)) params -> do mfInd <- lift (getField fName dtID) case mfInd of Nothing -> throwError [notInScope fPos "record field" fName] Just (fInd, conds, Closed (Type fType k)) -> do fs <- lift (getFields dtID) let lparams = length params lfs = length fs syn = S.FieldAcc lparams pid fields = zipWith (\(_,e,_) i -> Apply (Semantics syn $ V.FieldAcc i lfs lparams e) $ exprTerm:params) fs [0..] (terms, ty, tab) <- typeCheckApps pos Nothing ctx exprs (Type (apps fType $ params ++ fields) k) mty return (Apply (Semantics syn $ V.FieldAcc fInd lfs lparams conds) (exprTerm : params ++ terms), ty, tab) _ -> throwError [Error TypeMismatch $ emsgLC pos "" $ pretty "Expected a record type" $$ pretty "Actual type:" <+> prettyOpen ctx exprType] typeCheckCtx' ctx te (Just (Type ty _)) = do (te', Type ty' k') <- typeCheckCtx ctx te Nothing tab <- actExpType True ctx (fmap Right ty') ty (termPos te) (Just te') return (te', Type ty' k', tab) typeCheckCtx' _ _ _ = error "typeCheckCtx" typeCheckName :: (Monad m, Eq a) => Context a -> Posn -> Fixity -> Name -> [Term (Posn, Syntax) Void] -> Maybe (Type Semantics (Either Argument a)) -> TCM m (Term Semantics a, Type Semantics a, [(Argument, Term Semantics a)]) typeCheckName ctx pos ft var ts mty = do when (nameToString var == "_") $ throwError [inferExprErrorMsg pos] eres <- case lookupCtx (nameToString var) ctx of Just (te,ty) -> return $ Left (te, [], [], ty) Nothing -> do let mdt = mty >>= \(Type ty _) -> dropPis ty mt <- lift $ getEntry var $ mdt >>= either (const Nothing) Just cons <- lift (getConstructor var Nothing) let cons' = map (\(c,_,_,_,_) -> c) cons case (mdt, cons', mt) of (Just (Left wty), _:_, _) -> throwError [Error TypeMismatch $ emsgLC pos "" $ pretty "Expected type:" <+> prettyOpen' ctx wty $$ pretty ("But " ++ nameToPrefix var ++ " is a data type constructor")] (Just (Right (dtID, _)), c:cs, []) -> do dt <- lift (getDataTypeByID dtID) throwError [Error TypeMismatch $ emsgLC pos "" $ pretty ("Expected data type: " ++ nameToPrefix dt) $$ if null cs then pretty $ "Actual data type: " ++ nameToPrefix c else pretty $ "Posible data types: " ++ intercalate ", " (map nameToPrefix cons')] (_, _, []) -> liftM Right (typeCheckKeyword ctx pos (nameToString var) ts mty) (_, _, [(te, conds, ty)]) -> let te' = case te of Apply (Semantics (Constr k _) sem) ts -> Apply (Semantics (Constr k $ Name ft var) sem) ts Apply (Semantics _ sem) ts -> Apply (Semantics (Name ft var) sem) ts _ -> te in case (sequenceA te', sequenceA ty) of (Left kp, _) -> throwError (inferArgErrorMsg kp) (_, Left kp) -> throwError (inferArgErrorMsg kp) (Right te'', Right (Type Lambda{} _)) -> throwError [inferParamsErrorMsg pos $ nameToPrefix var] (Right te'', Right ty') -> return $ Left (te'', conds, maybe [] (either (const []) snd) mdt, ty') _ -> throwError [Error Other $ emsgLC pos ("Ambiguous identifier: " ++ show (nameToString var)) enull] case eres of Left (te, conds, params, ty) -> do (tes, ty', tab) <- typeCheckApps pos (Just var) ctx ts ty mty let lconds = length conds msg = "Expected " ++ show lconds ++ " arguments to " ++ nameToPrefix var when (length tes < lconds) $ warn [Error Conditions $ emsgLC pos msg enull] when (lconds > 0) $ let (lefts,params') = partitionEithers (map sequenceA params) in case lefts of [] -> forM_ (zip tes conds) $ \(term,cs) -> forM_ cs $ \(ClauseInCtx ctx' cl) -> case clauseToClauseEq $ instantiateClause ctx' (params' ++ tes) cl of P.ClauseEq pats rhs -> let (ctx1,args1) = patsToTerms pats term' = apps (fmap (liftBase ctx1) term) args1 actTerm = nf NF term' expTerm = nf NF rhs in unless (expTerm == actTerm) $ warn [conditionsErrorMsg pos (ctx C.+++ ctx1) ([], term', actTerm, expTerm)] _ -> warn (lefts >>= inferArgErrorMsg) return (apps te tes, ty', tab) Right res -> return res where dropPis :: Eq a => Term Semantics a -> Maybe (Either (Term Semantics a) (ID, [Term Semantics a])) dropPis (Apply (Semantics (S.Pi _ []) _) [_,t]) = dropPis (nf WHNF t) dropPis (Apply (Semantics (S.Pi _ (v:vs)) _) [_, Lambda t]) = case dropPis (nf WHNF t) of Just (Right (dtID, params)) -> Just $ Right (dtID, case sequenceA $ map sequenceA params of Free params' -> params' _ -> []) Just (Left t) -> Just $ Left $ t >>= \u -> case u of Bound -> capply $ Semantics (Name Prefix $ Ident v) (error "dropPis") Free a -> return a Nothing -> Nothing dropPis (Apply (Semantics _ (DataType dtID _)) params) = Just $ Right (dtID, params) dropPis t@(Apply (Semantics _ v) _) | isInj v = Just (Left t) dropPis _ = Nothing typeCheckKeyword :: (Monad m, Eq a) => Context a -> Posn -> String -> [Term (Posn, Syntax) Void] -> Maybe (Type Semantics (Either Argument a)) -> TCM m (Term Semantics a, Type Semantics a, [(Argument, Term Semantics a)]) typeCheckKeyword _ pos u as Nothing | (k,""):_ <- reads u = do unless (null as) $ warn [argsErrorMsg pos "A type"] return (universe k, Type (universe $ succ k) $ succ $ succ k, []) typeCheckKeyword ctx pos "contr" [] (Just (Type ty k)) = do case k of Contr -> return () _ -> warn [Error TypeMismatch $ emsgLC pos "" $ pretty "Expected a contractible type" $$ pretty "Actual type:" <+> prettyOpen' ctx ty] case sequenceA ty of Left kp -> throwError (inferArgErrorMsg kp) Right ty' -> return (capply $ Semantics (Name Prefix $ Ident "contr") CCon, Type ty' k, []) typeCheckKeyword _ pos "contr" _ _ = throwError [inferErrorMsg pos "contr"] typeCheckKeyword _ pos "I" as Nothing = do unless (null as) $ warn [argsErrorMsg pos "A type"] return (interval, Type (universe $ TypeK NoLevel) $ TypeK $ Level 1, []) typeCheckKeyword _ pos "left" as Nothing = do unless (null as) $ warn [argsErrorMsg pos $ show "left"] return (iCon ILeft, intType, []) typeCheckKeyword _ pos "right" as Nothing = do unless (null as) $ warn [argsErrorMsg pos $ show "right"] return (iCon IRight, intType, []) typeCheckKeyword _ pos "Path" [] _ = throwError [expectedArgErrorMsg pos "Path"] typeCheckKeyword ctx pos "Path" (a:as) Nothing = do (r1, _, (v, t1)) <- typeCheckLambda ctx a intType k <- checkIsType (Snoc ctx v $ error "") (termPos a) t1 let r1' c = apps r1 [iCon c] k' = sortPred k mkType t = Type t (succ k') case as of [] -> return (Apply (pathExp k) [r1], mkType $ Apply (Semantics (S.Pi Explicit []) $ V.Pi k $ succ k) [r1' ILeft, Apply (Semantics (S.Pi Explicit []) $ V.Pi k $ succ k) [r1' IRight, universe k']], []) [a2] -> do (r2, _) <- typeCheckCtx ctx a2 $ Just $ Type (nf WHNF $ r1' ILeft) k return (Apply (pathExp k) [r1,r2], mkType $ Apply (Semantics (S.Pi Explicit []) $ V.Pi k $ succ k) [r1' IRight, universe k'], []) a2:a3:as' -> do unless (null as') $ warn [argsErrorMsg pos "A type"] (r2, _) <- typeCheckCtx ctx a2 $ Just $ Type (nf WHNF $ r1' ILeft) k (r3, _) <- typeCheckCtx ctx a3 $ Just $ Type (nf WHNF $ r1' IRight) k return (Apply (pathExp k) [r1,r2,r3], mkType $ universe k', []) typeCheckKeyword _ pos "path" [] _ = throwError [expectedArgErrorMsg pos "path"] typeCheckKeyword ctx pos "path" (a:as) mty = do unless (null as) $ warn [argsErrorMsg pos "A path"] case mty of Nothing -> do (te, Type _ k, (_, ty)) <- typeCheckLambda ctx a intType return (path [te], Type (Apply (pathImp k) [Apply (Semantics (S.Lam ["_"]) V.Lam) [Lambda ty], apps te [iCon ILeft], apps te [iCon IRight]]) k, []) Just (Type (Var (Left kp) _) _) -> do (te, Type _ k, (_, ty)) <- typeCheckLambda ctx a intType let ty' = Apply (pathImp k) [Apply (Semantics (S.Lam ["_"]) V.Lam) [Lambda ty], apps te [iCon ILeft], apps te [iCon IRight]] return (path [te], Type ty' k, [(kp,ty')]) Just (Type ety@(Apply (Semantics _ (Path k1)) [t1,_,_]) k) -> do let sem = Semantics (S.Pi Explicit ["i"]) $ V.Pi (TypeK NoLevel) k1 aty = Apply sem [interval, Lambda $ apps (fmap Free t1) [bvar]] (r, Type ty' _, tab1) <- typeCheckCtx' ctx a $ Just (Type aty k1) case nf WHNF ty' of Apply (Semantics (S.Pi e vs) p) [ta, tb] -> do let tb' = case tb of Lambda t@Lambda{} -> Apply (Semantics (S.Lam ["i"]) V.Lam) [Lambda $ Apply (Semantics (S.Pi e $ tail vs) p) [fmap Free ta, t]] Lambda{} -> Apply (Semantics (S.Lam ["i"]) V.Lam) [tb] _ -> Apply (Semantics (S.Lam ["_"]) V.Lam) [Lambda $ fmap Free tb] aty = Apply (pathImp k1) [tb', apps r [iCon ILeft], apps r [iCon IRight]] res = path [r] tab2 <- actExpType True ctx (fmap Right aty) ety pos (Just res) return (res, Type aty k, tab1 ++ tab2) _ -> error "typeCheckKeyword: path" Just (Type ty _) -> throwError [Error TypeMismatch $ emsgLC pos "" $ pretty "Expected type:" <+> prettyOpen' ctx ty $$ pretty "Actual type: Path"] typeCheckKeyword _ pos "coe" [] _ = throwError [expectedArgErrorMsg pos "coe"] typeCheckKeyword ctx pos "coe" (a1:as) Nothing = do (r1, _, (v, t1)) <- typeCheckLambda ctx a1 intType k <- checkIsType (Snoc ctx v $ error "") (termPos a1) t1 let res = Apply (Semantics (S.Pi Explicit ["r"]) $ V.Pi (TypeK NoLevel) k) [interval, Lambda $ apps (fmap Free r1) [bvar]] coe = Semantics (Name Prefix $ Ident "coe") Coe case as of [] -> return (Apply coe [r1], Type (Apply (Semantics (S.Pi Explicit ["l"]) $ V.Pi (TypeK NoLevel) k) [interval, Lambda $ Apply (Semantics (S.Pi Explicit []) $ V.Pi k k) [apps (fmap Free r1) [bvar], fmap Free res]]) k, []) a2:as1 -> do (r2, _, tab2) <- typeCheckCtx' ctx a2 (Just intType) case as1 of [] -> return (Apply coe [r1,r2], Type (Apply (Semantics (S.Pi Explicit []) $ V.Pi k k) [apps r1 [r2], res]) k, []) a3:as2 -> do (r3, _) <- typeCheckCtx ctx a3 $ Just $ Type (nf WHNF $ apps r1 [r2]) k case as2 of [] -> return (Apply coe [r1,r2,r3], Type res k, []) a4:as3 -> do (r4, _, tab4) <- typeCheckCtx' ctx a4 (Just intType) (tes, ty, _) <- typeCheckApps pos Nothing ctx as3 (Type (apps r1 [r4]) k) Nothing return (Apply coe $ [r1,r2,r3,r4] ++ tes, ty, tab2 ++ tab4) typeCheckKeyword ctx pos "iso" (a1:a2:a3:a4:a5:a6:as) Nothing = do (r1, Type t1 _) <- typeCheckCtx ctx a1 Nothing (r2, Type t2 _) <- typeCheckCtx ctx a2 Nothing let t1' = nf WHNF t1 t2' = nf WHNF t2 k1 <- checkIsType ctx (termPos a1) t1' k2 <- checkIsType ctx (termPos a2) t2' let k = dmax k1 k2 (r3, _) <- typeCheckCtx ctx a3 $ Just $ Type (Apply (Semantics (S.Pi Explicit []) $ V.Pi k1 k2) [r1,r2]) k (r4, _) <- typeCheckCtx ctx a4 $ Just $ Type (Apply (Semantics (S.Pi Explicit []) $ V.Pi k2 k1) [r2,r1]) k let h e s1 s3 s4 tk = typeCheckCtx ctx e $ Just $ Type (Apply (Semantics (S.Pi Explicit ["x"]) $ V.Pi tk tk) [s1, Lambda $ Apply (pathImp tk) [Apply (Semantics (S.Lam ["_"]) V.Lam) [Lambda $ fmap (Free . Free) s1], apps (fmap Free s4) [apps (fmap Free s3) [bvar]], bvar]]) tk iso = Semantics (Name Prefix $ Ident "iso") Iso (r5, _) <- h a5 r1 r3 r4 k1 (r6, _) <- h a6 r2 r4 r3 k2 case as of [] -> return (Apply iso [r1,r2,r3,r4,r5,r6], Type (Apply (Semantics (S.Pi Explicit []) $ V.Pi (TypeK NoLevel) $ succ k) [interval, universe k]) $ succ k, []) a7:as' -> do unless (null as') $ warn [argsErrorMsg pos "A type"] (r7, _, tab7) <- typeCheckCtx' ctx a7 (Just intType) return (Apply iso [r1,r2,r3,r4,r5,r6,r7], Type (universe k) $ succ k, tab7) typeCheckKeyword _ pos "iso" _ Nothing = throwError [Error NotEnoughArgs $ emsgLC pos "Expected at least 6 arguments to \"iso\"" enull] typeCheckKeyword ctx pos "squeeze" as Nothing = let mkType t = Apply (Semantics (S.Pi Explicit []) $ V.Pi (TypeK NoLevel) $ TypeK NoLevel) [interval, t] squeeze = Semantics (Name Prefix $ Ident "squeeze") Squeeze in case as of [] -> return (capply squeeze, Type (mkType $ mkType interval) $ TypeK NoLevel, []) [a1] -> do (r1, _, tab) <- typeCheckCtx' ctx a1 (Just intType) return (Apply squeeze [r1], Type (mkType interval) $ TypeK NoLevel, tab) [a1,a2] -> do (r1, _, tab1) <- typeCheckCtx' ctx a1 (Just intType) (r2, _, tab2) <- typeCheckCtx' ctx a2 (Just intType) return (Apply squeeze [r1,r2], intType, tab1 ++ tab2) _ -> throwError [argsErrorMsg pos "squeeze _ _"] typeCheckKeyword ctx pos var ts (Just (Type ty _)) = do (te', Type ty' k', _) <- typeCheckKeyword ctx pos var ts Nothing tab <- actExpType True ctx (fmap Right ty') ty pos (Just te') return (te', Type ty' k', tab) typeCheckKeyword _ pos var _ _ = throwError [notInScope pos "" var] actExpType :: (Monad m, Eq a) => Bool -> Context a -> Term Semantics (Either Argument a) -> Term Semantics (Either Argument a) -> Posn -> Maybe (Term Semantics a) -> EDocM m [(Argument, Term Semantics a)] actExpType w ctx act exp pos mterm = do let act' = nf NF act exp' = nf NF exp (mo,(l1,l2)) = pcmpTerms act' exp' l = if w then l2 else l1 unless (mo == Just EQ || mo == Just LT) $ throwError [Error TypeMismatch $ emsgLC pos "" $ pretty "Expected type:" <+> prettyOpen' ctx exp' $$ pretty "Actual type: " <+> prettyOpen' ctx act' $$ maybe enull (\t -> pretty "Term:" <+> prettyOpen ctx t) mterm] return l typeCheckApps :: (Monad m, Eq a) => Posn -> Maybe Name -> Context a -> [Term (Posn, Syntax) Void] -> Type Semantics a -> Maybe (Type Semantics (Either Argument a)) -> TCM m ([Term Semantics a], Type Semantics a, [(Argument, Term Semantics a)]) typeCheckApps pos mname ctx allTerms ty mety = go 0 [] [] (map (\t -> (Explicit, Left t)) allTerms) nty where nty = nfType WHNF (fmap Right ty) mterm terms = fmap (\name -> Apply (Semantics (Name Prefix name) $ error "") terms) mname dropAndInstantiate t (Semantics (S.Pi _ [_]) _) a (Lambda b) = instantiate1 t b dropAndInstantiate t (Semantics (S.Pi e (_:vs)) s) a (Lambda b) = Apply (Semantics (S.Pi e vs) s) [a, instantiate1 t b] dropAndInstantiate _ _ _ b = b go n acc rest ((e1, term@(Left (Apply (pos', Name _ (Ident "_")) []))) : terms) (Type (Apply p@(Semantics (S.Pi e2 _) (V.Pi _ k2)) [a,b]) _) | e1 == e2 = go (n + 1) (Left (inferArgErrorMsg $ Argument n pos' mname) : acc) ((e1,term):rest) terms $ Type (nf WHNF $ dropAndInstantiate (cvar $ Left (Argument n pos' mname)) p a b) k2 go n acc rest ((e1,term):terms) (Type (Apply p@(Semantics (S.Pi e2 _) (V.Pi k1 k2)) [a,b]) _) | e1 == e2 = do mres <- case term of Left t -> let catchErrs = catchErrorType [Inference] in liftM (\(a,b,c) -> Right ((termPos t, a), Just b, c)) (typeCheckCtx' ctx t $ Just $ Type (nf WHNF a) k1) `catchErrs` (return . Left) Right (pte, maty) -> do tab <- case maty of Just (Type aty _) -> actExpType True ctx (fmap Right aty) a (fst pte) $ Just (snd pte) Nothing -> return [] return $ Right (pte, maty, tab) case mres of Left errs -> go (n + 1) (Left errs : acc) ((e1,term):rest) terms $ Type (nf WHNF $ dropAndInstantiate (cvar $ Left $ NoArgument n errs) p a b) k2 Right (pterm', mty, tab) -> let ty' = Right (pterm', mty) in if useful tab then go 0 [] [] (replaceTerms (reverse rest ++ [(e1, ty')] ++ terms) tab) nty else go (n + 1) (ty' : acc) ((e1, ty') : rest) terms $ Type (nf WHNF $ dropAndInstantiate (fmap Right $ snd pterm') p a b) k2 go n acc rest terms (Type (Apply p@(Semantics (S.Pi Implicit _) (V.Pi _ k2)) [a,b]) _) = go (n + 1) (Left (inferArgErrorMsg $ Argument n pos mname) : acc) ((Implicit, Left (capply (pos, Name Prefix $ Ident "_"))) : rest) terms $ Type (nf WHNF $ dropAndInstantiate (cvar $ Left (Argument n pos mname)) p a b) k2 go n acc rest [] (Type aty k) = let checkAty = case sequenceA aty of Left kp -> throwError (inferArgErrorMsg kp) Right aty' -> case partitionEithers (reverse acc) of ([], rights) -> return (map (snd . fst) rights, Type aty' k, []) (lefts, _) -> throwError (concat lefts) in case mety of Just (Type ety _) -> do tab <- actExpType False ctx aty ety pos Nothing if useful tab then go 0 [] [] (replaceTerms (reverse rest) tab) nty else do (acc', Type aty' k', _) <- checkAty tab' <- actExpType True ctx (fmap Right aty') ety pos (mterm acc') return (acc', Type aty' k', tab') Nothing -> checkAty go _ _ _ _ (Type (Var (Left kp) _) _) = throwError (inferArgErrorMsg kp) go _ _ _ _ (Type ty _) = throwError [Error TypeMismatch $ emsgLC pos "" $ pretty "Expected pi type" $$ pretty "Actual type:" <+> prettyOpen' ctx ty] replaceTerms :: [(e, Either (Term (Posn, Syntax) Void) ((Posn, s), Maybe u))] -> [(Argument, s)] -> [(e, Either (Term (Posn, Syntax) Void) ((Posn, s), Maybe u))] replaceTerms ts [] = ts replaceTerms ts ((arg, t):tab) = case splitAt (argumentIndex arg) (replaceTerms ts tab) of (ts1, []) -> ts1 (ts1, t2:ts2) -> ts1 ++ [(fst t2, Right ((either termPos (fst . fst) (snd t2), t), Nothing))] ++ ts2 useful :: [(Argument,a)] -> Bool useful = not . null typeCheckLambda :: (Monad m, Eq a) => Context a -> Term (Posn, Syntax) Void -> Type Semantics a -> TCM m (Term Semantics a, Type Semantics a, (String, Term Semantics (Scoped a))) typeCheckLambda ctx (Apply (pos, S.Lam (v:vs)) [te]) (Type ty k) = do (te', Type ty' k') <- typeCheckCtx (Snoc ctx v $ Type ty k) (if null vs then te else Apply (pos, S.Lam vs) [te]) Nothing let te'' = case te' of Apply (Semantics (S.Lam vs') _) [te''] -> Apply (Semantics (S.Lam $ v:vs') V.Lam) [Lambda te''] _ -> Apply (Semantics (S.Lam [v]) V.Lam) [Lambda te'] return (te'', Type (Apply (Semantics (S.Pi Explicit [v]) (V.Pi k k')) [ty, Lambda ty']) $ dmax k k', (v, ty')) typeCheckLambda ctx te ty = do (te', Type ty' k') <- typeCheckCtx ctx te Nothing case nf WHNF ty' of ty''@(Apply p@(Semantics sp (V.Pi ka kb)) [a,b]) -> let na = nf NF a Type nty kty = nfType NF ty in if (nty `lessOrEqual` na) then return (te', Type ty'' k', dropOnePi p a b) else throwError [Error TypeMismatch $ emsgLC (termPos te) "" $ pretty "Expected type:" <+> prettyOpen ctx (Apply (Semantics sp $ V.Pi kty kb) [nty,b]) $$ pretty "Actual type: " <+> prettyOpen ctx (Apply p [na,b]) $$ pretty "Term:" <+> prettyOpen ctx te'] _ -> throwError [Error TypeMismatch $ emsgLC (termPos te) "" $ pretty "Expected pi type" $$ pretty "Actual type:" <+> prettyOpen ctx ty' $$ pretty "Term:" <+> prettyOpen ctx te']