diff options
Diffstat (limited to 'src/Obs/Typing.idr')
-rw-r--r-- | src/Obs/Typing.idr | 578 |
1 files changed, 227 insertions, 351 deletions
diff --git a/src/Obs/Typing.idr b/src/Obs/Typing.idr index f814f93..4cc6d8e 100644 --- a/src/Obs/Typing.idr +++ b/src/Obs/Typing.idr @@ -1,6 +1,10 @@ module Obs.Typing -import Data.Vect +import Control.Monad.Maybe + +import Data.Nat + +import Decidable.Equality import Obs.Logging import Obs.NormalForm @@ -8,6 +12,7 @@ import Obs.NormalForm.Normalise import Obs.Sort import Obs.Substitution import Obs.Term +import Obs.Typing.Context import Obs.Typing.Conversion import System @@ -20,384 +25,255 @@ import Text.PrettyPrint.Prettyprinter.Render.Terminal -- Loggings ---------------------------------------------------------------------- -Rename (Logging ann . NormalForm) where - rename t f = pure $ rename !t f - -mismatch : Bounds -> Doc ann -> Doc ann -> Logging ann a -mismatch bounds lhs rhs = fatal $ - MkBounded - (pretty "expected" <++> lhs <+> comma <+> softline <+> pretty "got" <++> rhs) - False - bounds - -typeMismatch : Bounds -> Doc ann -> Doc ann -> Logging ann a -typeMismatch bounds lhs rhs = inScope "type mismatch" $ mismatch bounds lhs rhs - -sortMismatch : Bounds -> Doc ann -> Doc ann -> Logging ann a -sortMismatch bounds lhs rhs = inScope "sort mismatch" $ mismatch bounds lhs rhs +mismatch : (expected, got : Doc ann) -> Logging ann a +mismatch lhs rhs = fatal $ + hang 2 (pretty "expected" <+> line <+> lhs) <+> comma <+> line <+> + hang 2 (pretty "got" <+> line <+> align rhs) --- Typing Contexts ------------------------------------------------------------- +typeMismatch : Doc ann -> Doc ann -> Logging ann a +typeMismatch lhs rhs = inScope "type mismatch" $ mismatch lhs rhs -infix 5 ::< +sortMismatch : Doc ann -> Doc ann -> Logging ann a +sortMismatch lhs rhs = inScope "sort mismatch" $ mismatch lhs rhs -data TyContext : Nat -> Nat -> Type where - Nil : TyContext 0 0 - (:<) : TyContext m n -> NormalForm.Definition n -> TyContext m (S n) - (::<) : TyContext m n -> (String, NormalForm n, Sort) -> TyContext (S m) (S n) +-- Utilities ------------------------------------------------------------------- -fromContext : Context n -> TyContext 0 n -fromContext [] = [] -fromContext (ctx :< def) = fromContext ctx :< def +MkPair : (s, s' : Sort) + -> NormalForm (isSet s) ctx + -> NormalForm (isSet s') ctx + -> NormalForm (isSet (max s s')) ctx +MkPair Prop Prop t u = u +MkPair Prop s'@(Set _) t u = Cnstr $ Pair Prop s' Oh t u +MkPair s@(Set _) s' t u = Cnstr $ Pair s s' Oh t u -countVars : TyContext m n -> Fin (S n) -countVars [] = FZ -countVars (ctx :< y) = weaken $ countVars ctx -countVars (ctx ::< y) = FS $ countVars ctx +-- Checking and Inference ------------------------------------------------------ -index : TyContext m n -> Fin n -> (NormalForm n, NormalForm n, Sort) -index (ctx :< def) FZ = (weaken 1 def.tm, weaken 1 def.ty, def.sort) -index (ctx ::< (var, ty, Prop)) FZ = (Irrel, weaken 1 ty, Prop) -index (ctx ::< (var, ty, s)) FZ = (Ntrl $ Var var FZ, weaken 1 ty, s) -index (ctx :< _) (FS i) = bimap (weaken 1) (mapFst (weaken 1)) $ index ctx i -index (ctx ::< _) (FS i) = bimap (weaken 1) (mapFst (weaken 1)) $ index ctx i +check : (tyCtx : TyContext ctx) + -> (s : Sort) + -> NormalForm True ctx + -> WithBounds (Term (length ctx)) + -> Logging ann (NormalForm (isSet s) ctx) -partial -asSubst : (ctx : TyContext m n) -> Fin n -> Logging ann (NormalForm m) -asSubst (ctx :< def) FZ = subst def.tm (asSubst ctx) -asSubst (ctx ::< (var, _, Prop)) FZ = pure Irrel -asSubst (ctx ::< (var, _, _)) FZ = pure $ Ntrl (Var var FZ) -asSubst (ctx :< def) (FS i) = asSubst ctx i -asSubst (ctx ::< _) (FS i) = map (weaken 1) (asSubst ctx i) +checkType : (tyCtx : TyContext ctx) + -> (s : Sort) + -> WithBounds (Term (length ctx)) + -> Logging ann (NormalForm True ctx) +checkType ctx s tm = check ctx (suc s) (cast s) tm --- Checking and Inference ------------------------------------------------------ +infer : (tyCtx : TyContext ctx) + -> WithBounds (Term (length ctx)) + -> Logging ann (s ** (NormalForm True ctx, NormalForm (isSet s) ctx)) -partial -check : TyContext m n -> WithBounds (Term n) -> NormalForm n -> Sort -> Logging ann (NormalForm n) -partial -infer : TyContext m n -> WithBounds (Term n) -> Logging ann (NormalForm n, NormalForm n, Sort) -partial -inferType : {default typeMismatch tag : forall a . Bounds -> Doc ann -> Doc ann -> Logging ann a} - -> TyContext m n -> WithBounds (Term n) -> Logging ann (NormalForm n, Sort) -partial -inferSort : TyContext m n -> WithBounds (Term n) -> Logging ann Sort +inferType : {default typeMismatch tag : forall a . Doc ann -> Doc ann -> Logging ann a} + -> (tyCtx : TyContext ctx) + -> WithBounds (Term (length ctx)) + -> Logging ann (Sort, NormalForm True ctx) +inferType ctx tm = inBounds tm.bounds $ do + (Set _ ** (Cnstr (Sort s), a)) <- infer ctx tm + | (_ ** (a, t)) => tag (pretty "sort") (pretty a) + pure (s, a) -check ctx tm ty s = case (tm.val, ty) of - (Lambda _ t, Cnstr (Pi s s' var a b)) => do - inScope "check" $ trace $ map (\_ => pretty {ann} "checking under lambda with type" <++> pretty a) tm - inScope "check" $ trace $ map (\_ => "binding new variable to \{var}") tm - inScope "check" $ trace $ map (\_ => pretty {ann} "checking for type" <++> pretty b) tm - t <- check (ctx ::< (var, a, s)) t b s' - case s' of - Prop => pure Irrel - _ => pure (Cnstr $ Lambda var t) - (Lambda _ _, ty) => typeMismatch tm.bounds (pretty "pi") (pretty ty) - (Pair t u, Cnstr (Sigma s s' var a b)) => do - inScope "check" $ trace $ map (\_ => "checking pair") tm - inScope "check" $ trace $ map (\_ => pretty {ann} "checking first for type" <++> pretty a) tm - t <- check ctx t a s +check ctx s ty tm = inBounds tm.bounds $ case (ty, tm.val) of + (Cnstr (Pi l l' _ a b), Lambda var t) => do + info "encountered lambda" + trace $ pretty {ann} "checking body has type" <++> pretty b + t <- check (ctx ::< MkFreeVar l a var.val) l' b (assert_smaller tm t) + let Yes Refl = decEq s (l ~> l') + | No _ => fatal "internal sort mismatch" + pure $ case l' of + Prop => Irrel + Set _ => Cnstr (Lambda l var.val t) + (_, Lambda var t) => typeMismatch (pretty "function") (pretty ty) + (Cnstr (Sigma l l' var a b), Pair t u) => do + info "encountered pair" + trace $ pretty {ann} "checking first has type" <++> pretty a + t <- check ctx l a (assert_smaller tm t) b <- subst1 t b - inScope "check" $ trace $ map (\_ => pretty {ann} "checking second for type" <++> pretty b) tm - u <- check ctx u b s' - inScope "check" $ trace $ map (\_ => pretty {ann} "pair is well typed") tm - case (s, s') of - (Prop, Prop) => pure Irrel - _ => pure (Cnstr $ Pair t u) - (Pair _ _, ty) => typeMismatch tm.bounds (pretty "sigma") (pretty ty) - (Left t, Cnstr (Sum s s' a b)) => do - inScope "check" $ trace $ map (\_ => "checking left injection") tm - inScope "check" $ trace $ map (\_ => pretty {ann} "checking subterm for type" <++> pretty a) tm - t <- check ctx t a s - inScope "check" $ trace $ map (\_ => " subterm is well typed") tm - pure (Cnstr $ Left t) - (Left _, ty) => typeMismatch tm.bounds (pretty "sum") (pretty ty) - (Right t, Cnstr (Sum s s' a b)) => do - inScope "check" $ trace $ map (\_ => "checking right injection") tm - inScope "check" $ trace $ map (\_ => pretty {ann} "checking subterm for type" <++> pretty b) tm - t <- check ctx t b s' - inScope "check" $ trace $ map (\_ => " subterm is well typed") tm - pure (Cnstr $ Right t) - (Right _, ty) => typeMismatch tm.bounds (pretty "sum") (pretty ty) - (MkContainer t p f, Cnstr (Container s a s' s'')) => do - inScope "check" $ trace $ map (\_ => "checking container constructor") tm - let tagTy = tagTy s a s' - inScope "check" $ trace $ map (\_ => pretty {ann} "checking tag for type" <++> pretty tagTy) tm - t <- check ctx t (Cnstr tagTy) (s ~> suc s') - inScope "check" $ trace $ map (\_ => "tag is well typed") tm - positionTy <- positionTy s a s' t s'' - inScope "check" $ trace $ map (\_ => pretty {ann} "checking position for type" <++> pretty positionTy) tm - p <- check ctx p (Cnstr positionTy) (s ~> s' ~> suc s'') - inScope "check" $ trace $ map (\_ => "position is well typed") tm - nextTy <- nextTy s a s' t s'' p - inScope "check" $ trace $ map (\_ => pretty {ann} "checking next for type" <++> pretty nextTy) tm - f <- check ctx f (Cnstr nextTy) (s ~> s' ~> s'' ~> s) - inScope "check" $ trace $ map (\_ => "next is well typed") tm - pure (Cnstr $ MkContainer t p f) - (MkContainer t p f, ty) => typeMismatch tm.bounds (pretty "container") (pretty ty) - (_, _) => do - inScope "check" $ trace $ map (\_ => "checking has fallen through") tm - (v, a, s') <- infer ctx tm - inScope "check" $ trace $ map (\_ => pretty {ann} "inferred type is" <++> pretty a) tm - let True = s == s' - | False => sortMismatch tm.bounds (pretty s) (pretty s') - True <- convert !(subst ty $ asSubst ctx) !(subst a $ asSubst ctx) (cast s) (suc s) - | False => typeMismatch tm.bounds (pretty ty) (pretty a) - inScope "check" $ trace $ map (\_ => pretty {ann} "converted" <++> pretty a <+> softline <+> pretty "to" <++> pretty ty) tm - pure v + trace $ pretty {ann} "checking second has type" <++> pretty b + u <- check ctx l' b (assert_smaller tm u) + let Yes Refl = decEq s (max l l') + | No _ => fatal "internal sort mismatch" + pure $ MkPair l l' t u + (_, Pair t u) => typeMismatch (pretty "pair type") (pretty ty) + (_, Absurd t) => do + info "encountered absurd" + trace "checking proof of contradiction" + Irrel <- check ctx Prop (Cnstr Bottom) (assert_smaller tm t) + pure $ doAbsurd _ + (a, t) => do + info "falling through to inference" + (l ** (b, t)) <- infer ctx tm + trace $ pretty {ann} "inferred type is" <++> pretty b + let Yes Refl = decEq s l + | No _ => typeMismatch (pretty a) (pretty b) + a' <- subst a (reduce ctx) + b' <- subst b (reduce ctx) + Just _ <- inScope "convert" $ runMaybeT $ convert (suc s) (cast s) a' b' + | Nothing => inScope "conversion failed" $ mismatch (pretty a) (pretty b) + pure t -infer ctx tm = case tm.val of +infer ctx tm = inBounds tm.bounds $ case tm.val of (Var var i) => do - inScope "infer" $ trace $ map (\_ => "encountered variable \{var}@\{show i}") tm - let (t, a, s) = index ctx i - inScope "infer" $ trace $ map (\_ => pretty {ann} "variable has type" <++> pretty a) tm - pure (t, a, s) - (Sort s) => pure (cast s, cast (suc s), suc (suc s)) + info $ pretty {ann} "encountered variable" <++> pretty tm.val + let def = index' ctx i + pure (def.sort ** (def.ty, def.tm)) + (Sort s) => do + info $ pretty {ann} "encountered sort" <++> pretty tm.val + pure (suc (suc s) ** (cast (suc s), cast s)) (Pi var a b) => do - inScope "infer" $ trace $ map (\_ => "encountered Pi type") tm - (a, s) <- inferType ctx a - inScope "infer" $ trace $ map (\_ => pretty {ann} "argument has type" <++> pretty a) tm - (b, s') <- inferType (ctx ::< (var.val, a, s)) b - inScope "infer" $ trace $ map (\_ => pretty {ann} "result has type" <++> pretty b <+> comma <+> softline <+> pretty "so Pi type has type" <++> pretty (s ~> s')) tm - pure (Cnstr (Pi s s' var.val a b), cast (s ~> s'), suc (s ~> s')) - (Lambda _ _) => inScope "cannot infer type" $ fatal tm + info "encountered pi" + (s, a) <- inferType ctx (assert_smaller tm a) + trace $ pretty {ann} "domain type is" <++> pretty a + (s', b) <- inferType (ctx ::< MkFreeVar s a var.val) (assert_smaller tm b) + trace $ pretty {ann} "codomain type is" <++> pretty b + pure (suc (s ~> s') ** (cast (s ~> s'), Cnstr (Pi s s' var.val a b))) + (Lambda var t) => fatal "cannot infer type of lambda" (App t u) => do - inScope "infer" $ trace $ map (\_ => "encountered application") tm - (t, ty@(Cnstr (Pi s s' _ a b)), _) <- infer ctx t - | (_, ty, _) => inScope "wrong type to apply" $ fatal (map (\_ => ty) tm) - inScope "infer" $ trace $ map (\_ => pretty {ann} "function has type" <++> pretty ty) tm - inScope "infer" $ trace $ map (\_ => pretty {ann} "checking argument has type" <++> pretty a) tm - u <- check ctx u a s - inScope "infer" $ trace $ map (\_ => "argument is well typed") tm - res <- doApp t u + info "encountered application" + (s ** (ty@(Cnstr (Pi l l' _ a b)), t)) <- infer ctx (assert_smaller tm t) + | (_ ** (ty, _)) => inBounds t.bounds $ typeMismatch (pretty "function") (pretty ty) + trace $ pretty {ann} "function has type" <++> pretty ty + trace $ pretty {ann} "checking argument has type" <++> pretty a + u <- check ctx l a (assert_smaller tm u) + trace $ pretty {ann} "argument is well typed" + let Yes Refl = decEq s (l ~> l') + | No _ => fatal "internal sort mismatch" ty <- subst1 u b - inScope "infer" $ trace $ map (\_ => pretty {ann} "final result is" <++> pretty res <+> softline <+> pretty "of type" <++> pretty ty) tm - pure (res, ty, s') + tm <- doApp t u + pure (l' ** (ty, rewrite sym $ impredicative l l' in tm)) (Sigma var a b) => do - inScope "infer" $ trace $ map (\_ => "encountered Sigma type") tm - (a, s) <- inferType ctx a - inScope "infer" $ trace $ map (\_ => pretty {ann} "first has type" <++> pretty a) tm - (b, s') <- inferType (ctx ::< (var.val, a, s)) b - inScope "infer" $ trace $ map (\_ => pretty {ann} "second has type" <++> pretty b <+> comma <+> softline <+> pretty "so Sigma type has type" <++> pretty (lub s s')) tm - pure (Cnstr (Sigma s s' var.val a b), cast (lub s s'), suc (lub s s')) - (Pair _ _) => inScope "cannot infer type" $ fatal tm + info "encountered sigma" + (s, a) <- inferType ctx (assert_smaller tm a) + trace $ pretty {ann} "first type is" <++> pretty a + (s', b) <- inferType (ctx ::< MkFreeVar s a var.val) (assert_smaller tm b) + trace $ pretty {ann} "second type is" <++> pretty b + pure (suc (max s s') ** (cast (max s s'), Cnstr (Sigma s s' var.val a b))) + (Pair t u) => fatal "cannot infer type of pair" (Fst t) => do - inScope "infer" $ trace $ map (\_ => "encountered first projection") tm - (t, ty@(Cnstr (Sigma s s' _ a b)), _) <- infer ctx t - | (_, ty, _) => inScope "wrong type to fst" $ fatal (map (\_ => ty) tm) - inScope "infer" $ trace $ map (\_ => pretty {ann} "pair has type" <++> pretty ty) tm - res <- doFst t - inScope "infer" $ trace $ map (\_ => pretty {ann} "final result is" <++> pretty res <+> softline <+> pretty "of type" <++> pretty a) tm - pure (res, a, s) + info "encountered first" + (s ** (ty@(Cnstr (Sigma l l' _ a b)), t)) <- infer ctx (assert_smaller tm t) + | (_ ** (ty, _)) => inBounds t.bounds $ typeMismatch (pretty "pair type") (pretty ty) + trace $ pretty {ann} "pair has type" <++> pretty ty + let Yes Refl = decEq s (max l l') + | No _ => fatal "internal sort mismatch" + let ty = a + tm <- doFst (isSet l) (isSet l') (rewrite sym $ maxIsSet l l' in t) + pure (l ** (ty, tm)) (Snd t) => do - inScope "infer" $ trace $ map (\_ => "encountered first projection") tm - (t, ty@(Cnstr (Sigma s s' _ a b)), _) <- infer ctx t - | (_, ty, _) => inScope "wrong type to snd" $ fatal (map (\_ => ty) tm) - inScope "infer" $ trace $ map (\_ => pretty {ann} "pair has type" <++> pretty ty) tm - t1 <- doFst t - res <- doSnd t - b <- subst1 t1 b - inScope "infer" $ trace $ map (\_ => pretty {ann} "final result is" <++> pretty res <+> softline <+> pretty "of type" <++> pretty b) tm - pure (res, b, s') - (Sum a b) => do - inScope "infer" $ trace $ map (\_ => "encountered sum type") tm - (a, s) <- inferType ctx a - inScope "infer" $ trace $ map (\_ => pretty {ann} "left has type" <++> pretty a) tm - (b, s') <- inferType ctx b - inScope "infer" $ trace $ map (\_ => pretty {ann} "right has type" <++> pretty b) tm - pure (Cnstr (Sum s s' a b), cast (ensureSet (lub s s')), suc (ensureSet (lub s s'))) - (Left _) => inScope "cannot infer type" $ fatal tm - (Right _) => inScope "cannot infer type" $ fatal tm - (Case t l out f g) => do - inScope "infer" $ trace $ map (\_ => "encountered case") tm - (t, ty@(Cnstr (Sum s s' a b)), s'') <- infer ctx t - | (_, ty, _) => inScope "wrong type to case" $ fatal (map (\_ => ty) tm) - inScope "infer" $ trace $ map (\_ => pretty {ann} "sum has type" <++> pretty ty) tm - l <- inferSort ctx l - inScope "infer" $ trace $ map (\_ => pretty {ann} "output has sort" <++> pretty l) tm - let ty' = Cnstr (Pi s'' (suc l) "x" ty (cast l)) - inScope "infer" $ trace $ map (\_ => pretty {ann} "checking output has type" <++> pretty ty') tm - out <- check ctx out ty' (s'' ~> suc l) - inScope "infer" $ trace $ map (\_ => "output is well typed") tm - outL <- doApp (weaken 1 out) (Cnstr (Left (Ntrl (Var "x" 0)))) - let fTy = Cnstr (Pi s l "x" a outL) - inScope "infer" $ trace $ map (\_ => pretty {ann} "checking left branch has type" <++> pretty fTy) tm - f <- check ctx f fTy (s ~> l) - inScope "infer" $ trace $ map (\_ => "left branch is well typed") tm - outR <- doApp (weaken 1 out) (Cnstr (Right (Ntrl (Var "x" 0)))) - let gTy = Cnstr (Pi s' l "x" b outR) - inScope "infer" $ trace $ map (\_ => pretty {ann} "checking right branch has type" <++> pretty gTy) tm - g <- check ctx g gTy (s' ~> l) - inScope "infer" $ trace $ map (\_ => "right branch is well typed") tm - res <- doCase t f g - out <- doApp out t - inScope "infer" $ trace $ map (\_ => pretty {ann} "final result is" <++> pretty res <+> softline <+> pretty "of type" <++> pretty out) tm - pure (res, out, l) - (Container a s' s'') => do - inScope "infer" $ trace $ map (\_ => "encountered container") tm - (a, s) <- inferType ctx a - inScope "infer" $ trace $ map (\_ => pretty {ann} "index has type" <++> pretty a) tm - s' <- inferSort ctx s' - inScope "infer" $ trace $ map (\_ => pretty {ann} "tag has sort" <++> pretty s') tm - s'' <- inferSort ctx s'' - inScope "infer" $ trace $ map (\_ => pretty {ann} "position has sort" <++> pretty s'') tm - pure (Cnstr (Container s a s' s''), cast (lub s (suc $ lub s' s'')), suc (lub s (suc $ lub s' s''))) - (MkContainer _ _ _) => inScope "cannot infer type" $ fatal tm - (Tag t) => do - inScope "infer" $ trace $ map (\_ => "encountered tag") tm - (t, ty@(Cnstr (Container s a s' s'')), _) <- infer ctx t - | (_, ty, _) => typeMismatch t.bounds (pretty "container") (pretty ty) - inScope "infer" $ trace $ map (\_ => pretty {ann} "deconstructing a container" <++> pretty ty) tm - tag <- doTag t - let out = tagTy s a s' - pure (tag, Cnstr out, s ~> suc s') - (Position t) => do - inScope "infer" $ trace $ map (\_ => "encountered position") tm - (t, ty@(Cnstr (Container s a s' s'')), _) <- infer ctx t - | (_, ty, _) => typeMismatch t.bounds (pretty "container") (pretty ty) - inScope "infer" $ trace $ map (\_ => pretty {ann} "deconstructing a container" <++> pretty ty) tm - tag <- doTag t - pos <- doPosition t - out <- positionTy s a s' tag s'' - pure (pos, Cnstr out, s ~> s' ~> suc s'') - (Next t) => do - inScope "infer" $ trace $ map (\_ => "encountered next") tm - (t, ty@(Cnstr (Container s a s' s'')), _) <- infer ctx t - | (_, ty, _) => typeMismatch t.bounds (pretty "container") (pretty ty) - inScope "infer" $ trace $ map (\_ => pretty {ann} "deconstructing a container" <++> pretty ty) tm - tag <- doTag t - pos <- doPosition t - next <- doNext t - out <- nextTy s a s' tag s'' pos - pure (next, Cnstr out, s ~> s' ~> s'' ~> s) - (Sem l b t) => do - inScope "infer" $ trace $ map (\_ => "encountered sem") tm - (t, ty@(Cnstr (Container s a s' s'')), _) <- infer ctx t - | (_, ty, _) => typeMismatch t.bounds (pretty "container") (pretty ty) - inScope "infer" $ trace $ map (\_ => pretty {ann} "interpretting a container" <++> pretty ty) tm - l <- inferSort ctx l - inScope "infer" $ trace $ map (\_ => pretty {ann} "output has sort" <++> pretty l) tm - let outTy = Cnstr (Pi s (suc l) "i" a (cast l)) - inScope "infer" $ trace $ map (\_ => pretty {ann} "checking output has type" <++> pretty outTy) tm - b <- check ctx b outTy (s ~> suc l) - inScope "infer" $ trace $ map (\_ => "output is well typed") tm - tag <- doTag t - pos <- doPosition t - next <- doNext t - let i = Ntrl (Var "i" 0) - tag <- doApp (weaken 1 tag) i - pos <- doApp (weaken 1 pos) i - next <- doApp (weaken 1 next) i - let t = Ntrl (Var "t" 0) - pos <- doApp (weaken 1 pos) t - next <- doApp (weaken 1 next) t - let p = Ntrl (Var "p" 0) - next <- doApp (weaken 1 next) p - out <- doApp (weaken 3 b) next - let out = Cnstr $ Lambda "i" $ - Cnstr $ Sigma s' (s'' ~> l) "t" tag $ - Cnstr $ Pi s'' l "p" pos out - let ty = Cnstr $ Pi s (suc (lub s' (s'' ~> l))) "i" a (cast (lub s' (s'' ~> l))) - pure (out, ty, suc (s ~> suc (lub s' (s'' ~> l)))) - Top => pure $ (Cnstr Top, cast Prop, Set 0) - Point => pure $ (Irrel, Cnstr Top, Prop) - Bottom => pure $ (Cnstr Bottom, cast Prop, Set 0) - (Absurd a t) => do - inScope "infer" $ trace $ map (\_ => "encountered absurd") tm - (a, s) <- inferType ctx a - inScope "infer" $ trace $ map (\_ => pretty {ann} "will fudge to type" <++> pretty a) tm - inScope "infer" $ trace $ map (\_ => pretty {ann} "checking for proof of false") tm - _ <- check ctx t (Cnstr Bottom) Prop - inScope "infer" $ trace $ map (\_ => "proof of false is well typed") tm - pure (Ntrl Absurd, a, s) + info "encountered second" + (s ** (ty@(Cnstr (Sigma l l' _ a b)), t)) <- infer ctx (assert_smaller tm t) + | (_ ** (ty, _)) => inBounds t.bounds $ typeMismatch (pretty "pair type") (pretty ty) + trace $ pretty {ann} "pair has type" <++> pretty ty + let Yes Refl = decEq s (max l l') + | No _ => fatal "internal sort mismatch" + let t = rewrite sym $ maxIsSet l l' in t + fst <- doFst (isSet l) (isSet l') t + ty <- subst1 fst b + tm <- doSnd (isSet l) (isSet l') t + pure (l' ** (ty, tm)) + Bool => do + info "encountered bool" + pure (Set 1 ** (cast (Set 0), Cnstr Bool)) + True => do + info "encountered true" + pure (Set 0 ** (Cnstr Bool, Cnstr True)) + False => do + info "encountered false" + pure (Set 0 ** (Cnstr Bool, Cnstr False)) + (If var a t u v) => do + info "encountered if" + trace "checking discriminant is bool" + t <- check ctx (Set 0) (Cnstr Bool) (assert_smaller tm t) + trace "discriminant is well typed" + (s, a) <- inferType (ctx ::< MkFreeVar (Set 0) (Cnstr Bool) var.val) (assert_smaller tm a) + ty <- subst1 (Cnstr True) a + trace $ pretty {ann} "checking true branch has type" <++> pretty ty + u <- check ctx s ty (assert_smaller tm u) + ty <- subst1 (Cnstr False) a + trace $ pretty {ann} "checking false branch has type" <++> pretty ty + v <- check ctx s ty (assert_smaller tm v) + ty <- subst1 t a + tm <- doIf t u v + pure (s ** (ty, tm)) + Top => do + info "encountered top" + pure (Set 0 ** (cast Prop, Cnstr Top)) + Point => do + info "encountered point" + pure (Prop ** (Cnstr Top, Irrel)) + Bottom => do + info "encountered bottom" + pure (Set 0 ** (cast Prop, Cnstr Bottom)) + (Absurd t) => fatal "cannot infer type of absurd" (Equal t u) => do - inScope "infer" $ trace $ map (\_ => "encountered equal") tm - (t, a, s) <- infer ctx t - inScope "infer" $ trace $ map (\_ => pretty {ann} "lhs has type" <++> pretty a) tm - inScope "infer" $ trace $ map (\_ => "checking rhs has same type") tm - u <- check ctx u a s - inScope "infer" $ trace $ map (\_ => "rhs is well typed") tm - res <- doEqual a t u - inScope "infer" $ trace $ map (\_ => pretty {ann} "equality computes to" <++> pretty res) tm - pure (res, cast Prop, Set 0) + info "encountered equal" + (s ** (a, t)) <- infer ctx (assert_smaller tm t) + trace $ pretty {ann} "left side has type" <++> pretty a + u <- check ctx s a (assert_smaller tm u) + trace "right side is well typed" + eq <- doEqual (isSet s) a t u + pure (Set 0 ** (cast Prop, eq)) (Refl t) => do - inScope "infer" $ trace $ map (\_ => "encountered refl") tm - (t, a, s) <- infer ctx t - inScope "infer" $ trace $ map (\_ => pretty {ann} "term has type" <++> pretty a) tm - ty <- doEqual a t t - inScope "infer" $ trace $ map (\_ => pretty {ann} "equality computes to" <++> pretty ty) tm - pure (Irrel, ty, Prop) - (Transp t b u t' e) => do - inScope "infer" $ trace $ map (\_ => "encountered transp") tm - (t, a, s) <- infer ctx t - inScope "infer" $ trace $ map (\_ => pretty {ann} "start index has type" <++> pretty a) tm - inScope "infer" $ trace $ map (\_ => "checking end index has same type") tm - t' <- check ctx t' a s - inScope "infer" $ trace $ map (\_ => "end index is well typed") tm - let ty = Cnstr (Pi s (Set 0) "_" a (cast Prop)) - inScope "infer" $ trace $ map (\_ => pretty {ann} "checkout output is in" <++> pretty ty) tm - b <- check ctx b ty s - inScope "infer" $ trace $ map (\_ => pretty {ann} "output is well typed") tm - inScope "infer" $ trace $ map (\_ => "checking equality type") tm - eq <- doEqual a t t' - _ <- check ctx e eq Prop - inScope "infer" $ trace $ map (\_ => "equality is well typed") tm - inScope "infer" $ trace $ map (\_ => "checking transformed value") tm - inTy <- doApp b t - _ <- check ctx u inTy Prop - inScope "infer" $ trace $ map (\_ => "transformed value is well typed") tm - outTy <- doApp b t' - inScope "infer" $ trace $ map (\_ => pretty {ann} "producing value of type" <++> pretty outTy) tm - pure (Irrel, outTy, Prop) - (Cast b e t) => do - inScope "infer" $ trace $ map (\_ => "encountered cast") tm - (t, a, s) <- infer ctx t - inScope "infer" $ trace $ map (\_ => pretty {ann} "input has type" <++> pretty a) tm - inScope "infer" $ trace $ map (\_ => "checking output has same sort") tm - b <- check ctx b (cast s) (suc s) - inScope "infer" $ trace $ map (\_ => "output is well sorted") tm - inScope "infer" $ trace $ map (\_ => "checking equality type") tm - eq <- doEqual (cast s) a b - _ <- check ctx e eq Prop - inScope "infer" $ trace $ map (\_ => "equality is well typed") tm - inScope "infer" $ trace $ map (\_ => pretty {ann} "producing value of type" <++> pretty b) tm - res <- doCastL a b t - pure (res, b, s) + info "encountered refl" + (s ** (a, t)) <- infer ctx (assert_smaller tm t) + trace "argument is well typed" + eq <- doEqual (isSet s) a t t + pure (Prop ** (eq, Irrel)) + (Transp b t u t' e) => do + info "encountered transp" + (s ** (a, t)) <- infer ctx (assert_smaller tm t) + trace $ pretty {ann} "index type is" <++> pretty a + t' <- check ctx s a (assert_smaller tm t') + trace "new index is well typed" + b <- check ctx (s ~> Set 0) (Cnstr $ Pi s (Set 0) "" a (cast Prop)) (assert_smaller tm b) + trace "transporting in Prop" + oldB <- doApp b t + u <- check ctx Prop oldB (assert_smaller tm u) + trace "old-indexed proposition is well typed" + eq <- doEqual (isSet s) a t t' + trace $ pretty {ann} "checking equality has type" <++> pretty eq + e <- check ctx Prop eq (assert_smaller tm e) + trace "equality is well typed" + newB <- doApp b t' + pure (Prop ** (newB, Irrel)) + (Cast a b e t) => do + info "encountered cast" + (s, a) <- inferType ctx (assert_smaller tm a) + trace $ pretty {ann} "old type is" <++> pretty a + b <- checkType ctx s (assert_smaller tm b) + trace $ pretty {ann} "new type is" <++> pretty b + eq <- doEqual True (cast s) a b + e <- check ctx Prop eq (assert_smaller tm e) + trace "equality is well typed" + t <- check ctx s a (assert_smaller tm t) + trace "value is well typed" + tm <- doCast (isSet s) a b t + pure (s ** (b, tm)) (CastId t) => do - inScope "infer" $ trace $ map (\_ => "encountered cast identity proof") tm - (t, a, s) <- infer ctx t - inScope "infer" $ trace $ map (\_ => pretty {ann} "term has type" <++> pretty a) tm - cast <- doCastL a a t - eq <- doEqual a cast t - inScope "infer" $ trace $ map (\_ => pretty {ann} "producing equality type" <++> pretty eq) tm - pure (Irrel, eq, Prop) - -inferType ctx a = do - (a, Cnstr (Sort s), _) <- infer ctx a - | (_, ty, _) => tag a.bounds (pretty "sort") (pretty ty) - pure (a, s) - -inferSort ctx a = do - (Cnstr (Sort s), _, _) <- infer ctx a - | (t, _, _) => inScope "infer" $ typeMismatch a.bounds (pretty "sort") (pretty t) - pure s + info "encountered castRefl" + (s ** (a, t)) <- infer ctx (assert_smaller tm t) + trace $ pretty {ann} "argument has type" <++> pretty a + lhs <- doCast (isSet s) a a t + ret <- doEqual (isSet s) a lhs t + pure (Prop ** (ret, Irrel)) -- Checking Definitions and Blocks --------------------------------------------- -partial -checkDef : Context n -> Term.Definition n -> Logging ann (NormalForm.Definition n) -checkDef ctx def = do - (ty, sort) <- - inferType {tag = \bounds, lhs, rhs => inScope "invalid declaration" $ mismatch bounds lhs rhs} +checkDef : Context ctx -> Term.Definition (length ctx) -> Logging ann (NormalForm.Definition ctx) +checkDef ctx def = inBounds def.name.bounds $ inScope "check" $ do + debug $ "inferring type of \{def.name.val}" + (sort, ty) <- + inferType {tag = \lhs, rhs => inScope "invalid declaration" $ mismatch lhs rhs} (fromContext ctx) def.ty - inScope "check" $ debug $ map (\name => pretty {ann} "\{name} has type" <++> pretty ty) def.name - tm <- check (fromContext ctx) def.tm ty sort - inScope "check" $ debug $ map (\name => pretty {ann} "\{name} is well typed with value" <++> pretty tm) def.name + debug $ pretty {ann} "\{def.name.val} has type" <++> pretty ty + tm <- check (fromContext ctx) sort ty def.tm + debug $ pretty {ann} "\{def.name.val} is well typed with value" <++> pretty tm pure $ MkDefinition {name = def.name, ty, tm, sort} -partial export -checkBlock : Block n -> Logging ann (Context n) -checkBlock [] = pure [] +checkBlock : Block n -> Logging ann (ctx ** (Context ctx, length ctx = n)) +checkBlock [] = pure ([] ** ([], Refl)) checkBlock (blk :< def) = do - ctx <- checkBlock blk + (_ ** (ctx, Refl)) <- checkBlock blk def <- checkDef ctx def - pure (ctx :< def) + pure (_ ** (ctx :< def, Refl)) |