@@ -1,9 +1,10 @@
1{-# LANGUAGE PatternGuards #-}
1{-# LANGUAGE PatternGuards #-}
3−module Idris.ProofSearch(trivial, trivialHoles, proofSearch) where
3+module Idris.ProofSearch(trivial, trivialHoles, proofSearch, resolveTC) where
5import Idris.Core.Elaborate hiding (Tactic(..))
5import Idris.Core.Elaborate hiding (Tactic(..))
6import Idris.Core.TT
6import Idris.Core.TT
7+import Idris.Core.Unify
7import Idris.Core.Evaluate
8import Idris.Core.Evaluate
8import Idris.Core.CaseTree
9import Idris.Core.CaseTree
9import Idris.Core.Typecheck
10import Idris.Core.Typecheck
@@ -24,14 +25,16 @@ import Debug.Trace
24trivial :: (PTerm -> ElabD ()) -> IState -> ElabD ()
25trivial :: (PTerm -> ElabD ()) -> IState -> ElabD ()
25trivial = trivialHoles [] []
26trivial = trivialHoles [] []
28+trivialHoles :: [Name] -> -- user visible names, when working
29+ -- in interactive mode
27−trivialHoles :: [Name] -> [(Name, Int)] -> (PTerm -> ElabD ()) -> IState -> ElabD ()
30+ [(Name, Int)] -> (PTerm -> ElabD ()) -> IState -> ElabD ()
28trivialHoles psnames ok elab ist
31trivialHoles psnames ok elab ist
29− = try' (do elab (PApp (fileFC "prf") (PRef (fileFC "prf") [] eqCon) [pimp (sUN "A") Placeholder False, pimp (sUN "x") Placeholder False])
32+ = try' (do elab (PApp (fileFC "prf") (PRef (fileFC "prf") [] eqCon) [pimp (sUN "A") Placeholder False, pimp (sUN "x") Placeholder False])
30− return ())
33+ return ())
31− (do env <- get_env
34+ (do env <- get_env
32− g <- goal
35+ g <- goal
33− tryAll env
36+ tryAll env
34− return ()) True
37+ return ()) True
36 tryAll [] = fail "No trivial solution"
39 tryAll [] = fail "No trivial solution"
37 tryAll ((x, b):xs)
40 tryAll ((x, b):xs)
@@ -41,7 +44,7 @@ trivialHoles psnames ok elab ist
42 -- anywhere but the top is okay for a hole, if holesOK set
45 -- anywhere but the top is okay for a hole, if holesOK set
43 if -- all (\n -> not (n `elem` badhs)) (freeNames (binderTy b))
46 if -- all (\n -> not (n `elem` badhs)) (freeNames (binderTy b))
44− holesOK hs (binderTy b) && (null psnames || x `elem` psnames)
47+ (holesOK hs (binderTy b) && (null psnames || x `elem` psnames))
45 then try' (elab (PRef (fileFC "prf") [] x))
48 then try' (elab (PRef (fileFC "prf") [] x))
46 (tryAll xs) True
49 (tryAll xs) True
47 else tryAll xs
50 else tryAll xs
@@ -60,6 +63,50 @@ trivialHoles psnames ok elab ist
60 | (n, p) `elem` ok = holeArgsOK hs n (p + 1) as
63 | (n, p) `elem` ok = holeArgsOK hs n (p + 1) as
61 | otherwise = holesOK hs a && holeArgsOK hs n (p + 1) as
64 | otherwise = holesOK hs a && holeArgsOK hs n (p + 1) as
66+trivialTCs :: [(Name, Int)] -> (PTerm -> ElabD ()) -> IState -> ElabD ()
67+trivialTCs ok elab ist
68+ = try' (do elab (PApp (fileFC "prf") (PRef (fileFC "prf") [] eqCon) [pimp (sUN "A") Placeholder False, pimp (sUN "x") Placeholder False])
75+ tryAll [] = fail "No trivial solution"
77+ = do -- if type of x has any holes in it, move on
79+ let badhs = hs -- filter (flip notElem holesOK) hs
82+ -- anywhere but the top is okay for a hole, if holesOK set
83+ if -- all (\n -> not (n `elem` badhs)) (freeNames (binderTy b))
84+ (holesOK hs (binderTy b) && tcArg env (binderTy b))
85+ then try' (elab (PRef (fileFC "prf") [] x))
90+ | (P _ n _, args) <- unApply (getRetTy (normalise (tt_ctxt ist) env ty))
91+ = case lookupCtxtExact n (idris_classes ist) of
96+ holesOK hs ap@(App _ _ _)
97+ | (P _ n _, args) <- unApply ap
98+ = holeArgsOK hs n 0 args
99+ holesOK hs (App _ f a) = holesOK hs f && holesOK hs a
100+ holesOK hs (P _ n _) = not (n `elem` hs)
101+ holesOK hs (Bind n b sc) = holesOK hs (binderTy b) &&
105+ holeArgsOK hs n p [] = True
106+ holeArgsOK hs n p (a : as)
107+ | (n, p) `elem` ok = holeArgsOK hs n (p + 1) as
108+ | otherwise = holesOK hs a && holeArgsOK hs n (p + 1) as
63cantSolveGoal :: ElabD a
110cantSolveGoal :: ElabD a
64cantSolveGoal = do g <- goal
111cantSolveGoal = do g <- goal
65 env <- get_env
112 env <- get_env
@@ -179,7 +226,9 @@ proofSearch rec fromProver ambigok deferonfail maxDepth elab fn nroot psnames hi
179 ty <- goal
226 ty <- goal
180 when (S.member ty tys) $ fail "Been here before"
227 when (S.member ty tys) $ fail "Been here before"
181 let tys' = S.insert ty tys
228 let tys' = S.insert ty tys
182− try' (trivialHoles psnames [] elab ist)
229+ try' (try' (trivialHoles psnames [] elab ist)
230+ (resolveTC False False 20 ty nroot elab ist)
183 (try' (try' (resolveByCon (d - 1) locs tys')
232 (try' (try' (resolveByCon (d - 1) locs tys')
184 (resolveByLocals (d - 1) locs tys')
233 (resolveByLocals (d - 1) locs tys')
@@ -188,9 +237,14 @@ proofSearch rec fromProver ambigok deferonfail maxDepth elab fn nroot psnames hi
188 then fail "cantSolveGoal"
237 then fail "cantSolveGoal"
189 else do attack; defer [] nroot; solve) True) True
238 else do attack; defer [] nroot; solve) True) True
191− getFn d Nothing = []
240+ -- get recursive function name. Only user given names make sense.
192− getFn d (Just f) | d < maxDepth-1 = [f]
241+ getFn d (Just f) | d < maxDepth-1 && usersname f = [f]
193 | otherwise = []
242 | otherwise = []
245+ usersname (UN _) = True
246+ usersname (NS n _) = usersname n
195 resolveByCon d locs tys
249 resolveByCon d locs tys
196 = do t <- goal
250 = do t <- goal
@@ -273,3 +327,182 @@ checkConstructor ist (n : ns) =
273 any conHead args
327 any conHead args
274 conHead t | (P _ n _, _) <- unApply t = isConName n (tt_ctxt ist)
328 conHead t | (P _ n _, _) <- unApply t = isConName n (tt_ctxt ist)
275 | otherwise = False
329 | otherwise = False
331+-- | Resolve type classes. This will only pick up 'normal' instances, never
332+-- named instances (which is enforced by 'findInstances').
333+resolveTC :: Bool -- ^ using default Int
334+ -> Bool -- ^ allow metavariables in the goal
336+ -> Term -- ^ top level goal, for error messages
337+ -> Name -- ^ top level function name, to prevent loops
338+ -> (PTerm -> ElabD ()) -- ^ top level elaborator
339+ -> IState -> ElabD ()
340+resolveTC def mvok depth top fn elab ist
341+ = do hs <- get_holes
342+ resTC' [] def hs depth top fn elab ist
344+resTC' tcs def topholes 0 topg fn elab ist = fail $ "Can't resolve type class"
345+resTC' tcs def topholes 1 topg fn elab ist = try' (trivial elab ist) (resolveTC def False 0 topg fn elab ist) True
346+resTC' tcs defaultOn topholes depth topg fn elab ist
349+ -- Resolution can proceed only if there is something concrete in the
350+ -- determining argument positions. Keep track of the holes in the
351+ -- non-determining position, because it's okay for 'trivial' to solve
352+ -- those holes and no others.
353+ let (argsok, okholePos) = case tcArgsOK g topholes of
354+ Nothing -> (False, [])
355+ Just hs -> (True, hs)
356+ if not argsok -- && not mvok)
357+ then lift $ tfail $ CantResolve True topg
364+ let (tc, ttypes) = unApply (getRetTy t)
365+ let okholes = case tc of
366+ P _ n _ -> zip (repeat n) okholePos
369+ traceWhen ulog ("Resolving class " ++ show g ++ "\nin" ++ show env ++ "\n" ++ show okholes) $
370+ try' (trivialTCs okholes elab ist)
371+ (do addDefault t tc ttypes
372+ let stk = map fst (filter snd $ elab_stack ist)
373+ let insts = findInstances ist t
374+ blunderbuss t depth stk (stk ++ insts)) True
376+ -- returns Just hs if okay, where hs are holes which are okay in the
377+ -- goal, or Nothing if not okay to proceed
378+ tcArgsOK ty hs | (P _ nc _, as) <- unApply (getRetTy ty), nc == numclass && defaultOn
380+ tcArgsOK ty hs -- if any determining arguments are metavariables, postpone
381+ = let (f, as) = unApply (getRetTy ty) in
383+ P _ cn _ -> case lookupCtxtExact cn (idris_classes ist) of
384+ Just ci -> tcDetArgsOK 0 (class_determiners ci) hs as
385+ Nothing -> if any (isMeta hs) as
388+ _ -> if any (isMeta hs) as
392+ -- return the list of argument positions which can safely be a hole
393+ -- or Nothing if one of the determining arguments is a hole
394+ tcDetArgsOK i ds hs (x : xs)
395+ | i `elem` ds = if isMeta hs x
397+ else tcDetArgsOK (i + 1) ds hs xs
398+ | otherwise = do rs <- tcDetArgsOK (i + 1) ds hs xs
400+ P _ n _ -> Just (i : rs)
402+ tcDetArgsOK _ _ _ [] = Just []
404+ isMeta :: [Name] -> Term -> Bool
405+ isMeta ns (P _ n _) = n `elem` ns
408+ notHole hs (P _ n _, c)
409+ | (P _ cn _, _) <- unApply (getRetTy c),
410+ n `elem` hs && isConName cn (tt_ctxt ist) = False
411+ | Constant _ <- c = not (n `elem` hs)
414+ -- HACK! Rather than giving a special name, better to have some kind
415+ -- of flag in ClassInfo structure
417+ | ('@':'@':_) <- str nm = True -- old way
418+ chaser (SN (ParentN _ _)) = True
419+ chaser (NS n _) = chaser n
422+ numclass = sNS (sUN "Num") ["Classes","Prelude"]
424+ addDefault t num@(P _ nc _) [P Bound a _] | nc == numclass && defaultOn
426+ fill (RConstant (AType (ATInt ITBig))) -- default Integer
429+ | all boundVar as = return () -- True -- fail $ "Can't resolve " ++ show t
430+ addDefault t f a = return () -- trace (show t) $ return ()
432+ boundVar (P Bound _ _) = True
435+ blunderbuss t d stk [] = do -- c <- get_env
437+ lift $ tfail $ CantResolve False topg
438+ blunderbuss t d stk (n:ns)
439+ | n /= fn -- && (n `elem` stk)
440+ = tryCatch (resolve n d)
442+ CantResolve True _ -> lift $ tfail e
443+ _ -> blunderbuss t d stk ns)
444+ | otherwise = blunderbuss t d stk ns
446+ introImps = do g <- goal
448+ (Bind _ (Pi _ _ _) sc) -> do attack; intro Nothing
453+ solven 0 = return ()
454+ solven n = do solve; solven (n - 1)
457+ | depth == 0 = fail $ "Can't resolve type class"
459+ = do lams <- introImps
461+ let (tc, ttypes) = trace (show t) $ unApply (getRetTy t)
462+-- if (all boundVar ttypes) then resolveTC (depth - 1) fn insts ist
464+ -- if there's a hole in the goal, don't even try
465+ let imps = case lookupCtxtName n (idris_implicits ist) of
467+ [args] -> map isImp (snd args) -- won't be overloaded!
468+ xs -> error "The impossible happened - overloading is not expected here!"
471+ args <- map snd <$> try' (apply (Var n) imps)
472+ (match_apply (Var n) imps) True
473+ solven lams -- close any implicit lambdas we introduced
475+ when (length ps < length ps' || unrecoverable ps') $
476+ fail "Can't apply type class"
477+-- traceWhen (all boundVar ttypes) ("Progress: " ++ show t ++ " with " ++ show n) $
478+ mapM_ (\ (_,n) -> do focus n
480+ let (tc', ttype) = unApply (getRetTy t')
481+ let got = fst (unApply (getRetTy t))
482+ let depth' = if tc' `elem` tcs
483+ then depth - 1 else depth
484+ resTC' (got : tcs) defaultOn topholes depth' topg fn elab ist)
485+ (filter (\ (x, y) -> not x) (zip (map fst imps) args))
486+ -- if there's any arguments left, we've failed to resolve
490+ traceWhen ulog ("Got " ++ show n) $ return ()
491+ where isImp (PImp p _ _ _ _) = (True, p)
492+ isImp arg = (False, priority arg)
494+-- | Find the names of instances that have been designeated for
495+-- searching (i.e. non-named instances or instances from Elab scripts)
496+findInstances :: IState -> Term -> [Name]
498+ | (P _ n _, _) <- unApply (getRetTy t)
499+ = case lookupCtxt n (idris_classes ist) of
500+ [CI _ _ _ _ _ ins _] ->
501+ [n | (n, True) <- ins, accessible n]
504+ where accessible n = case lookupDefAccExact n False (tt_ctxt ist) of
505+ Just (_, Hidden) -> False