summaryrefslogtreecommitdiff
path: root/src/Obs/Typing.idr
diff options
context:
space:
mode:
Diffstat (limited to 'src/Obs/Typing.idr')
-rw-r--r--src/Obs/Typing.idr468
1 files changed, 308 insertions, 160 deletions
diff --git a/src/Obs/Typing.idr b/src/Obs/Typing.idr
index 7bb5deb..b3762cf 100644
--- a/src/Obs/Typing.idr
+++ b/src/Obs/Typing.idr
@@ -48,11 +48,31 @@ MkPair s@(Set _) s' t u = Cnstr $ Pair s s' Set t u
-- Checking and Inference ------------------------------------------------------
+check' : (tyCtx : TyContext ctx)
+ -> (s : Universe)
+ -> TypeNormalForm ctx
+ -> Term (length ctx)
+ -> Logging ann (NormalForm (relevance s) ctx)
+
+infer' : (tyCtx : TyContext ctx)
+ -> Term (length ctx)
+ -> Logging ann (s ** (TypeNormalForm ctx, NormalForm (relevance s) ctx))
+
+inferType' : {default typeMismatch tag : forall a . Doc ann -> Doc ann -> Logging ann a}
+ -> (tyCtx : TyContext ctx)
+ -> Term (length ctx)
+ -> Logging ann (Universe, TypeNormalForm ctx)
+inferType' ctx t = do
+ (Set _ ** (Cnstr (Universe s), a)) <- infer' ctx t
+ | (_ ** (type, a)) => tag (pretty "sort") (pretty type)
+ pure (s, a)
+
check : (tyCtx : TyContext ctx)
-> (s : Universe)
-> TypeNormalForm ctx
-> WithBounds (Term (length ctx))
-> Logging ann (NormalForm (relevance s) ctx)
+check ctx s a (MkBounded t irrel bounds) = inBounds (MkBounded (check' ctx s a t) irrel bounds)
checkType : (tyCtx : TyContext ctx)
-> (s : Universe)
@@ -63,212 +83,340 @@ checkType ctx s tm = check ctx (succ s) (cast s) tm
infer : (tyCtx : TyContext ctx)
-> WithBounds (Term (length ctx))
-> Logging ann (s ** (TypeNormalForm ctx, NormalForm (relevance s) ctx))
+infer ctx (MkBounded t irrel bounds) = inBounds (MkBounded (infer' ctx t) irrel bounds)
inferType : {default typeMismatch tag : forall a . Doc ann -> Doc ann -> Logging ann a}
-> (tyCtx : TyContext ctx)
-> WithBounds (Term (length ctx))
-> Logging ann (Universe, TypeNormalForm ctx)
-inferType ctx tm = inBounds tm.bounds $ do
- (Set _ ** (Cnstr (Universe s), a)) <- infer ctx tm
- | (_ ** (a, t)) => tag (pretty "universe") (pretty a)
- pure (s, a)
+inferType ctx (MkBounded t irrel bounds) = inBounds (MkBounded (inferType' ctx t) irrel bounds)
+
+check' ctx sort (Cnstr (Pi domainSort codomainSort _ domain codomain)) (Lambda {var, body}) = do
+ info "encountered lambda"
+
+ let Yes Refl = decEq sort (domainSort ~> codomainSort)
+ | No _ => fatal "internal universe mismatch"
+
+ let bodyCtx = ctx ::< MkFreeVar domainSort domain var.val
+
+ trace $ pretty {ann} "checking body has type" <++> pretty codomainSort
+ body <- check bodyCtx codomainSort codomain body
+
+ pure $ case codomainSort of
+ Prop => Irrel
+ Set _ => Cnstr (Lambda domainSort var.val body)
+
+check' ctx sort type (Lambda {var, body}) = typeMismatch (pretty "function") (pretty type)
+
+check' ctx sort (Cnstr (Sigma indexSort elementSort var index element)) (Pair {first, second}) = do
+ info "encountered pair"
+
+ let Yes Refl = decEq sort (max indexSort elementSort)
+ | No _ => fatal "internal universe mismatch"
+
+ trace $ pretty {ann} "checking first has type" <++> pretty index
+ first <- check ctx indexSort index first
+
+ element <- subst1 first element
+ trace $ pretty {ann} "checking second has type" <++> pretty element
+ second <- check ctx elementSort element second
+
+ pure $ MkPair indexSort elementSort first second
+
+check' ctx sort type (Pair {first, second}) = typeMismatch (pretty "pair type") (pretty type)
+
+check' ctx sort type (Absurd {contradiction}) = do
+ info "encountered absurd"
+
+ trace "checking proof of contradiction"
+ Irrel <- check ctx Prop (Cnstr Bottom) contradiction
+
+ pure $ doAbsurd _
+
+check' ctx sort type t = do
+ info "falling through to inference"
+
+ (inferredSort ** (inferredType, value)) <- infer' ctx t
+ trace $ pretty {ann} "inferred type is" <++> pretty inferredType
+
+ let Yes Refl = decEq sort inferredSort
+ | No _ => typeMismatch (pretty type) (pretty inferredType)
+
+ expandedType <- subst type (reduce ctx)
+ expandedInferredType <- subst inferredType (reduce ctx)
+
+ Just _ <- inScope "convert" $ runMaybeT $ convert (succ sort) (cast sort) expandedType expandedInferredType
+ | Nothing => inScope "conversion failed" $ mismatch (pretty type) (pretty inferredType)
+
+ pure value
+
+
+infer' ctx tm@(Var {var, i}) = do
+ info $ pretty {ann} "encountered variable" <++> pretty tm
-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 universe 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
- 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 universe 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 (succ s) (cast s) a' b'
- | Nothing => inScope "conversion failed" $ mismatch (pretty a) (pretty b)
- pure t
-
-infer ctx tm = inBounds tm.bounds $ case tm.val of
- (Var var i) => do
- info $ pretty {ann} "encountered variable" <++> pretty tm.val
let def = index' ctx i
pure (def.sort ** (def.ty, def.tm))
- (Universe s) => do
- info $ pretty {ann} "encountered universe" <++> pretty tm.val
+
+infer' ctx (Universe {s}) = do
+ info $ pretty {ann} "encountered universe" <++> pretty s
+
pure (succ (succ s) ** (cast (succ s), cast s))
- (Pi var a b) => do
+
+infer' ctx (Pi {var, domain, codomain}) = do
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 (succ (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
+
+ (domainSort, domain) <- inferType ctx domain
+ trace $ pretty {ann} "domain type is" <++> pretty domain
+
+ let domainVar = MkFreeVar domainSort domain var.val
+ let codomainCtx = ctx ::< domainVar
+
+ (codomainSort, codomain) <- inferType codomainCtx codomain
+ trace $ pretty {ann} "codomain type is" <++> pretty codomain
+
+ let piSort = domainVar.sort ~> codomainSort
+ let term = Cnstr (Pi domainVar.sort codomainSort var.val domain codomain)
+ pure (succ piSort ** (cast piSort, term))
+
+infer' ctx (Lambda {var, body}) = fatal "cannot infer type of lambda"
+
+infer' ctx (App {fun, arg}) = do
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')
+
+ (piSort ** (funType, funValue)) <- infer ctx fun
+ trace $ pretty {ann} "function has type" <++> pretty funType
+
+ let Cnstr (Pi domainSort codomainSort _ domain codomain) = funType
+ | _ => inBounds $ map (const $ typeMismatch (pretty "function") (pretty funType)) fun
+
+ let Yes Refl = decEq piSort (domainSort ~> codomainSort)
| No _ => fatal "internal universe mismatch"
- ty <- subst1 u b
- tm <- doApp t u
- pure (l' ** (ty, rewrite sym $ functionRelevance l l' in tm))
- (Sigma var a b) => do
+
+ let fun = funValue
+
+ trace $ pretty {ann} "checking argument has type" <++> pretty domain
+ arg <- check ctx domainSort domain arg
+ trace $ pretty {ann} "argument is well typed"
+
+ returnType <- subst1 arg codomain
+ returnValue <- doApp fun arg
+
+ let returnValue = rewrite sym $ functionRelevance domainSort codomainSort in returnValue
+
+ pure (codomainSort ** (returnType, returnValue))
+
+infer' ctx (Sigma {var, index, element}) = do
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 (succ (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
+
+ (indexSort, index) <- inferType ctx index
+ trace $ pretty {ann} "index type is" <++> pretty index
+
+ let indexVar = MkFreeVar indexSort index var.val
+ let elementCtx = ctx ::< indexVar
+
+ (elementSort, element) <- inferType elementCtx element
+ trace $ pretty {ann} "element type is" <++> pretty element
+
+ let sigmaSort = max indexVar.sort elementSort
+ let term = Cnstr (Sigma indexVar.sort elementSort var.val index element)
+ pure (succ sigmaSort ** (cast sigmaSort, term))
+
+infer' ctx (Pair {first, second}) = fatal "cannot infer type of pair"
+
+infer' ctx (First {arg}) = do
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')
+
+ (sigmaSort ** (argType, argValue)) <- infer ctx arg
+ trace $ pretty {ann} "pair has type" <++> pretty argType
+
+ let Cnstr (Sigma indexSort elementSort _ index element) = argType
+ | _ => inBounds $ map (const $ typeMismatch (pretty "pair type") (pretty argType)) arg
+
+ let Yes Refl = decEq sigmaSort (max indexSort elementSort)
| No _ => fatal "internal universe mismatch"
- let ty = a
- tm <- doFst (relevance l) (relevance l') (rewrite sym $ pairRelevance l l' in t)
- pure (l ** (ty, tm))
- (Snd t) => do
+
+ let argValue = rewrite sym $ pairRelevance indexSort elementSort in argValue
+
+ let returnType = index
+ returnValue <- doFst (relevance indexSort) (relevance elementSort) argValue
+
+ pure (indexSort ** (returnType, returnValue))
+
+infer' ctx (Second {arg}) = do
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')
+
+ (sigmaSort ** (argType, argValue)) <- infer ctx arg
+ trace $ pretty {ann} "pair has type" <++> pretty argType
+
+ let Cnstr (Sigma indexSort elementSort _ index element) = argType
+ | _ => inBounds $ map (const $ typeMismatch (pretty "pair type") (pretty argType)) arg
+
+ let Yes Refl = decEq sigmaSort (max indexSort elementSort)
| No _ => fatal "internal universe mismatch"
- let t = rewrite sym $ pairRelevance l l' in t
- fst <- doFst (relevance l) (relevance l') t
- ty <- subst1 fst b
- tm <- doSnd (relevance l) (relevance l') t
- pure (l' ** (ty, tm))
- Bool => do
+
+ let argValue = rewrite sym $ pairRelevance indexSort elementSort in argValue
+
+ indexValue <- doFst (relevance indexSort) (relevance elementSort) argValue
+ returnType <- subst1 indexValue element
+ returnValue <- doSnd (relevance indexSort) (relevance elementSort) argValue
+
+ pure (elementSort ** (returnType, returnValue))
+
+infer' ctx Bool = do
info "encountered bool"
pure (Set 1 ** (cast (Set 0), Cnstr Bool))
- True => do
+
+infer' ctx True = do
info "encountered true"
pure (Set 0 ** (Cnstr Bool, Cnstr True))
- False => do
+
+infer' ctx False = do
info "encountered false"
pure (Set 0 ** (Cnstr Bool, Cnstr False))
- (If var a t u v) => do
+
+infer' ctx (If {var, returnType, discriminant, true, false}) = do
info "encountered if"
trace "checking discriminant is bool"
- t <- check ctx (Set 0) (Cnstr Bool) (assert_smaller tm t)
+
+ discriminant <- check ctx (Set 0) (Cnstr Bool) discriminant
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
+
+ let returnTypeCtx = ctx ::< MkFreeVar (Set 0) (Cnstr Bool) var.val
+
+ (returnSort, returnType) <- inferType returnTypeCtx returnType
+ trace $ pretty {ann} "result is an index of type" <++> pretty returnType
+
+ trueType <- subst1 (Cnstr True) returnType
+ trace $ pretty {ann} "checking true branch has type" <++> pretty trueType
+ true <- check ctx returnSort trueType true
+ trace "true branch is well typed"
+
+ falseType <- subst1 (Cnstr False) returnType
+ trace $ pretty {ann} "checking false branch has type" <++> pretty falseType
+ false <- check ctx returnSort falseType false
+ trace "false branch is well typed"
+
+ returnType <- subst1 discriminant returnType
+ returnValue <- doIf discriminant true false
+
+ pure (returnSort ** (returnType, returnValue))
+
+infer' ctx Top = do
info "encountered top"
pure (Set 0 ** (Cnstr (Universe Prop), Cnstr Top))
- Point => do
+
+infer' ctx Point = do
info "encountered point"
pure (Prop ** (Cnstr Top, Irrel))
- Bottom => do
+
+infer' ctx Bottom = do
info "encountered bottom"
pure (Set 0 ** (Cnstr (Universe Prop), Cnstr Bottom))
- (Absurd t) => fatal "cannot infer type of absurd"
- (Equal t u) => do
+
+infer' ctx (Absurd {contradiction}) = fatal "cannot infer type of absurd"
+
+infer' ctx (Equal {left, right}) = do
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)
+
+ (sort ** (type, left)) <- infer ctx left
+ trace $ pretty {ann} "left side has type" <++> pretty type
+
+ right <- check ctx sort type right
trace "right side is well typed"
- eq <- doEqual (relevance s) a t u
- pure (Set 0 ** (Cnstr (Universe Prop), eq))
- (Refl t) => do
+
+ let equalitySort = Prop
+ equalityType <- doEqual (relevance sort) type left right
+
+ pure (succ equalitySort ** (cast equalitySort, equalityType))
+
+infer' ctx (Refl {value}) = do
info "encountered refl"
- (s ** (a, t)) <- infer ctx (assert_smaller tm t)
- trace "argument is well typed"
- eq <- doEqual (relevance s) a t t
- pure (Prop ** (eq, Irrel))
- (Transp b t u t' e) => do
+
+ (sort ** (type, value)) <- infer ctx value
+ trace $ pretty {ann} "value has type" <++> pretty type
+
+ equalityType <- doEqual (relevance sort) type value value
+
+ pure (Prop ** (equalityType, Irrel))
+
+infer' ctx (Transp {indexedType, oldIndex, value, newIndex, equality}) = 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')
+
+ (indexSort ** (indexType, oldIndex)) <- infer ctx oldIndex
+ trace $ pretty {ann} "index type is" <++> pretty indexType
+
+ newIndex <- check ctx indexSort indexType newIndex
trace "new index is well typed"
- b <- check ctx (s ~> Set 0) (Cnstr $ Pi s (Set 0) "" a (Cnstr (Universe 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 (relevance s) a t t'
- trace $ pretty {ann} "checking equality has type" <++> pretty eq
- e <- check ctx Prop eq (assert_smaller tm e)
+
+ let indexedTypeShape = Cnstr $ Pi indexSort (Set 0) "" indexType (Cnstr (Universe Prop))
+ indexedType <- check ctx (indexSort ~> Set 0) indexedTypeShape indexedType
+ trace $ pretty {ann} "result is an index of type" <++> pretty indexedType
+
+ oldType <- doApp indexedType oldIndex
+ trace $ pretty {ann} "checking value has type" <++> pretty oldType
+ Irrel <- check ctx Prop oldType value
+ trace "value is well typed"
+
+ equalityType <- doEqual (relevance indexSort) indexType oldIndex newIndex
+ trace $ pretty {ann} "checking equality has type" <++> pretty equalityType
+ equality <- check ctx Prop equalityType equality
trace "equality is well typed"
- newB <- doApp b t'
- pure (Prop ** (newB, Irrel))
- (Cast a b e t) => do
+
+ returnType <- doApp indexedType newIndex
+
+ pure (Prop ** (returnType, Irrel))
+
+infer' ctx (Cast {oldType, newType, equality, value}) = 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 Relevant (cast s) a b
- e <- check ctx Prop eq (assert_smaller tm e)
+
+ (sort, oldType) <- inferType ctx oldType
+ trace $ pretty {ann} "old type is" <++> pretty oldType
+
+ newType <- checkType ctx sort newType
+ trace $ pretty {ann} "new type is" <++> pretty newType
+
+ equalityType <- doEqual Relevant (cast sort) oldType newType
+ trace $ pretty {ann} "checking equality has type" <++> pretty equalityType
+ equality <- check ctx Prop equalityType equality
trace "equality is well typed"
- t <- check ctx s a (assert_smaller tm t)
+
+ trace $ pretty {ann} "checking value has type" <++> pretty oldType
+ value <- check ctx sort oldType value
trace "value is well typed"
- tm <- doCast (relevance s) a b t
- pure (s ** (b, tm))
- (CastId t) => do
+
+ returnValue <- doCast (relevance sort) oldType newType value
+
+ pure (sort ** (newType, returnValue))
+
+infer' ctx (CastId {value}) = do
info "encountered castRefl"
- (s ** (a, t)) <- infer ctx (assert_smaller tm t)
- trace $ pretty {ann} "argument has type" <++> pretty a
- lhs <- doCast (relevance s) a a t
- ret <- doEqual (relevance s) a lhs t
- pure (Prop ** (ret, Irrel))
+
+ (sort ** (type, value)) <- infer ctx value
+ trace $ pretty {ann} "value has type" <++> pretty value
+
+ castRefl <- doCast (relevance sort) type type value
+
+ returnType <- doEqual (relevance sort) type castRefl value
+
+ pure (Prop ** (returnType, Irrel))
-- Checking Definitions and Blocks ---------------------------------------------
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
- 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}
+checkDef ctx def =
+ let block = do
+ debug $ "inferring type of \{def.name.val}"
+ (sort, ty) <-
+ inferType {tag = \lhs, rhs => inScope "invalid declaration" $ mismatch lhs rhs}
+ (fromContext ctx) def.ty
+ 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}
+
+ in inBounds $ map (const $ inScope "check" block) def.name
export
checkBlock : Block n -> Logging ann (ctx ** (Context ctx, length ctx = n))