1
{-# LANGUAGE CPP, PatternGuards #-}
2
{-# LANGUAGE PatternGuards #-}
3
{-# LANGUAGE ScopedTypeVariables #-}
2
5
module Agda.TypeChecking.CompiledClause.Match where
4
7
import Control.Applicative
8
import Control.Monad.Reader (asks)
5
9
import qualified Data.Map as Map
6
import Data.Traversable
11
import Debug.Trace (trace)
9
13
import Agda.Syntax.Internal
10
14
import Agda.Syntax.Common
11
15
import Agda.TypeChecking.CompiledClause
12
import Agda.TypeChecking.Monad
16
import Agda.TypeChecking.Monad hiding (reportSDoc, reportSLn)
17
import Agda.TypeChecking.Pretty
18
import Agda.TypeChecking.Reduce
19
import Agda.TypeChecking.Reduce.Monad as RedM
13
20
import Agda.TypeChecking.Substitute
14
import Agda.TypeChecking.Reduce
15
import Agda.TypeChecking.Primitive
17
import Agda.Utils.List
22
import Agda.Utils.Maybe
24
#include "../../undefined.h"
19
25
import Agda.Utils.Impossible
20
#include "../../undefined.h"
22
matchCompiled :: CompiledClauses -> MaybeReducedArgs -> TCM (Reduced (Blocked Args) Term)
23
matchCompiled c args = match c args id []
25
type Stack = [(CompiledClauses, MaybeReducedArgs, Args -> Args)]
27
matchCompiled :: CompiledClauses -> MaybeReducedArgs -> ReduceM (Reduced (Blocked Args) Term)
28
matchCompiled c args = do
29
r <- matchCompiledE c $ map (fmap Apply) args
31
YesReduction simpl v -> return $ YesReduction simpl v
32
NoReduction bes -> return $ NoReduction $ fmap (map fromElim) bes
33
where fromElim (Apply v) = v
34
fromElim (Proj f ) = __IMPOSSIBLE__
36
-- | @matchCompiledE c es@ takes a function given by case tree @c@ and
37
-- and a spine @es@ and tries to apply the function to @es@.
38
matchCompiledE :: CompiledClauses -> MaybeReducedElims -> ReduceM (Reduced (Blocked Elims) Term)
39
matchCompiledE c args = match' [(c, args, id)]
41
-- | A stack entry is a triple consisting of
42
-- 1. the part of the case tree to continue matching,
43
-- 2. the current argument vector, and
44
-- 3. a patch function taking the current argument vector back
45
-- to the original argument vector.
46
type Frame = (CompiledClauses, MaybeReducedElims, Elims -> Elims)
50
-- | @match'@ tries to solve the matching problems on the @Stack@.
51
-- In each iteration, the top problem is removed and handled.
53
-- If the top problem was a @Done@, we succeed.
55
-- If the top problem was a @Case n@ and the @n@th argument of the problem
56
-- is not a constructor or literal, we are stuck, thus, fail.
58
-- If we have a branch for the constructor/literal, we put it on the stack
60
-- If we do not have a branch, we fall through to the next problem, which
61
-- should be the corresponding catch-all branch.
63
-- An empty stack is an exception that can come only from an incomplete
64
-- function definition.
27
66
-- TODO: literal/constructor pattern conflict (for Nat)
29
match :: CompiledClauses -> MaybeReducedArgs -> (Args -> Args) -> Stack -> TCM (Reduced (Blocked Args) Term)
30
match Fail args patch stack = return $ NoReduction $ NotBlocked (patch $ map ignoreReduced args)
31
match (Done xs t) args _ _
32
| m < n = return $ YesReduction $ applySubst (parallelS $ reverse $ toTm args)
33
$ foldr lam t (drop m xs)
34
| otherwise = return $ YesReduction $
35
applySubst (parallelS $ reverse $ toTm args0) t `apply` map ignoreReduced args1
39
toTm = map (unArg . ignoreReduced)
40
(args0, args1) = splitAt n $ map (fmap $ fmap shared) args
41
lam x t = Lam (argHiding x) (Abs (unArg x) t)
42
match (Case n bs) args patch stack =
43
case genericSplitAt n args of
44
(_, []) -> return $ NoReduction $ NotBlocked $ patch $ map ignoreReduced args
45
(args0, MaybeRed red (Arg h r v0) : args1) -> do
47
Reduced b -> return $ fmap (const v0) b
49
unfoldCorecursion =<< instantiate v0
50
cv <- constructorForm $ ignoreBlocking w
51
let v = ignoreBlocking w
52
args' = args0 ++ [MaybeRed red $ Arg h r v] ++ args1
53
stack' = maybe [] (\c -> [(c, args', patch)]) (catchAllBranch bs)
55
patchLit args = patch (args0 ++ [Arg h r v] ++ args1)
56
where (args0, args1) = splitAt n args
57
patchCon c m args = patch (args0 ++ [Arg h r $ Con c vs] ++ args1)
58
where (args0, args1') = splitAt n args
59
(vs, args1) = splitAt m args1'
60
case ignoreSharing <$> w of
61
Blocked x _ -> return $ NoReduction $ Blocked x (patch $ map ignoreReduced args')
62
NotBlocked (MetaV x _) -> return $ NoReduction $ Blocked x (patch $ map ignoreReduced args')
63
NotBlocked (Lit l) -> case Map.lookup l (litBranches bs) of
64
Nothing -> match' stack''
65
Just cc -> match cc (args0 ++ args1) patchLit stack''
67
stack'' = (++ stack') $ case ignoreSharing cv of
68
Con c vs -> case Map.lookup c (conBranches bs) of
70
Just cc -> [(content cc, args0 ++ map (MaybeRed red) vs ++ args1, patchCon c (length vs))]
72
NotBlocked (Con c vs) -> case Map.lookup c (conBranches bs) of
73
Nothing -> match' stack'
74
Just cc -> match (content cc)
75
(args0 ++ map (MaybeRed red) vs ++ args1)
76
(patchCon c (length vs))
78
NotBlocked _ -> return $ NoReduction $ NotBlocked (patch $ map ignoreReduced args')
80
match' :: Stack -> TCM (Reduced (Blocked Args) Term)
81
match' ((c, args, patch):stack) = match c args patch stack
82
match' [] = typeError $ GenericError "Incomplete pattern matching"
84
unfoldCorecursion v = case v of
85
Def f args -> unfoldDefinition True unfoldCorecursion (Def f []) f args
86
Shared{} -> fmap shared <$> unfoldCorecursion (ignoreSharing v) -- don't update when unfolding corecursion!
68
match' :: Stack -> ReduceM (Reduced (Blocked Elims) Term)
69
match' ((c, es, patch) : stack) = do
71
traceSDoc "reduce.compiled" 95 $ vcat $
72
[ text "reducing case" <+> do
73
caseMaybeM (asks envAppDef) __IMPOSSIBLE__ $ \ f -> do
74
sep $ prettyTCM f : map prettyTCM es
75
, text $ "trying clause " ++ show c
77
let no es = return $ NoReduction $ NotBlocked $ patch $ map ignoreReduced es
78
noBlocked x es = return $ NoReduction $ Blocked x $ patch $ map ignoreReduced es
79
yes t = flip YesReduction t <$> asks envSimplification
81
-- traceSLn "reduce.compiled" 95 "CompiledClause.Match.match'" $ do
91
-- if the function was partially applied, return a lambda
92
| m < n -> yes $ applySubst (toSubst es) $ foldr lam t (drop m xs)
93
-- otherwise, just apply instantiation to body
94
-- apply the result to any extra arguments
95
| otherwise -> yes $ applySubst (toSubst es0) t `applyE` map ignoreReduced es1
96
-- | otherwise -> yes $ applySubst (toSubst args0) t `apply` map ignoreReduced args1
100
-- at least the first @n@ elims must be @Apply@s, so we can
101
-- turn them into a subsitution
102
toSubst = parallelS . reverse . map (unArg . argFromElim . ignoreReduced)
103
-- (args0, args1) = splitAt n $ map (fmap $ fmap shared) args
104
-- (args0, es1) = takeArgsFromElims n $ map (fmap $ fmap shared) args
105
-- Andreas, 2013-05-21 why introduce sharing only here,
106
-- and not in underapplied case also?
107
(es0, es1) = splitAt n $ map (fmap $ fmap shared) es
108
lam x t = Lam (argInfo x) (Abs (unArg x) t)
110
-- splitting on the @n@th elimination
112
case genericSplitAt n es of
113
-- if the @n@th elimination is not supplied, no match
115
-- if the @n@th elimination is @e0@
116
-- (args0, MaybeRed red (Arg info v0) : args1) -> do
117
(es0, MaybeRed red e0 : es1) -> do
118
-- get the reduced form of @e0@
121
Reduced b -> return $ v0 <$ b
122
NotReduced -> unfoldCorecursion v0
123
let v = ignoreBlocking w
124
args' = args0 ++ [MaybeRed red $ Arg info v] ++ args1
126
eb :: Blocked Elim <- do
128
Reduced b -> return $ e0 <$ b
129
NotReduced -> unfoldCorecursionE e0
130
let e = ignoreBlocking eb
131
-- replace the @n@th argument by its reduced form
132
es' = es0 ++ [MaybeRed red e] ++ es1
133
-- if a catch-all clause exists, put it on the stack
134
catchAllFrame stack = maybe stack (\c -> (c, es', patch) : stack) (catchAllBranch bs)
135
-- If our argument is @Lit l@, we push @litFrame l@ onto the stack.
137
case Map.lookup l (litBranches bs) of
139
Just cc -> (cc, es0 ++ es1, patchLit) : stack
140
-- If our argument (or its constructor form) is @Con c vs@
141
-- we push @conFrame c vs@ onto the stack.
142
conFrame c vs stack =
143
case Map.lookup (conName c) (conBranches bs) of
145
Just cc -> ( content cc
146
, es0 ++ map (MaybeRed red . Apply) vs ++ es1
147
, patchCon c (length vs)
149
-- If our argument is @Proj p@, we push @projFrame p@ onto the stack.
151
case Map.lookup p (conBranches bs) of
153
Just cc -> (content cc, es0 ++ es1, patchLit) : stack
154
-- The new patch function restores the @n@th argument to @v@:
155
-- In case we matched a literal, just put @v@ back.
156
patchLit es = patch (es0 ++ [e] ++ es1)
157
where (es0, es1) = splitAt n es
158
-- In case we matched constructor @c@ with @m@ arguments,
159
-- contract these @m@ arguments @vs@ to @Con c vs@.
160
patchCon c m es = patch (es0 ++ [Con c vs <$ e] ++ es2)
161
where (es0, rest) = splitAt n es
162
(es1, es2) = splitAt m rest
163
vs = map argFromElim es1
165
-- Now do the matching on the @n@ths argument:
166
case fmap ignoreSharing <$> eb of
167
Blocked x _ -> noBlocked x es'
168
NotBlocked (Apply (Arg info (MetaV x _))) -> noBlocked x es'
170
-- In case of a literal, try also its constructor form
171
NotBlocked (Apply (Arg info v@(Lit l))) -> performedSimplification $ do
172
cv <- constructorForm v
173
let cFrame stack = case ignoreSharing cv of
174
Con c vs -> conFrame c vs stack
176
match' $ litFrame l $ cFrame $ catchAllFrame stack
178
-- In case of a constructor, push the conFrame
179
NotBlocked (Apply (Arg info (Con c vs))) -> performedSimplification $
180
match' $ conFrame c vs $ catchAllFrame $ stack
182
-- In case of a projection, push the litFrame
183
NotBlocked (Proj p) -> performedSimplification $
184
match' $ projFrame p $ stack
186
NotBlocked _ -> no es'
188
-- If we reach the empty stack, then pattern matching was incomplete
189
match' [] = do {- new line here since __IMPOSSIBLE__ does not like the ' in match' -}
190
caseMaybeM (asks envAppDef) __IMPOSSIBLE__ $ \ f -> do
191
error $ "Incomplete pattern matching when applying " ++ show f
194
-- Andreas, 2013-03-20 recursive invokations of unfoldCorecursion
195
-- need also to instantiate metas, see Issue 826.
196
unfoldCorecursionE :: Elim -> ReduceM (Blocked Elim)
197
unfoldCorecursionE e@(Proj f) = return $ NotBlocked e
198
unfoldCorecursionE (Apply (Arg info v)) = fmap (Apply . Arg info) <$>
201
unfoldCorecursion :: Term -> ReduceM (Blocked Term)
202
unfoldCorecursion v = do
205
Def f es -> unfoldDefinitionE True unfoldCorecursion (Def f []) f es
206
Shared{} -> fmap shared <$> unfoldCorecursion (ignoreSharing v) -- don't update when unfolding corecursion!