2Module : Idris.Core.CaseTree
3Description : Module to define and interact with case trees.
6Maintainer : The Idris Community.
8Note: The case-tree elaborator only produces (Case n alts)-cases;
9in other words, it never inspects anything else than variables.
11ProjCase is a special powerful case construct that allows inspection
12of compound terms. Occurrences of ProjCase arise no earlier than
13in the function `prune` as a means of optimisation
14of already built case trees.
16While the intermediate representation (follows in the pipeline, named LExp)
17allows casing on arbitrary terms, here we choose to maintain the distinction
18in order to allow for better optimisation opportunities.
22{-# LANGUAGE DeriveFunctor, DeriveGeneric, FlexibleContexts, FlexibleInstances,
23 PatternGuards, TypeSynonymInstances #-}
25module Idris.Core.CaseTree (
26 CaseDef(..), SC, SC'(..), CaseAlt, CaseAlt'(..), ErasureInfo
27 , Phase(..), CaseTree, CaseType(..)
28 , simpleCase, small, namesUsed, findCalls, findCalls', findUsedArgs
29 , substSC, substAlt, mkForce
34import Control.Monad.Reader
35import Control.Monad.State
36import Data.List hiding (partition)
37import qualified Data.List (partition)
38import qualified Data.Set as S
39import GHC.Generics (Generic)
41data CaseDef = CaseDef [Name] !SC [Term]
44data SC' t = Case CaseType Name [CaseAlt' t] -- ^ invariant: lowest tags first
45 | ProjCase t [CaseAlt' t] -- ^ special case for projections/thunk-forcing before inspection
47 | UnmatchedCase String -- ^ error message
48 | ImpossibleCase -- ^ already checked to be impossible
49 deriving (Eq, Ord, Functor, Generic)
51deriving instance Binary SC'
54data CaseType = Updatable | Shared
55 deriving (Eq, Ord, Show, Generic)
59data CaseAlt' t = ConCase Name Int [Name] !(SC' t)
60 | FnCase Name [Name] !(SC' t) -- ^ reflection function
61 | ConstCase Const !(SC' t)
62 | SucCase Name !(SC' t)
63 | DefaultCase !(SC' t)
64 deriving (Show, Eq, Ord, Functor, Generic)
66deriving instance Binary CaseAlt'
69type CaseAlt = CaseAlt' Term
71instance Show t => Show (SC' t) where
74 show' i (Case up n alts) = "case" ++ u ++ show n ++ " of\n" ++ indent i ++
75 showSep ("\n" ++ indent i) (map (showA i) alts)
79 show' i (ProjCase tm alts) = "case " ++ show tm ++ " of " ++
80 showSep ("\n" ++ indent i) (map (showA i) alts)
81 show' i (STerm tm) = show tm
82 show' i (UnmatchedCase str) = "error " ++ show str
83 show' i ImpossibleCase = "impossible"
85 indent i = concat $ take i (repeat " ")
87 showA i (ConCase n t args sc)
88 = show n ++ "(" ++ showSep (", ") (map show args) ++ ") => "
90 showA i (FnCase n args sc)
91 = "FN " ++ show n ++ "(" ++ showSep (", ") (map show args) ++ ") => "
93 showA i (ConstCase t sc)
94 = show t ++ " => " ++ show' (i+1) sc
95 showA i (SucCase n sc)
96 = show n ++ "+1 => " ++ show' (i+1) sc
97 showA i (DefaultCase sc)
98 = "_ => " ++ show' (i+1) sc
102type Clause = ([Pat], (Term, Term))
103type CS = ([Term], Int, [(Name, Type)])
105instance TermSize SC where
106 termsize n (Case _ n' as) = termsize n as
107 termsize n (ProjCase n' as) = termsize n as
108 termsize n (STerm t) = termsize n t
111instance TermSize CaseAlt where
112 termsize n (ConCase _ _ _ s) = termsize n s
113 termsize n (FnCase _ _ s) = termsize n s
114 termsize n (ConstCase _ s) = termsize n s
115 termsize n (SucCase _ s) = termsize n s
116 termsize n (DefaultCase s) = termsize n s
118-- simple terms can be inlined trivially - good for primitives in particular
119-- To avoid duplicating work, don't inline something which uses one
120-- of its arguments in more than one place
122small :: Name -> [Name] -> SC -> Bool
123small n args t = let as = findAllUsedArgs t args in
124 length as == length (nub as) &&
127namesUsed :: SC -> [Name]
128namesUsed sc = nub $ nu' [] sc where
129 nu' ps (Case _ n alts) = nub (concatMap (nua ps) alts) \\ [n]
130 nu' ps (ProjCase t alts) = nub $ nut ps t ++ concatMap (nua ps) alts
131 nu' ps (STerm t) = nub $ nut ps t
134 nua ps (ConCase n i args sc) = nub (nu' (ps ++ args) sc) \\ args
135 nua ps (FnCase n args sc) = nub (nu' (ps ++ args) sc) \\ args
136 nua ps (ConstCase _ sc) = nu' ps sc
137 nua ps (SucCase _ sc) = nu' ps sc
138 nua ps (DefaultCase sc) = nu' ps sc
140 nut ps (P _ n _) | n `elem` ps = []
142 nut ps (App _ f a) = nut ps f ++ nut ps a
143 nut ps (Proj t _) = nut ps t
144 nut ps (Bind n (Let _ t v) sc) = nut ps v ++ nut (n:ps) sc
145 nut ps (Bind n b sc) = nut (n:ps) sc
148-- | Return all called functions, and which arguments are used
149-- in each argument position for the call, in order to help reduce
150-- compilation time, and trace all unused arguments
151findCalls :: SC -> [Name] -> [(Name, [[Name]])]
152findCalls = findCalls' False
154findCalls' :: Bool -> SC -> [Name] -> [(Name, [[Name]])]
155findCalls' ignoreasserts sc topargs = S.toList $ nu' topargs sc where
156 nu' ps (Case _ n alts) = S.unions $ map (nua (n : ps)) alts
157 nu' ps (ProjCase t alts) = S.unions $ nut ps t : map (nua ps) alts
158 nu' ps (STerm t) = nut ps t
161 nua ps (ConCase n i args sc) = nu' (ps ++ args) sc
162 nua ps (FnCase n args sc) = nu' (ps ++ args) sc
163 nua ps (ConstCase _ sc) = nu' ps sc
164 nua ps (SucCase _ sc) = nu' ps sc
165 nua ps (DefaultCase sc) = nu' ps sc
167 nut ps (P _ n _) | n `elem` ps = S.empty
168 | otherwise = S.singleton (n, [])
169 nut ps fn@(App _ f a)
170 | (P _ n _, args) <- unApply fn
171 = if ignoreasserts && n == sUN "assert_total"
174 then S.union (nut ps f) (nut ps a)
175 else S.insert (n, map argNames args)
176 (S.unions $ map (nut ps) args)
177 | (P (TCon _ _) n _, _) <- unApply fn = S.empty
178 | otherwise = S.union (nut ps f) (nut ps a)
179 nut ps (Bind n (Let _ t v) sc) = S.union (nut ps v) (nut (n:ps) sc)
180 nut ps (Proj t _) = nut ps t
181 nut ps (Bind n b sc) = nut (n:ps) sc
184 argNames tm = let ns = directUse tm in
185 filter (\x -> x `elem` ns) topargs
187-- Find names which are used directly (i.e. not in a function call) in a term
189directUse :: TT Name -> [Name]
190directUse (P _ n _) = [n]
191directUse (Bind n (Let _ t v) sc) = nub $ directUse v ++ (directUse sc \\ [n])
193directUse (Bind n b sc) = nub $ directUse (binderTy b) ++ (directUse sc \\ [n])
194directUse fn@(App _ f a)
195 | (P Ref (UN pfk) _, [App _ e w]) <- unApply fn,
196 pfk == txt "prim_fork"
197 = directUse e ++ directUse w -- HACK so that fork works
198 | (P Ref (UN fce) _, [_, _, a]) <- unApply fn,
200 = directUse a -- forcing a value counts as a use
201 | (P Ref n _, args) <- unApply fn = [] -- need to know what n does with them
202 | (P (TCon _ _) n _, args) <- unApply fn = [] -- type constructors not used at runtime
203 | otherwise = nub $ directUse f ++ directUse a
204directUse (Proj x i) = nub $ directUse x
207-- Find all directly used arguments (i.e. used but not in function calls)
209findUsedArgs :: SC -> [Name] -> [Name]
210findUsedArgs sc topargs = nub (findAllUsedArgs sc topargs)
212findAllUsedArgs sc topargs = filter (\x -> x `elem` topargs) (nu' sc) where
213 nu' (Case _ n alts) = n : concatMap nua alts
214 nu' (ProjCase t alts) = directUse t ++ concatMap nua alts
215 nu' (STerm t) = directUse t
218 nua (ConCase n i args sc) = nu' sc
219 nua (FnCase n args sc) = nu' sc
220 nua (ConstCase _ sc) = nu' sc
221 nua (SucCase _ sc) = nu' sc
222 nua (DefaultCase sc) = nu' sc
224-- Return whether name is used anywhere in a case tree
225isUsed :: SC -> Name -> Bool
226isUsed sc n = used sc where
228 used (Case _ n' alts) = n == n' || any usedA alts
229 used (ProjCase t alts) = n `elem` freeNames t || any usedA alts
230 used (STerm t) = n `elem` freeNames t
233 usedA (ConCase _ _ args sc) = used sc
234 usedA (FnCase _ args sc) = used sc
235 usedA (ConstCase _ sc) = used sc
236 usedA (SucCase _ sc) = used sc
237 usedA (DefaultCase sc) = used sc
239type ErasureInfo = Name -> [Int] -- name to list of inaccessible arguments; empty list if name not found
240type CaseBuilder a = ReaderT ErasureInfo (State CS) a
242runCaseBuilder :: ErasureInfo -> CaseBuilder a -> (CS -> (a, CS))
243runCaseBuilder ei bld = runState $ runReaderT bld ei
245data Phase = CoverageCheck [Int] -- list of positions explicitly given
250-- Generate a simple case tree
253simpleCase :: Bool -> SC -> Bool ->
255 -- Following two can be empty lists when Phase = CoverageCheck
256 [Int] -> -- Inaccessible argument positions
257 [(Type, Bool)] -> -- (Argument type, whether it's canonical)
258 [([Name], Term, Term)] ->
261simpleCase tc defcase reflect phase fc inacc argtys cs erInfo
262 = sc' tc defcase phase fc (filter (\(_, _, r) ->
267 sc' tc defcase phase fc []
268 = return $ CaseDef [] (UnmatchedCase (show fc ++ ":No pattern clauses")) []
269 sc' tc defcase phase fc cs
270 = let proj = phase == RunTime
271 pats = map (\ (avs, l, r) ->
272 (avs, toPats reflect tc l, (l, r))) cs
273 chkPats = mapM chkAccessible pats in
276 let numargs = length (fst (head pats))
277 ns = take numargs args
278 (ns', ps') = order phase [(n, i `elem` inacc) | (i,n) <- zip [0..] ns] pats (map snd argtys)
279 (tree, st) = runCaseBuilder erInfo
280 (match ns' ps' defcase)
282 t = CaseDef ns (prune proj (depatt ns' tree)) (fstT st) in
283 if proj then return (stripLambdas t)
285 Error err -> Error (At fc err)
286 where args = map (\i -> sMN i "e") [0..]
289 -- Check that all pattern variables are reachable by a case split
290 -- Otherwise, they won't make sense on the RHS.
291 chkAccessible (avs, l, c)
292 | phase /= CompileTime || reflect = return (l, c)
293 | otherwise = do mapM_ (acc l) avs
296 acc [] n = Error (Inaccessible n)
297 acc (PV x t : xs) n | x == n = OK ()
298 acc (PCon _ _ _ ps : xs) n = acc (ps ++ xs) n
299 acc (PSuc p : xs) n = acc (p : xs) n
300 acc (_ : xs) n = acc xs n
302data Pat = PCon Bool Name Int [Pat]
306 | PSuc Pat -- special case for n+1 on Integer
307 | PReflected Name [Pat]
309 | PTyPat -- typecase, not allowed, inspect last
312-- If there are repeated variables, take the *last* one (could be name shadowing
313-- in a where clause, so take the most recent).
315toPats :: Bool -> Bool -> Term -> [Pat]
316toPats reflect tc f = reverse (toPat reflect tc (getArgs f)) where
317 getArgs (App _ f a) = a : getArgs f
320toPat :: Bool -> Bool -> [Term] -> [Pat]
321toPat reflect tc = map $ toPat' []
323 toPat' [_,_,arg] (P (DCon t a uniq) nm@(UN n) _)
325 = PCon uniq nm t [PAny, PAny, toPat' [] arg]
327 toPat' args (P (DCon t a uniq) nm@(NS (UN n) [own]) _)
328 | n == txt "Read" && own == txt "Ownership"
329 = PCon False nm t (map shareCons (map (toPat' []) args))
330 where shareCons (PCon _ n i ps) = PCon False n i (map shareCons ps)
333 toPat' args (P (DCon t a uniq) n _)
334 = PCon uniq n t $ map (toPat' []) args
337 toPat' [p, Constant (BI 1)] (P _ (UN pabi) _)
338 | pabi == txt "prim__addBigInt"
341 toPat' [] (P Bound n ty) = PV n ty
342 toPat' args (App _ f a) = toPat' (a : args) f
343 toPat' args (Inferred tm) = PInferred (toPat' args tm)
344 toPat' [] (Constant x) | isTypeConst x = PTyPat
345 | otherwise = PConst x
347 toPat' [] (Bind n (Pi _ _ t _) sc)
348 | reflect && noOccurrence n sc
349 = PReflected (sUN "->") [toPat' [] t, toPat' [] sc]
351 toPat' args (P _ n _)
353 = PReflected n $ map (toPat' []) args
357data Partition = Cons [Clause]
361isVarPat (PV _ _ : ps , _) = True
362isVarPat (PAny : ps , _) = True
363isVarPat (PTyPat : ps , _) = True
366isConPat (PCon _ _ _ _ : ps, _) = True
367isConPat (PReflected _ _ : ps, _) = True
368isConPat (PSuc _ : ps, _) = True
369isConPat (PConst _ : ps, _) = True
372partition :: [Clause] -> [Partition]
375 | isVarPat m = let (vars, rest) = span isVarPat ms in
376 Vars vars : partition rest
377 | isConPat m = let (cons, rest) = span isConPat ms in
378 Cons cons : partition rest
379partition xs = error $ "Partition " ++ show xs
381-- reorder the patterns so that the one with most distinct names
382-- comes next. Take rightmost first, otherwise (i.e. pick value rather
385-- The first argument means [(Name, IsInaccessible)].
387order :: Phase -> [(Name, Bool)] -> [Clause] -> [Bool] -> ([Name], [Clause])
388-- do nothing at compile time: FIXME (EB): Put this in after checking
389-- implications for Franck's reflection work... see issue 3233
390-- order CompileTime ns cs _ = (map fst ns, cs)
391order _ [] cs cans = ([], cs)
392order _ ns' [] cans = (map fst ns', [])
393order (CoverageCheck pos) ns' cs cans
394 = let ns_out = pick 0 [] (map fst ns')
395 cs_out = map pickClause cs in
398 pickClause (pats, def) = (pick 0 [] pats, def)
400 -- Order the list so that things in a position in 'pos' are in the first
401 -- part, then all the other things later. Otherwise preserve order.
402 pick i skipped [] = reverse skipped
403 pick i skipped (x : xs)
404 | i `elem` pos = x : pick (i + 1) skipped xs
405 | otherwise = pick (i + 1) (x : skipped) xs
407order phase ns' cs cans
408 = let patnames = transpose (map (zip ns') (map (zip cans) (map fst cs)))
409 -- only sort the arguments where there is no clash in
410 -- constructor tags between families, the argument type is canonical,
411 -- and no constructor/constant
412 -- clash, because otherwise we can't reliable make the
413 -- case distinction on evaluation
414 (patnames_ord, patnames_rest)
415 = Data.List.partition (noClash . map snd) patnames
416 patnames_ord' = case phase of
417 CompileTime -> patnames_ord
418 -- reversing tends to make better case trees
420 RunTime -> reverse patnames_ord
421 pats' = transpose (sortBy moreDistinct patnames_ord'
423 (getNOrder pats', zipWith rebuild pats' cs)
425 getNOrder [] = error $ "Failed order on " ++ show (map fst ns', cs)
426 getNOrder (c : _) = map (fst . fst) c
428 rebuild patnames clause = (map (snd . snd) patnames, snd clause)
431 noClash ((can, p) : ps) = can && not (any (clashPat p) (map snd ps))
434 clashPat (PCon _ _ _ _) (PConst _) = True
435 clashPat (PConst _) (PCon _ _ _ _) = True
436 clashPat (PCon _ _ _ _) (PSuc _) = True
437 clashPat (PSuc _) (PCon _ _ _ _) = True
438 clashPat (PCon _ n i _) (PCon _ n' i' _) | i == i' = n /= n'
441 -- this compares (+isInaccessible, -numberOfCases)
443 = compare (snd . fst . head $ xs, numNames [] (map snd ys))
444 (snd . fst . head $ ys, numNames [] (map snd xs))
446 numNames xs ((_, PCon _ n _ _) : ps)
447 | not (Left n `elem` xs) = numNames (Left n : xs) ps
448 numNames xs ((_, PConst c) : ps)
449 | not (Right c `elem` xs) = numNames (Right c : xs) ps
450 numNames xs (_ : ps) = numNames xs ps
451 numNames xs [] = length xs
453-- Reorder the patterns in the clause so that the PInferred patterns come
454-- last. Also strip 'PInferred' from the top level patterns so that we can
455-- go ahead and match.
456orderByInf :: [Name] -> [Clause] -> ([Name], [Clause])
457orderByInf vs cs = let alwaysInf = getInf cs in
458 (selectInf alwaysInf vs,
459 map deInf (map (selectExp alwaysInf) cs))
462 getInf [(pats, def)] = infPos 0 pats
463 getInf ((pats, def) : cs) = infPos 0 pats `intersect` getInf cs
465 selectExp :: [Int] -> Clause -> Clause
466 selectExp infs (pats, def)
467 = let (notInf, inf) = splitPats 0 infs [] [] pats in
470 selectInf :: [Int] -> [a] -> [a]
471 selectInf infs ns = let (notInf, inf) = splitPats 0 infs [] [] ns in
474 splitPats i infpos notInf inf [] = (reverse notInf, reverse inf)
475 splitPats i infpos notInf inf (p : ps)
476 | i `elem` infpos = splitPats (i + 1) infpos notInf (p : inf) ps
477 | otherwise = splitPats (i + 1) infpos (p : notInf) inf ps
480 infPos i (PInferred p : ps) = i : infPos (i + 1) ps
481 infPos i (_ : ps) = infPos (i + 1) ps
483 deInf (pats, def) = (map deInfPat pats, def)
485 deInfPat (PInferred p) = p
488match :: [Name] -> [Clause] -> SC -- error case
490match [] (([], ret) : xs) err
491 = do (ts, v, ntys) <- get
492 put (ts ++ (map (fst.snd) xs), v, ntys)
494 Impossible -> return ImpossibleCase
495 tm -> return $ STerm tm -- run out of arguments
496match vs cs err = do let (vs', de_inf) = orderByInf vs cs
497 ps = partition de_inf
500mixture :: [Name] -> [Partition] -> SC -> CaseBuilder SC
501mixture vs [] err = return err
502mixture vs (Cons ms : ps) err = do fallthrough <- mixture vs ps err
503 conRule vs ms fallthrough
504mixture vs (Vars ms : ps) err = do fallthrough <- mixture vs ps err
505 varRule vs ms fallthrough
507-- Return the list of inaccessible arguments of a data constructor.
508inaccessibleArgs :: Name -> CaseBuilder [Int]
509inaccessibleArgs n = do
510 getInaccessiblePositions <- ask -- this function is the only thing in the environment
511 return $ getInaccessiblePositions n
513data ConType = CName Name Int -- named constructor
514 | CFn Name -- reflected function name
516 | CConst Const -- constant, not implemented yet
519data Group = ConGroup Bool -- Uniqueness flag
520 ConType -- Constructor
521 [([Pat], Clause)] -- arguments and rest of alternative
524conRule :: [Name] -> [Clause] -> SC -> CaseBuilder SC
525conRule (v:vs) cs err = do groups <- groupCons cs
526 caseGroups (v:vs) groups err
528caseGroups :: [Name] -> [Group] -> SC -> CaseBuilder SC
529caseGroups (v:vs) gs err = do g <- altGroups gs
530 return $ Case (getShared gs) v (sort g)
532 getShared (ConGroup True _ _ : _) = Updatable
535 altGroups [] = return [DefaultCase err]
537 altGroups (ConGroup _ (CName n i) args : cs)
538 = (:) <$> altGroup n i args <*> altGroups cs
540 altGroups (ConGroup _ (CFn n) args : cs)
541 = (:) <$> altFnGroup n args <*> altGroups cs
543 altGroups (ConGroup _ CSuc args : cs)
544 = (:) <$> altSucGroup args <*> altGroups cs
546 altGroups (ConGroup _ (CConst c) args : cs)
547 = (:) <$> altConstGroup c args <*> altGroups cs
550 = do inacc <- inaccessibleArgs n
551 (newVars, accVars, inaccVars, nextCs) <- argsToAlt inacc args
552 matchCs <- match (accVars ++ vs ++ inaccVars) nextCs err
553 return $ ConCase n i newVars matchCs
555 altFnGroup n args = do (newVars, _, [], nextCs) <- argsToAlt [] args
556 matchCs <- match (newVars ++ vs) nextCs err
557 return $ FnCase n newVars matchCs
559 altSucGroup args = do ([newVar], _, [], nextCs) <- argsToAlt [] args
560 matchCs <- match (newVar:vs) nextCs err
561 return $ SucCase newVar matchCs
563 altConstGroup n args = do (_, _, [], nextCs) <- argsToAlt [] args
564 matchCs <- match vs nextCs err
565 return $ ConstCase n matchCs
568-- * names of all variables arising from match
569-- * names of accessible variables (subset of all variables)
570-- * names of inaccessible variables (subset of all variables)
571-- * clauses corresponding to (accVars ++ origVars ++ inaccVars)
572argsToAlt :: [Int] -> [([Pat], Clause)] -> CaseBuilder ([Name], [Name], [Name], [Clause])
573argsToAlt _ [] = return ([], [], [], [])
574argsToAlt inacc rs@((r, m) : rest) = do
575 newVars <- getNewVars r
576 let (accVars, inaccVars) = partitionAcc newVars
577 return (newVars, accVars, inaccVars, addRs rs)
579 -- Create names for new variables arising from the given patterns.
580 getNewVars :: [Pat] -> CaseBuilder [Name]
581 getNewVars [] = return []
582 getNewVars ((PV n t) : ns) = do v <- getVar "e"
585 -- Record the type of the variable.
587 -- It seems that the ordering is not important
588 -- and we can put (v,t) always in front of "ntys"
589 -- (the varName-type pairs seem to represent a mapping).
591 -- The code that reads this is currently
592 -- commented out, anyway.
594 put (cs, i, (v, t) : ntys)
598 getNewVars (PAny : ns) = (:) <$> getVar "i" <*> getNewVars ns
599 getNewVars (PTyPat : ns) = (:) <$> getVar "t" <*> getNewVars ns
600 getNewVars (_ : ns) = (:) <$> getVar "e" <*> getNewVars ns
602 -- Partition a list of things into (accessible, inaccessible) things,
603 -- according to the list of inaccessible indices.
605 ( [x | (i,x) <- zip [0..] xs, i `notElem` inacc]
606 , [x | (i,x) <- zip [0..] xs, i `elem` inacc]
610 addRs ((r, (ps, res)) : rs) = ((acc++ps++inacc, res) : addRs rs)
612 (acc, inacc) = partitionAcc r
614getVar :: String -> CaseBuilder Name
615getVar b = do (t, v, ntys) <- get; put (t, v+1, ntys); return (sMN v b)
617groupCons :: [Clause] -> CaseBuilder [Group]
618groupCons cs = gc [] cs
620 gc acc [] = return acc
621 gc acc ((p : ps, res) : cs) =
622 do acc' <- addGroup p ps res acc
624 addGroup p ps res acc = case p of
625 PCon uniq con i args -> return $ addg uniq (CName con i) args (ps, res) acc
626 PConst cval -> return $ addConG cval (ps, res) acc
627 PSuc n -> return $ addg False CSuc [n] (ps, res) acc
628 PReflected fn args -> return $ addg False (CFn fn) args (ps, res) acc
629 pat -> fail $ show pat ++ " is not a constructor or constant (can't happen)"
631 addg uniq c conargs res []
632 = [ConGroup uniq c [(conargs, res)]]
633 addg uniq c conargs res (g@(ConGroup _ c' cs):gs)
634 | c == c' = ConGroup uniq c (cs ++ [(conargs, res)]) : gs
635 | otherwise = g : addg uniq c conargs res gs
637 addConG con res [] = [ConGroup False (CConst con) [([], res)]]
638 addConG con res (g@(ConGroup False (CConst n) cs) : gs)
639 | con == n = ConGroup False (CConst n) (cs ++ [([], res)]) : gs
640-- | otherwise = g : addConG con res gs
641 addConG con res (g : gs) = g : addConG con res gs
643varRule :: [Name] -> [Clause] -> SC -> CaseBuilder SC
644varRule (v : vs) alts err =
645 do alts' <- mapM (repVar v) alts
648 repVar v (PV p ty : ps , (lhs, res))
649 = do (cs, i, ntys) <- get
650 put (cs, i, (v, ty) : ntys)
651 return (ps, (lhs, subst p (P Bound v ty) res))
652 repVar v (PAny : ps , res) = return (ps, res)
653 repVar v (PTyPat : ps , res) = return (ps, res)
655-- fix: case e of S k -> f (S k) ==> case e of S k -> f e
657depatt :: [Name] -> SC -> SC
658depatt ns tm = dp [] tm
660 dp ms (STerm tm) = STerm (applyMaps ms tm)
661 dp ms (Case up x alts) = Case up x (map (dpa ms x) alts)
664 dpa ms x (ConCase n i args sc)
665 = ConCase n i args (dp ((x, (n, args)) : ms) sc)
666 dpa ms x (FnCase n args sc)
667 = FnCase n args (dp ((x, (n, args)) : ms) sc)
668 dpa ms x (ConstCase c sc) = ConstCase c (dp ms sc)
669 dpa ms x (SucCase n sc) = SucCase n (dp ms sc)
670 dpa ms x (DefaultCase sc) = DefaultCase (dp ms sc)
672 applyMaps ms f@(App _ _ _)
673 | (P nt cn pty, args) <- unApply f
674 = let args' = map (applyMaps ms) args in
675 applyMap ms nt cn pty args'
677 applyMap [] nt cn pty args' = mkApp (P nt cn pty) args'
678 applyMap ((x, (n, args)) : ms) nt cn pty args'
679 | and ((length args == length args') :
680 (n == cn) : zipWith same args args') = P Ref x Erased
681 | otherwise = applyMap ms nt cn pty args'
682 same n (P _ n' _) = n == n'
685 applyMaps ms (App s f a) = App s (applyMaps ms f) (applyMaps ms a)
688-- FIXME: Do this for SucCase too
689-- Issue #1719 on the issue tracker: https://github.com/idris-lang/Idris-dev/issues/1719
690prune :: Bool -- ^ Convert single branches to projections (only useful at runtime)
692prune proj (Case up n alts) = case alts' of
695 -- Projection transformations prevent us from seeing some uses of ctor fields
696 -- because they delete information about which ctor is being used.
698 -- f (X x) = ... x ...
702 -- Hence, we disable this step.
703 -- TODO: re-enable this in toIR
705 -- as@[ConCase cn i args sc]
706 -- | proj -> mkProj n 0 args (prune proj sc)
707 -- mkProj n i xs sc = foldr (\x -> projRep x n i) sc xs
709 -- If none of the args are used in the sc, however, we can just replace it
711 as@[ConCase cn i args sc]
712 | proj -> let sc' = prune proj sc in
713 if any (isUsed sc') args
714 then Case up n [ConCase cn i args sc']
719 -> projRep cn n (-1) $ prune proj sc
724 -- Bit of a hack here! The default case will always be 0, make sure
725 -- it gets caught first.
726 [s@(SucCase _ _), DefaultCase dc]
727 -> Case up n [ConstCase (BI 0) dc, s]
731 alts' = filter (not . erased) $ map pruneAlt alts
733 pruneAlt (ConCase cn i ns sc) = ConCase cn i ns (prune proj sc)
734 pruneAlt (FnCase cn ns sc) = FnCase cn ns (prune proj sc)
735 pruneAlt (ConstCase c sc) = ConstCase c (prune proj sc)
736 pruneAlt (SucCase n sc) = SucCase n (prune proj sc)
737 pruneAlt (DefaultCase sc) = DefaultCase (prune proj sc)
739 erased (DefaultCase (STerm Erased)) = True
740 erased (DefaultCase ImpossibleCase) = True
743 projRep :: Name -> Name -> Int -> SC -> SC
744 projRep arg n i (Case up x alts) | x == arg
745 = ProjCase (Proj (P Bound n Erased) i) $ map (projRepAlt arg n i) alts
746 projRep arg n i (Case up x alts)
747 = Case up x (map (projRepAlt arg n i) alts)
748 projRep arg n i (ProjCase t alts)
749 = ProjCase (projRepTm arg n i t) $ map (projRepAlt arg n i) alts
750 projRep arg n i (STerm t) = STerm (projRepTm arg n i t)
751 projRep arg n i c = c
753 projRepAlt arg n i (ConCase cn t args rhs)
754 = ConCase cn t args (projRep arg n i rhs)
755 projRepAlt arg n i (FnCase cn args rhs)
756 = FnCase cn args (projRep arg n i rhs)
757 projRepAlt arg n i (ConstCase t rhs)
758 = ConstCase t (projRep arg n i rhs)
759 projRepAlt arg n i (SucCase sn rhs)
760 = SucCase sn (projRep arg n i rhs)
761 projRepAlt arg n i (DefaultCase rhs)
762 = DefaultCase (projRep arg n i rhs)
764 projRepTm arg n i t = subst arg (Proj (P Bound n Erased) i) t
768stripLambdas :: CaseDef -> CaseDef
769stripLambdas (CaseDef ns (STerm (Bind x (Lam _ _) sc)) tm)
770 = stripLambdas (CaseDef (ns ++ [x]) (STerm (instantiate (P Bound x Erased) sc)) tm)
773substSC :: Name -> Name -> SC -> SC
774substSC n repl (Case up n' alts)
775 | n == n' = Case up repl (map (substAlt n repl) alts)
776 | otherwise = Case up n' (map (substAlt n repl) alts)
777substSC n repl (STerm t) = STerm $ subst n (P Bound repl Erased) t
778substSC n repl (UnmatchedCase errmsg) = UnmatchedCase errmsg
779substSC n repl ImpossibleCase = ImpossibleCase
780substSC n repl sc = error $ "unsupported in substSC: " ++ show sc
782substAlt :: Name -> Name -> CaseAlt -> CaseAlt
783substAlt n repl (ConCase cn a ns sc) = ConCase cn a ns (substSC n repl sc)
784substAlt n repl (FnCase fn ns sc) = FnCase fn ns (substSC n repl sc)
785substAlt n repl (ConstCase c sc) = ConstCase c (substSC n repl sc)
786substAlt n repl (SucCase n' sc)
787 | n == n' = SucCase n (substSC n repl sc)
788 | otherwise = SucCase n' (substSC n repl sc)
789substAlt n repl (DefaultCase sc) = DefaultCase (substSC n repl sc)
791-- mkForce n' n t updates the tree t under the assumption that
792-- n' = force n (so basically updating n to n')
793mkForce :: Name -> Name -> SC -> SC
796 mkForceSC n arg (Case up x alts) | x == arg
797 = Case up n $ map (mkForceAlt n arg) alts
799 mkForceSC n arg (Case up x alts)
800 = Case up x (map (mkForceAlt n arg) alts)
802 mkForceSC n arg (ProjCase t alts)
803 = ProjCase t $ map (mkForceAlt n arg) alts
805 mkForceSC n arg c = c
807 mkForceAlt n arg (ConCase cn t args rhs)
808 = ConCase cn t args (mkForceSC n arg rhs)
809 mkForceAlt n arg (FnCase cn args rhs)
810 = FnCase cn args (mkForceSC n arg rhs)
811 mkForceAlt n arg (ConstCase t rhs)
812 = ConstCase t (mkForceSC n arg rhs)
813 mkForceAlt n arg (SucCase sn rhs)
814 = SucCase sn (mkForceSC n arg rhs)
815 mkForceAlt n arg (DefaultCase rhs)
816 = DefaultCase (mkForceSC n arg rhs)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list