module Check where
open import Prelude
open import Prelude.Pretty
open import Exp
open import Term
private
variable
a b : Ty
Γ : Context
data CheckError : Set where
unboundIdentifier : Ident → _
applyNonFunction : Ty → Exp → _
inferUntypedLambda : _
notSubtype : (a b : Ty) → _
data Scope : Context → Set where
empty : Scope []
cons : (x : Ident) (a : Ty) (sc : Scope Γ) → Scope (a ∷ Γ)
lookupIdent : Scope Γ → Ident → Maybe (∃ λ a → a ∈ Γ)
lookupIdent empty x = nothing
lookupIdent (cons y a sc) x =
case y String.≟ x of λ where
(yes _) → just (a , zero)
(no _) → case lookupIdent sc x of λ where
(just (a , x)) → just (a , suc x)
nothing → nothing
data Infer (Γ : Context) : Set where
inferred : (a : Ty) (t : Term Γ a) → _
failed : (err : CheckError) → _
data Check (Γ : Context) (a : Ty) : Set where
checked : (t : Term Γ a) → _
failed : (err : CheckError) → _
mutual
infer : Scope Γ → Exp → Infer Γ
infer sc (var x) =
case lookupIdent sc x of λ where
nothing → failed (unboundIdentifier x)
(just (a , y)) → inferred a (var y)
infer sc (app f e) =
case infer sc f of λ where
(inferred (a ⇒ b) t) →
case check sc e a of λ where
(checked u) → inferred b (app t u)
(failed err) → failed err
(inferred a t) → failed (applyNonFunction a e)
(failed err) → failed err
infer sc (abs (uBind x) e) = failed inferUntypedLambda
infer sc (abs (tBind x a) e) =
case infer (cons x a sc) e of λ where
(inferred b t) → inferred (a ⇒ b) (abs t)
(failed err) → failed err
check : Scope Γ → Exp → (a : Ty) → Check Γ a
check sc (abs (uBind x) e) (a ⇒ c) =
case check (cons x a sc) e c of λ where
(checked t) → checked (abs t)
(failed err) → failed err
check sc e a =
case infer sc e of λ where
(inferred b u) →
case eqType b a of λ where
(yes refl) → checked u
(no _) → failed (notSubtype b a)
(failed err) → failed err
prettyCheckError : CheckError → String
prettyCheckError (unboundIdentifier x) = "unbound identifier"
prettyCheckError (applyNonFunction x x₁) = "application of non-function"
prettyCheckError inferUntypedLambda = "cannot infer untyped lambda"
prettyCheckError (notSubtype a b) =
"inferred type" <+> prettyTy a <+> "does not match expected type" <+> prettyTy b