on master help sign in
Merge pull request #990 from david-christiansen/unifier-context

Add more context to unification errors internally

commitda93e25189c7ce2deeba8ceff5752962287ce369 authorEdwin Brady <edwin.brady@gmail.com> dateSat 22 Mar 2014, 15:29 (13 years ago) parent0fc0cdcf490d9f
10 files changed+116−108
src/Idris/Core/Elaborate.hs+5−1 src/Idris/Core/TT.hs+5−4 src/Idris/Core/Unify.hs+4−2 src/Idris/Delaborate.hs+11−3 src/Idris/ElabDecls.hs+3−11 src/Idris/ElabTerm.hs+75−79 test/basic009/expected+2−1 test/error004/FunErrTest.idr+3−1 test/error004/expected+6−4 test/reg034/expected+2−2
src/Idris/Core/Elaborate.hs+5−1
@@ -167,6 +167,10 @@ done_elaborating_app :: Name -> Elab' aux ()
167167done_elaborating_app f = updatePS (doneElaboratingAppPS f)
168168done_elaborating_arg :: Name -> Name -> Elab' aux ()
169169done_elaborating_arg f a = updatePS (doneElaboratingArgPS f a)
170+elaborating_app :: Elab' aux [(FC, Name, Name)]
171+elaborating_app = do ES (ps, _) _ _ <- get
172+ return $ map (\ (FailContext x y z) -> (x, y, z))
173+ (while_elaborating ps)
170174
171175-- Some handy gadgets for pulling out bits of state
172176
@@ -687,7 +691,7 @@ try' t1 t2 proofSearch
687691 r || proofSearch
688692 recoverableErr (CantSolveGoal _ _) = False
689693 recoverableErr (ProofSearchFail _) = False
690− recoverableErr (ElaboratingArg _ _ e) = recoverableErr e
694+ recoverableErr (ElaboratingArg _ _ _ e) = recoverableErr e
691695 recoverableErr (At _ e) = recoverableErr e
692696 recoverableErr _ = True
693697
src/Idris/Core/TT.hs+5−4
@@ -140,7 +140,7 @@ data Err' t
140140 | NoRewriting t
141141 | At FC (Err' t)
142142 | Elaborating String Name (Err' t)
143− | ElaboratingArg Name Name (Err' t)
143+ | ElaboratingArg Name Name [(Name, Name)] (Err' t)
144144 | ProviderError String
145145 | LoadingFailed String (Err' t)
146146 | ReflectionError [[ErrorReportPart]] (Err' t)
@@ -171,7 +171,7 @@ instance Sized Err where
171171 size ProgramLineComment = 1
172172 size (At fc err) = size fc + size err
173173 size (Elaborating _ n err) = size err
174− size (ElaboratingArg _ _ err) = size err
174+ size (ElaboratingArg _ _ _ err) = size err
175175 size (ProviderError msg) = length msg
176176 size (LoadingFailed fn e) = 1 + length fn + size e
177177 size _ = 1
@@ -196,8 +196,9 @@ instance Show Err where
196196 show (LoadingFailed fn e) = "Loading " ++ fn ++ " failed: (TT) " ++ show e
197197 show ProgramLineComment = "Program line next to comment"
198198 show (At f e) = show f ++ ":" ++ show e
199− show (ElaboratingArg f x e) = "Elaborating " ++ show f ++ " arg " ++
200− show x ++ ": " ++ show e
199+ show (ElaboratingArg f x prev e) = "Elaborating " ++ show f ++ " arg " ++
200+ show x ++ ": " ++ show e
201+ show (Elaborating what n e) = "Elaborating " ++ what ++ show n ++ ":" ++ show e
201202 show _ = "Error"
202203
203204instance Pretty Err OutputAnnotation where
src/Idris/Core/Unify.hs+4−2
@@ -40,8 +40,10 @@ data UResult a = UOK a
4040-- | Smart constructor for unification errors that takes into account the FailContext
4141cantUnify :: [FailContext] -> Bool -> t -> t -> (Err' t) -> [(Name, t)] -> Int -> Err' t
4242cantUnify [] r t1 t2 e ctxt i = CantUnify r t1 t2 e ctxt i
43−cantUnify (FailContext fc f x : _) r t1 t2 e ctxt i =
44− At fc (ElaboratingArg f x (CantUnify r t1 t2 e ctxt i))
43+cantUnify (FailContext fc f x : prev) r t1 t2 e ctxt i =
44+ At fc (ElaboratingArg f x
45+ (map (\(FailContext _ f' x') -> (f', x')) prev)
46+ (CantUnify r t1 t2 e ctxt i))
4547
4648-- Solve metavariables by matching terms against each other
4749-- Not really unification, of course!
src/Idris/Delaborate.hs+11−3
@@ -217,15 +217,23 @@ pprintErr' i (At f e) = annotate (AnnFC f) (text (show f)) <> colon <> pprintErr
217217pprintErr' i (Elaborating s n e) = text "When elaborating" <+> text s <>
218218 annName' n (showqual i n) <> colon <$>
219219 pprintErr' i e
220−pprintErr' i (ElaboratingArg f x e)
220+pprintErr' i (ElaboratingArg f x _ e)
221221 | isUN x =
222222 text "When elaborating argument" <+>
223223 annotate (AnnBoundName x False) (text (showbasic x)) <+> --TODO check plicity
224− text "to function" <+> annName f <> colon <>
224+ text "to" <+> whatIsName <> annName f <> colon <>
225225 indented (pprintErr' i e)
226226 | otherwise =
227− text "When elaborating an application of function" <+>
227+ text "When elaborating an application of" <+> whatIsName <>
228228 annName f <> colon <> indented (pprintErr' i e)
229+ where whatIsName = let ctxt = tt_ctxt i
230+ in if isTConName f ctxt
231+ then text "type constructor" <> space
232+ else if isConName f ctxt
233+ then text "constructor" <> space
234+ else if isFnName f ctxt
235+ then text "function" <> space
236+ else empty
229237pprintErr' i (ProviderError msg) = text ("Type provider error: " ++ msg)
230238pprintErr' i (LoadingFailed fn e) = text "Loading" <+> text fn <+> text "failed:" <+> pprintErr' i e
231239pprintErr' i (ReflectionError parts orig) =
src/Idris/ElabDecls.hs+3−11
@@ -91,8 +91,7 @@ elabType' norm info syn doc argDocs fc opts n ty' = {- let ty' = piBind (params
9191 -- if the type is not complete, note that we'll need to infer
9292 -- things later (for solving metavariables)
9393 when (not (null ds)) $ addTyInferred n
94−-- let ds' = map (\(n, (i, top, t)) -> (n, (i, top, t, True))) ds
95−-- addDeferred ds'
94+
9695 mapM_ (elabCaseBlock info opts) is
9796 ctxt <- getContext
9897 logLvl 5 $ "Rechecking"
@@ -1270,10 +1269,6 @@ checkPossible info fc tcgen fname lhs_in
12701269 case recheck ctxt [] (forget lhs_tm) lhs_tm of
12711270 OK _ -> return True
12721271 err -> return False
1273−
1274−-- b <- inferredDiff fc (delab' i lhs_tm True) lhs
1275−-- return (not b) -- then return (Just lhs_tm) else return Nothing
1276−-- trace (show (delab' i lhs_tm True) ++ "\n" ++ show lhs) $ return (not b)
12771272 Error err -> if tcgen then return False
12781273 else return (impossibleError err)
12791274 where impossibleError (CantUnify _ topx topy e _ _)
@@ -1281,7 +1276,7 @@ checkPossible info fc tcgen fname lhs_in
12811276 impossibleError (CantConvert _ _ _) = False
12821277 impossibleError (At _ e) = impossibleError e
12831278 impossibleError (Elaborating _ _ e) = impossibleError e
1284− impossibleError (ElaboratingArg _ _ e) = impossibleError e
1279+ impossibleError (ElaboratingArg _ _ _ e) = impossibleError e
12851280 impossibleError _ = True
12861281
12871282 sameFam topx topy
@@ -1980,10 +1975,7 @@ elabInstance info syn what fc cs n ps t expn ds = do
19801975 iLOG (show idecls)
19811976 mapM_ (elabDecl EAll info) idecls
19821977 addIBC (IBCInstance intInst n iname)
1983−-- -- for each constraint, build a top level function to chase it
1984−-- logLvl 5 $ "Building functions"
1985−-- fns <- mapM (cfun (instanceName ci) constraint syn idecls) cs
1986−-- mapM_ (elabDecl EAll info) (concat fns)
1978+
19871979 where
19881980 intInst = case ps of
19891981 [PConstant (AType (ATInt ITNative))] -> True
src/Idris/ElabTerm.hs+75−79
@@ -20,7 +20,7 @@ import Control.Monad
2020import Control.Monad.State.Strict
2121import Data.List
2222import qualified Data.Map as M
23−import Data.Maybe (mapMaybe)
23+import Data.Maybe (mapMaybe, fromMaybe)
2424import qualified Data.Set as S
2525import qualified Data.Text as T
2626
@@ -191,7 +191,7 @@ elab ist info pattern opts fn tm
191191 | (P _ (UN ht) _, _) <- unApply (normalise (tt_ctxt ist) env t),
192192 ht == txt "Lazy'" = True
193193 forceErr env (Elaborating _ _ t) = forceErr env t
194− forceErr env (ElaboratingArg _ _ t) = forceErr env t
194+ forceErr env (ElaboratingArg _ _ _ t) = forceErr env t
195195 forceErr env (At _ t) = forceErr env t
196196 forceErr env t = False
197197
@@ -727,10 +727,7 @@ elab ist info pattern opts fn tm
727727 -> Bool -- ^ under a 'force'
728728 -> [(Bool, PTerm)] -- ^ (Laziness, argument)
729729 -> ElabD ()
730− elabArgs ist ina failed fc retry f [] force _
731−-- | retry = let (ns, ts) = unzip (reverse failed) in
732−-- elabArgs ina [] False ns ts
733− | otherwise = return ()
730+ elabArgs ist ina failed fc retry f [] force _ = return ()
734731 elabArgs ist ina failed fc r f (n:ns) force ((_, Placeholder) : args)
735732 = elabArgs ist ina failed fc r f ns force args
736733 elabArgs ist ina failed fc r f ((argName, holeName):ns) force ((lazy, t) : args)
@@ -741,54 +738,30 @@ elab ist info pattern opts fn tm
741738 | otherwise = elabArg argName holeName t
742739 where elabArg argName holeName t =
743740 do now_elaborating fc f argName
744− hs <- get_holes
745− tm <- get_term
746− -- No coercing under an explicit Force (or it can Force/Delay
747− -- recursively!)
748− let elab = if force then elab' else elabE
749− failed' <- -- trace (show (n, t, hs, tm)) $
750− -- traceWhen (not (null cs)) (show ty ++ "\n" ++ showImp True t) $
751− case holeName `elem` hs of
752− True -> do focus holeName; elab ina t; return failed
753− False -> return failed
754− done_elaborating_arg f argName
755− elabArgs ist ina failed fc r f ns force args
756−
757−-- | Perform error reflection for function applicaitons with specific error handlers
758−reflectFunctionErrors :: IState -> Name -> Name -> ElabD a -> ElabD a
759−reflectFunctionErrors ist f arg action =
760− do elabState <- get
761− (result, newState) <- case runStateT action elabState of
762− OK (res, newState) -> return (res, newState)
763− Error e@(ReflectionError _ _) -> (lift . tfail) e
764− Error e@(ReflectionFailed _ _) -> (lift . tfail) e
765− Error e -> handle e >>= lift . tfail
766− put newState
767− return result
768− where handle :: Err -> ElabD Err
769− handle e = do let funhandlers = (maybe M.empty id . lookupCtxtExact f . idris_function_errorhandlers) ist
770− handlers = (maybe [] S.toList . M.lookup arg) funhandlers
771− reports = map (\n -> RApp (Var n) (reflectErr e)) handlers
772−
773−
774− -- Typecheck error handlers - if this fails, then something else was wrong earlier!
775− handlers <- case mapM (check (tt_ctxt ist) []) reports of
776− Error e -> lift . tfail $
777− ReflectionFailed "Type error while constructing reflected error" e
778− OK hs -> return hs
779−
780− -- Normalize error handler terms to produce the new messages
781− let ctxt = tt_ctxt ist
782− results = map (normalise ctxt []) (map fst handlers)
783−
784− -- For each handler term output, either discard it if it is Nothing or reify it the Haskell equivalent
785− let errorpartsTT = mapMaybe unList (mapMaybe fromTTMaybe results)
786− errorparts <- case mapM (mapM reifyReportPart) errorpartsTT of
787− Left err -> lift (tfail err)
788− Right ok -> return ok
789− return $ case errorparts of
790− [] -> e
791− parts -> ReflectionError errorparts e
741+ wrapErr f argName $ do
742+ hs <- get_holes
743+ tm <- get_term
744+ -- No coercing under an explicit Force (or it can Force/Delay
745+ -- recursively!)
746+ let elab = if force then elab' else elabE
747+ failed' <- -- trace (show (n, t, hs, tm)) $
748+ -- traceWhen (not (null cs)) (show ty ++ "\n" ++ showImp True t) $
749+ case holeName `elem` hs of
750+ True -> do focus holeName; elab ina t; return failed
751+ False -> return failed
752+ done_elaborating_arg f argName
753+ elabArgs ist ina failed fc r f ns force args
754+ wrapErr f argName action =
755+ do elabState <- get
756+ while <- elaborating_app
757+ let while' = map (\(x, y, z)-> (y, z)) while
758+ (result, newState) <- case runStateT action elabState of
759+ OK (res, newState) -> return (res, newState)
760+ Error e -> do done_elaborating_arg f argName
761+ lift (tfail (elaboratingArgErr while' e))
762+ put newState
763+ return result
764+
792765
793766-- For every alternative, look at the function at the head. Automatically resolve
794767-- any nested alternatives where that function is also at the head
@@ -1631,6 +1604,14 @@ reflectErr (LoadingFailed str err) =
16311604 raw_apply (Var $ reflErrName "LoadingFailed") [RConstant (Str str)]
16321605reflectErr x = raw_apply (Var (sNS (sUN "Msg") ["Errors", "Reflection", "Language"])) [RConstant . Str $ "Default reflection: " ++ show x]
16331606
1607+elaboratingArgErr :: [(Name, Name)] -> Err -> Err
1608+elaboratingArgErr [] err = err
1609+elaboratingArgErr ((f,x):during) err = fromMaybe err (rewrite err)
1610+ where rewrite (ElaboratingArg _ _ _ _) = Nothing
1611+ rewrite (ProofSearchFail e) = fmap ProofSearchFail (rewrite e)
1612+ rewrite (At fc e) = fmap (At fc) (rewrite e)
1613+ rewrite err = Just (ElaboratingArg f x during err)
1614+
16341615
16351616withErrorReflection :: Idris a -> Idris a
16361617withErrorReflection x = idrisCatch x (\ e -> handle e >>= ierror)
@@ -1646,35 +1627,50 @@ withErrorReflection x = idrisCatch x (\ e -> handle e >>= ierror)
16461627 handle e@(Elaborating what n err) = do logLvl 3 "Reflecting body of Elaborating"
16471628 err' <- handle err
16481629 return (Elaborating what n err')
1649− handle e@(ElaboratingArg f a err) = do logLvl 3 "Reflecting body of ElaboratingArg"
1650− err' <- handle err
1651− return (ElaboratingArg f a err')
1630+ handle e@(ElaboratingArg f a prev err) = do logLvl 3 "Reflecting body of ElaboratingArg"
1631+ hs <- getFnHandlers f a
1632+ err' <- if null hs
1633+ then handle err
1634+ else applyHandlers err hs
1635+ return (ElaboratingArg f a prev err')
16521636 -- TODO: argument-specific error handlers go here for ElaboratingArg
16531637 handle e = do ist <- getIState
1654− let err = fmap (errReverse ist) e
16551638 logLvl 2 "Starting error reflection"
16561639 let handlers = idris_errorhandlers ist
1657− logLvl 3 $ "Using reflection handlers " ++ concat (intersperse ", " (map show handlers))
1658− let reports = map (\n -> RApp (Var n) (reflectErr err)) handlers
1659−
1660− -- Typecheck error handlers - if this fails, then something else was wrong earlier!
1661− handlers <- case mapM (check (tt_ctxt ist) []) reports of
1662− Error e -> ierror $ ReflectionFailed "Type error while constructing reflected error" e
1663− OK hs -> return hs
1664−
1665− -- Normalize error handler terms to produce the new messages
1666− ctxt <- getContext
1667− let results = map (normalise ctxt []) (map fst handlers)
1668− logLvl 3 $ "New error message info: " ++ concat (intersperse " and " (map show results))
1669−
1670− -- For each handler term output, either discard it if it is Nothing or reify it the Haskell equivalent
1671− let errorpartsTT = mapMaybe unList (mapMaybe fromTTMaybe results)
1672− errorparts <- case mapM (mapM reifyReportPart) errorpartsTT of
1673− Left err -> ierror err
1674− Right ok -> return ok
1675− return $ case errorparts of
1676− [] -> e
1677− parts -> ReflectionError errorparts e
1640+ applyHandlers e handlers
1641+ getFnHandlers :: Name -> Name -> Idris [Name]
1642+ getFnHandlers f arg = do ist <- getIState
1643+ let funHandlers = maybe M.empty id .
1644+ lookupCtxtExact f .
1645+ idris_function_errorhandlers $ ist
1646+ return . maybe [] S.toList . M.lookup arg $ funHandlers
1647+
1648+
1649+ applyHandlers e handlers =
1650+ do ist <- getIState
1651+ let err = fmap (errReverse ist) e
1652+ logLvl 3 $ "Using reflection handlers " ++
1653+ concat (intersperse ", " (map show handlers))
1654+ let reports = map (\n -> RApp (Var n) (reflectErr err)) handlers
1655+
1656+ -- Typecheck error handlers - if this fails, then something else was wrong earlier!
1657+ handlers <- case mapM (check (tt_ctxt ist) []) reports of
1658+ Error e -> ierror $ ReflectionFailed "Type error while constructing reflected error" e
1659+ OK hs -> return hs
1660+
1661+ -- Normalize error handler terms to produce the new messages
1662+ ctxt <- getContext
1663+ let results = map (normalise ctxt []) (map fst handlers)
1664+ logLvl 3 $ "New error message info: " ++ concat (intersperse " and " (map show results))
1665+
1666+ -- For each handler term output, either discard it if it is Nothing or reify it the Haskell equivalent
1667+ let errorpartsTT = mapMaybe unList (mapMaybe fromTTMaybe results)
1668+ errorparts <- case mapM (mapM reifyReportPart) errorpartsTT of
1669+ Left err -> ierror err
1670+ Right ok -> return ok
1671+ return $ case errorparts of
1672+ [] -> e
1673+ parts -> ReflectionError errorparts e
16781674
16791675fromTTMaybe :: Term -> Maybe Term -- WARNING: Assumes the term has type Maybe a
16801676fromTTMaybe (App (App (P (DCon _ _) (NS (UN just) _) _) ty) tm)
test/basic009/expected+2−1
@@ -1,4 +1,5 @@
11MAIN-PASS
22Faulty.idr:6:7:When elaborating type of Faulty.fault:
3−Can't disambiguate name: A.num, B.C.num
3+When elaborating an application of type constructor =:
4+ Can't disambiguate name: A.num, B.C.num
45Multiple.idr:3:1:import alias not unique: "X"
test/error004/FunErrTest.idr+3−1
@@ -19,7 +19,6 @@ extractList : TT -> Maybe TT
1919extractList (App (App reflCon (App isCons lst)) _) = Just lst
2020extractList _ = Nothing
2121
22−%error_handler
2322total
2423has2elts : Err -> Maybe (List ErrorReportPart)
2524has2elts (CantSolveGoal tm _) = do lst <- extractList tm
@@ -29,6 +28,9 @@ has2elts (CantSolveGoal tm _) = do lst <- extractList tm
2928 ]
3029has2elts e = Just [TextPart (show e)]
3130
31+%error_handlers cadr cons1 has2elts
32+%error_handlers cadr cons2 has2elts
33+
3234badCadr1 : Int
3335badCadr1 = cadr []
3436
test/error004/expected+6−4
@@ -1,4 +1,6 @@
1−FunErrTest.idr:33:10:When elaborating right hand side of badCadr1:
2−Could not prove that [] has at least two elements.
3−FunErrTest.idr:36:10:When elaborating right hand side of badCadr2:
4−Could not prove that tail [(fromInteger 1)] refl has at least two elements.
1+FunErrTest.idr:35:10:When elaborating right hand side of badCadr1:
2+When elaborating argument cons1 to function FunErrTest.cadr:
3+ Could not prove that [] has at least two elements.
4+FunErrTest.idr:38:10:When elaborating right hand side of badCadr2:
5+When elaborating argument cons2 to function FunErrTest.cadr:
6+ Could not prove that tail [(fromInteger 1)] refl has at least two elements.
test/reg034/expected+2−2
@@ -1,5 +1,5 @@
11reg034.idr:6:5:When elaborating left hand side of bar:
2−When elaborating an application of function main.bar:
2+When elaborating an application of main.bar:
33 Can't unify
44 x = x
55 with
@@ -11,7 +11,7 @@ When elaborating an application of function main.bar:
1111 with
1212 length xs
1313reg034.idr:9:5:When elaborating left hand side of foo:
14−When elaborating an application of function main.foo:
14+When elaborating an application of main.foo:
1515 Can't unify
1616 x = x
1717 with