quox/lib/Quox/Typing/Error.idr

405 lines
13 KiB
Idris
Raw Normal View History

2023-03-13 16:41:57 -04:00
module Quox.Typing.Error
2023-05-01 21:06:25 -04:00
import Quox.Loc
2023-03-13 16:41:57 -04:00
import Quox.Syntax
2024-04-14 09:48:43 -04:00
import Quox.Syntax.Builtin
2023-03-13 16:41:57 -04:00
import Quox.Typing.Context
import Quox.Typing.EqMode
import Quox.Pretty
import Data.List
2023-03-31 13:23:30 -04:00
import Control.Eff
2023-09-17 13:09:54 -04:00
import Derive.Prelude
%language ElabReflection
%hide TT.Name
2023-03-13 16:41:57 -04:00
2023-10-19 23:28:42 -04:00
%default total
2023-03-13 16:41:57 -04:00
public export
2023-04-01 13:16:43 -04:00
data Error
2024-05-27 15:28:22 -04:00
= ExpectedTYPE Loc (NameContexts q d n) (Term q d n)
| ExpectedPi Loc (NameContexts q d n) (Term q d n)
| ExpectedSig Loc (NameContexts q d n) (Term q d n)
| ExpectedEnum Loc (NameContexts q d n) (Term q d n)
| ExpectedEq Loc (NameContexts q d n) (Term q d n)
| ExpectedNAT Loc (NameContexts q d n) (Term q d n)
| ExpectedSTRING Loc (NameContexts q d n) (Term q d n)
| ExpectedBOX Loc (NameContexts q d n) (Term q d n)
| ExpectedIOState Loc (NameContexts q d n) (Term q d n)
2024-04-14 09:48:43 -04:00
| BadUniverse Loc Universe Universe
| TagNotIn Loc TagVal (SortedSet TagVal)
| BadCaseEnum Loc (SortedSet TagVal) (SortedSet TagVal)
2024-05-27 15:28:22 -04:00
| BadQtys Loc String (TyContext q d n) (List (QOutput q n, Term q d n))
2023-03-13 16:41:57 -04:00
-- first term arg of ClashT is the type
2024-05-27 15:28:22 -04:00
| ClashT Loc (EqContext q n) EqMode (Term q 0 n) (Term q 0 n) (Term q 0 n)
| ClashTy Loc (EqContext q n) EqMode (Term q 0 n) (Term q 0 n)
| ClashE Loc (EqContext q n) EqMode (Elim q 0 n) (Elim q 0 n)
2023-05-01 21:06:25 -04:00
| ClashU Loc EqMode Universe Universe
2024-05-27 15:28:22 -04:00
| ClashQ Loc (BContext q) (Qty q) (Qty q)
2023-05-01 21:06:25 -04:00
| NotInScope Loc Name
2023-03-13 16:41:57 -04:00
2024-05-27 15:28:22 -04:00
| NotType Loc (TyContext q d n) (Term q d n)
| WrongType Loc (EqContext q n) (Term q 0 n) (Term q 0 n)
2023-03-13 16:41:57 -04:00
2024-04-14 09:48:43 -04:00
| WrongBuiltinType Builtin Error
2024-05-27 15:28:22 -04:00
| ExpectedSingleEnum Loc (NameContexts q d n) (Term q d n)
2024-04-14 09:48:43 -04:00
2023-05-01 21:06:25 -04:00
| MissingEnumArm Loc TagVal (List TagVal)
2023-04-15 09:13:01 -04:00
2023-03-13 16:41:57 -04:00
-- extra context
| WhileChecking
2024-05-27 15:28:22 -04:00
(TyContext q d n) SQty
(Term q d n) -- term
(Term q d n) -- type
2023-04-01 13:16:43 -04:00
Error
2023-03-13 16:41:57 -04:00
| WhileCheckingTy
2024-05-27 15:28:22 -04:00
(TyContext q d n)
(Term q d n)
2023-03-13 16:41:57 -04:00
(Maybe Universe)
2023-04-01 13:16:43 -04:00
Error
2023-03-13 16:41:57 -04:00
| WhileInferring
2024-05-27 15:28:22 -04:00
(TyContext q d n) SQty
(Elim q d n)
2023-04-01 13:16:43 -04:00
Error
2023-03-13 16:41:57 -04:00
| WhileComparingT
2024-05-27 15:28:22 -04:00
(EqContext q n) EqMode SQty
(Term q 0 n) -- type
(Term q 0 n) (Term q 0 n) -- lhs/rhs
2023-04-01 13:16:43 -04:00
Error
2023-03-13 16:41:57 -04:00
| WhileComparingE
2024-05-27 15:28:22 -04:00
(EqContext q n) EqMode SQty
(Elim q 0 n) (Elim q 0 n)
2023-04-01 13:16:43 -04:00
Error
2023-03-13 16:41:57 -04:00
%name Error err
2024-05-27 15:28:22 -04:00
-- %runElab derive "Error" [Show]
2023-03-13 16:41:57 -04:00
public export
2023-04-01 13:16:43 -04:00
ErrorEff : Type -> Type
ErrorEff = Except Error
2023-03-13 16:41:57 -04:00
export
Located Error where
2024-04-14 09:48:43 -04:00
(ExpectedTYPE loc _ _).loc = loc
(ExpectedPi loc _ _).loc = loc
(ExpectedSig loc _ _).loc = loc
(ExpectedEnum loc _ _).loc = loc
(ExpectedEq loc _ _).loc = loc
(ExpectedNAT loc _ _).loc = loc
(ExpectedSTRING loc _ _).loc = loc
(ExpectedBOX loc _ _).loc = loc
(ExpectedIOState loc _ _).loc = loc
(BadUniverse loc _ _).loc = loc
(TagNotIn loc _ _).loc = loc
(BadCaseEnum loc _ _).loc = loc
(BadQtys loc _ _ _).loc = loc
(ClashT loc _ _ _ _ _).loc = loc
(ClashTy loc _ _ _ _).loc = loc
(ClashE loc _ _ _ _).loc = loc
(ClashU loc _ _ _).loc = loc
2024-05-27 15:28:22 -04:00
(ClashQ loc _ _ _).loc = loc
2024-04-14 09:48:43 -04:00
(NotInScope loc _).loc = loc
(NotType loc _ _).loc = loc
(WrongType loc _ _ _).loc = loc
(WrongBuiltinType _ err).loc = err.loc
(ExpectedSingleEnum loc _ _).loc = loc
(MissingEnumArm loc _ _).loc = loc
(WhileChecking _ _ _ _ err).loc = err.loc
(WhileCheckingTy _ _ _ err).loc = err.loc
(WhileInferring _ _ _ err).loc = err.loc
(WhileComparingT _ _ _ _ _ _ err).loc = err.loc
(WhileComparingE _ _ _ _ _ err).loc = err.loc
2023-03-13 16:41:57 -04:00
||| separates out all the error context layers
||| (e.g. "while checking s : A, …")
export
2023-04-01 13:16:43 -04:00
explodeContext : Error -> (List (Error -> Error), Error)
2023-05-14 13:58:46 -04:00
explodeContext (WhileChecking ctx x s t err) =
mapFst (WhileChecking ctx x s t ::) $ explodeContext err
explodeContext (WhileCheckingTy ctx s k err) =
mapFst (WhileCheckingTy ctx s k ::) $ explodeContext err
explodeContext (WhileInferring ctx x e err) =
mapFst (WhileInferring ctx x e ::) $ explodeContext err
explodeContext (WhileComparingT ctx x sg s t r err) =
mapFst (WhileComparingT ctx x sg s t r ::) $ explodeContext err
explodeContext (WhileComparingE ctx x sg e f err) =
mapFst (WhileComparingE ctx x sg e f ::) $ explodeContext err
2023-05-14 13:58:46 -04:00
explodeContext err = ([], err)
2023-03-13 16:41:57 -04:00
||| leaves the outermost context layer, and the innermost (up to) n, and removes
||| the rest if there are more than n+1 in total
export
2023-04-01 13:16:43 -04:00
trimContext : Nat -> Error -> Error
2023-03-13 16:41:57 -04:00
trimContext n err =
case explodeContext err of
([], err) => err
(f :: fs, err) => f $ foldr apply err $ takeEnd n fs
where
takeEnd : Nat -> List a -> List a
takeEnd n = reverse . take n . reverse
2023-03-31 13:23:30 -04:00
private
expect : Has (Except e) fs =>
(a -> a -> e) -> (a -> a -> Bool) -> a -> a -> Eff fs ()
expect err cmp x y = unless (x `cmp` y) $ throw $ err x y
2023-03-13 16:41:57 -04:00
2024-05-27 15:28:22 -04:00
parameters {auto _ : Has ErrorEff fs} (loc : Loc) (ctx : BContext q)
2023-03-13 16:41:57 -04:00
export %inline
2024-05-27 15:28:22 -04:00
expectEqualQ : Qty q -> Qty q -> Eff fs ()
expectEqualQ = expect (ClashQ loc ctx) (==)
-- [fixme] probably replace (==)
2023-03-13 16:41:57 -04:00
export %inline
2024-05-27 15:28:22 -04:00
expectCompatQ : Qty q -> Qty q -> Eff fs ()
expectCompatQ = expect (ClashQ loc ctx) compat
2023-03-13 16:41:57 -04:00
export %inline
2023-03-31 13:23:30 -04:00
expectModeU : EqMode -> Universe -> Universe -> Eff fs ()
2023-05-01 21:06:25 -04:00
expectModeU mode = expect (ClashU loc mode) $ ucmp mode
2023-03-13 16:41:57 -04:00
2023-03-15 10:54:51 -04:00
private
2023-05-14 13:58:46 -04:00
prettyMode : EqMode -> String
2023-03-15 10:54:51 -04:00
prettyMode Equal = "equal to"
prettyMode Sub = "a subtype of"
prettyMode Super = "a supertype of"
private
2023-05-14 13:58:46 -04:00
prettyModeU : EqMode -> String
2023-03-15 10:54:51 -04:00
prettyModeU Equal = "equal to"
prettyModeU Sub = "less than or equal to"
prettyModeU Super = "greater than or equal to"
private
2023-05-14 13:58:46 -04:00
isTypeInUniverse : Maybe Universe -> String
2023-03-15 10:54:51 -04:00
isTypeInUniverse Nothing = "is a type"
2023-05-14 13:58:46 -04:00
isTypeInUniverse (Just k) = "is a type in universe \{show k}"
2023-03-15 10:54:51 -04:00
2023-05-14 13:58:46 -04:00
private
2024-05-27 15:28:22 -04:00
filterSameQtys : BContext n -> List (QOutput q n, z) ->
Exists $ \n' => (BContext n', List (QOutput q n', z))
2023-05-14 13:58:46 -04:00
filterSameQtys [<] qts = Evidence 0 ([<], qts)
filterSameQtys (ns :< n) qts =
let (qs, qts) = unzip $ map (\(qs :< q, t) => (q, qs, t)) qts
Evidence l (ns, qts) = filterSameQtys ns qts
in
if allSame qs
then Evidence l (ns, qts)
else Evidence (S l) (ns :< n, zipWith (\(qs, t), q => (qs :< q, t)) qts qs)
where
2024-05-27 15:28:22 -04:00
allSame : List (Qty q) -> Bool
2023-05-14 13:58:46 -04:00
allSame [] = True
allSame (q :: qs) = all (== q) qs
private
2024-05-27 15:28:22 -04:00
printCaseQtys : {opts : _} -> TyContext q d n ->
BContext n' -> List (QOutput q n', Term q d n) ->
2023-05-14 13:58:46 -04:00
Eff Pretty (List (Doc opts))
printCaseQtys ctx ns qts =
let Evidence _ (ns, qts) = filterSameQtys ns qts in
traverse (line ns) qts
where
2024-05-27 15:28:22 -04:00
line : BContext l -> (QOutput q l, Term q d n) -> Eff Pretty (Doc opts)
line ns (qs, t) =
let Val q = ctx.qtyLen; names = ctx.names in
map (("-" <++>) . sep) $ sequence
2023-05-14 13:58:46 -04:00
[hangDSingle "the term"
2024-05-27 15:28:22 -04:00
!(prettyTerm names t),
2023-05-14 13:58:46 -04:00
hangDSingle "uses variables" $
separateTight !commaD $ toSnocList' !(traverse prettyTBind ns),
hangDSingle "with quantities" $
2024-05-27 15:28:22 -04:00
separateTight !commaD $ toSnocList' !(traverse (prettyQty names) qs)]
2023-05-14 13:58:46 -04:00
2023-10-19 23:28:42 -04:00
parameters {opts : LayoutOpts} (showContext : Bool)
export
inContext' : Bool -> a -> (a -> Eff Pretty (Doc opts)) ->
Doc opts -> Eff Pretty (Doc opts)
inContext' null ctx f doc =
if showContext && not null then
2023-12-21 12:03:57 -05:00
vappend doc <$> hangDSingle "in context" !(f ctx)
2023-10-19 23:28:42 -04:00
else pure doc
2023-05-14 13:58:46 -04:00
2023-10-19 23:28:42 -04:00
export %inline
2024-05-27 15:28:22 -04:00
inTContext : TyContext q d n -> Doc opts -> Eff Pretty (Doc opts)
2023-10-19 23:28:42 -04:00
inTContext ctx = inContext' (null ctx) ctx prettyTyContext
2023-05-14 13:58:46 -04:00
2023-10-19 23:28:42 -04:00
export %inline
2024-05-27 15:28:22 -04:00
inEContext : EqContext q n -> Doc opts -> Eff Pretty (Doc opts)
2023-10-19 23:28:42 -04:00
inEContext ctx = inContext' (null ctx) ctx prettyEqContext
2023-05-14 13:58:46 -04:00
2023-10-19 23:28:42 -04:00
export
prettyErrorNoLoc : Error -> Eff Pretty (Doc opts)
prettyErrorNoLoc err0 = case err0 of
ExpectedTYPE _ ctx s =>
hangDSingle "expected a type universe, but got"
2024-05-27 15:28:22 -04:00
!(prettyTerm ctx s)
2023-10-19 23:28:42 -04:00
ExpectedPi _ ctx s =>
hangDSingle "expected a function type, but got"
2024-05-27 15:28:22 -04:00
!(prettyTerm ctx s)
2023-10-19 23:28:42 -04:00
ExpectedSig _ ctx s =>
hangDSingle "expected a pair type, but got"
2024-05-27 15:28:22 -04:00
!(prettyTerm ctx s)
2023-10-19 23:28:42 -04:00
ExpectedEnum _ ctx s =>
hangDSingle "expected an enumeration type, but got"
2024-05-27 15:28:22 -04:00
!(prettyTerm ctx s)
2023-10-19 23:28:42 -04:00
ExpectedEq _ ctx s =>
2023-11-04 12:45:55 -04:00
hangDSingle "expected an equality type, but got"
2024-05-27 15:28:22 -04:00
!(prettyTerm ctx s)
2023-10-19 23:28:42 -04:00
2023-11-02 13:14:22 -04:00
ExpectedNAT _ ctx s =>
2023-10-19 23:28:42 -04:00
hangDSingle
("expected the type" <++>
2024-05-27 15:28:22 -04:00
!(prettyTerm ctx $ NAT noLoc) <+> ", but got")
!(prettyTerm ctx s)
2023-10-19 23:28:42 -04:00
ExpectedSTRING _ ctx s =>
hangDSingle
("expected the type" <++>
2024-05-27 15:28:22 -04:00
!(prettyTerm ctx $ STRING noLoc) <+> ", but got")
!(prettyTerm ctx s)
2023-10-19 23:28:42 -04:00
ExpectedBOX _ ctx s =>
hangDSingle "expected a box type, but got"
2024-05-27 15:28:22 -04:00
!(prettyTerm ctx s)
2023-10-19 23:28:42 -04:00
2024-04-14 09:48:43 -04:00
ExpectedIOState _ ctx s =>
hangDSingle "expected IOState, but got"
2024-05-27 15:28:22 -04:00
!(prettyTerm ctx s)
2024-04-14 09:48:43 -04:00
2023-10-19 23:28:42 -04:00
BadUniverse _ k l => pure $
sep ["the universe level" <++> !(prettyUniverse k),
"is not strictly less than" <++> !(prettyUniverse l)]
TagNotIn _ tag set =>
hangDSingle (hsep ["the tag", !(prettyTag tag), "is not contained in"])
2024-05-27 15:28:22 -04:00
!(prettyTerm empty $ Enum set noLoc)
2023-10-19 23:28:42 -04:00
BadCaseEnum _ head body => sep <$> sequence
[hangDSingle "case expression has head of type"
2024-05-27 15:28:22 -04:00
!(prettyTerm empty $ Enum head noLoc),
2023-10-19 23:28:42 -04:00
hangDSingle "but cases for"
2024-05-27 15:28:22 -04:00
!(prettyTerm empty $ Enum body noLoc)]
2023-10-19 23:28:42 -04:00
BadQtys _ what ctx arms =>
hangDSingle (text "inconsistent variable usage in \{what}") $
sep !(printCaseQtys ctx ctx.tnames arms)
ClashT _ ctx mode ty s t =>
2024-05-27 15:28:22 -04:00
let names = ctx.names0 in
2023-10-19 23:28:42 -04:00
inEContext ctx . sep =<< sequence
2024-05-27 15:28:22 -04:00
[hangDSingle "the term" !(prettyTerm names s),
hangDSingle (text "is not \{prettyMode mode}") !(prettyTerm names t),
hangDSingle "at type" !(prettyTerm names ty)]
2023-10-19 23:28:42 -04:00
ClashTy _ ctx mode a b =>
2024-05-27 15:28:22 -04:00
let names = ctx.names0 in
2023-10-19 23:28:42 -04:00
inEContext ctx . sep =<< sequence
2024-05-27 15:28:22 -04:00
[hangDSingle "the type" !(prettyTerm names a),
hangDSingle (text "is not \{prettyMode mode}") !(prettyTerm names b)]
2023-10-19 23:28:42 -04:00
ClashE _ ctx mode e f =>
2024-05-27 15:28:22 -04:00
let names = ctx.names0 in
2023-10-19 23:28:42 -04:00
inEContext ctx . sep =<< sequence
2024-05-27 15:28:22 -04:00
[hangDSingle "the term" !(prettyElim names e),
hangDSingle (text "is not \{prettyMode mode}") !(prettyElim names f)]
2023-10-19 23:28:42 -04:00
ClashU _ mode k l => pure $
sep ["the universe level" <++> !(prettyUniverse k),
text "is not \{prettyModeU mode}" <++> !(prettyUniverse l)]
2024-05-27 15:28:22 -04:00
ClashQ _ ctx pi rh => pure $
sep ["the quantity" <++> !(prettyQty ctx pi),
"is not equal to" <++> !(prettyQty ctx rh)]
2023-10-19 23:28:42 -04:00
NotInScope _ x => pure $
hsep [!(prettyFree x), "is not in scope"]
NotType _ ctx s =>
inTContext ctx . sep =<< sequence
2024-05-27 15:28:22 -04:00
[hangDSingle "the term" !(prettyTerm ctx.names s),
2023-10-19 23:28:42 -04:00
pure "is not a type"]
WrongType _ ctx ty s =>
2024-05-27 15:28:22 -04:00
let names = ctx.names0 in
2023-10-19 23:28:42 -04:00
inEContext ctx . sep =<< sequence
2024-05-27 15:28:22 -04:00
[hangDSingle "the term" !(prettyTerm names s),
hangDSingle "cannot have type" !(prettyTerm names ty)]
2023-10-19 23:28:42 -04:00
2024-04-14 09:48:43 -04:00
WrongBuiltinType b err => pure $
vappend
(sep [sep ["when checking", text $ builtinDesc b],
sep ["has type", !(builtinTypeDoc b)]])
!(prettyErrorNoLoc err)
ExpectedSingleEnum _ ctx s =>
hangDSingle "expected an enumeration type with one case, but got"
2024-05-27 15:28:22 -04:00
!(prettyTerm ctx s)
2024-04-14 09:48:43 -04:00
2023-10-19 23:28:42 -04:00
MissingEnumArm _ tag tags => pure $
sep [hsep ["the tag", !(prettyTag tag), "is not contained in"],
2024-05-27 15:28:22 -04:00
!(prettyTerm empty $ Enum (fromList tags) noLoc)]
2023-10-19 23:28:42 -04:00
WhileChecking ctx sg s a err =>
2024-05-27 15:28:22 -04:00
let names = ctx.names in
2023-10-19 23:28:42 -04:00
[|vappendBlank
(inTContext ctx . sep =<< sequence
2024-05-27 15:28:22 -04:00
[hangDSingle "while checking" !(prettyTerm names s),
hangDSingle "has type" !(prettyTerm names a),
hangDSingle "with quantity" !(prettyQConst sg.qconst)])
2023-10-19 23:28:42 -04:00
(prettyErrorNoLoc err)|]
WhileCheckingTy ctx a k err =>
[|vappendBlank
(inTContext ctx . sep =<< sequence
2024-05-27 15:28:22 -04:00
[hangDSingle "while checking" !(prettyTerm ctx.names a),
2023-10-19 23:28:42 -04:00
pure $ text $ isTypeInUniverse k])
(prettyErrorNoLoc err)|]
WhileInferring ctx sg e err =>
[|vappendBlank
(inTContext ctx . sep =<< sequence
[hangDSingle "while inferring the type of"
2024-05-27 15:28:22 -04:00
!(prettyElim ctx.names e),
hangDSingle "with quantity" !(prettyQConst sg.qconst)])
2023-10-19 23:28:42 -04:00
(prettyErrorNoLoc err)|]
WhileComparingT ctx mode sg a s t err =>
2024-05-27 15:28:22 -04:00
let names = ctx.names0 in
2023-10-19 23:28:42 -04:00
[|vappendBlank
(inEContext ctx . sep =<< sequence
2024-05-27 15:28:22 -04:00
[hangDSingle "while checking that" !(prettyTerm names s),
hangDSingle (text "is \{prettyMode mode}") !(prettyTerm names t),
hangDSingle "at type" !(prettyTerm names a),
hangDSingle "with quantity" !(prettyQConst sg.qconst)])
2023-10-19 23:28:42 -04:00
(prettyErrorNoLoc err)|]
WhileComparingE ctx mode sg e f err =>
2024-05-27 15:28:22 -04:00
let names = ctx.names0 in
2023-10-19 23:28:42 -04:00
[|vappendBlank
(inEContext ctx . sep =<< sequence
2024-05-27 15:28:22 -04:00
[hangDSingle "while checking that" !(prettyElim names e),
hangDSingle (text "is \{prettyMode mode}") !(prettyElim names f),
hangDSingle "with quantity" !(prettyQConst sg.qconst)])
2023-10-19 23:28:42 -04:00
(prettyErrorNoLoc err)|]
where
vappendBlank : Doc opts -> Doc opts -> Doc opts
vappendBlank a b = flush a `vappend` b
export
prettyError : Error -> Eff Pretty (Doc opts)
2023-12-21 12:03:57 -05:00
prettyError err = hangDSingle
!(prettyLoc err.loc)
!(indentD =<< prettyErrorNoLoc err)