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.
21{-# LANGUAGE PatternGuards, DeriveFunctor, TypeSynonymInstances,
24module Idris.Core.CaseTree (
25 CaseDef(..), SC, SC'(..), CaseAlt, CaseAlt'(..), ErasureInfo
26 , Phase(..), CaseTree, CaseType(..)
27 , simpleCase, small, namesUsed, findCalls, findCalls', findUsedArgs
28 , substSC, substAlt, mkForce
33import Control.Applicative hiding (Const)
34import Control.Monad.State
35import Control.Monad.Reader
37import Data.List hiding (partition)
38import qualified Data.List(partition)
40import GHC.Generics (Generic)
42data CaseDef = CaseDef [Name] !SC [Term]
45data SC' t = Case CaseType Name [CaseAlt' t] -- ^ invariant: lowest tags first
46 | ProjCase t [CaseAlt' t] -- ^ special case for projections/thunk-forcing before inspection
48 | UnmatchedCase String -- ^ error message
49 | ImpossibleCase -- ^ already checked to be impossible
50 deriving (Eq, Ord, Functor, Generic)
52deriving instance Binary SC'
53deriving instance NFData SC'
56data CaseType = Updatable | Shared
57 deriving (Eq, Ord, Show, Generic)
61data CaseAlt' t = ConCase Name Int [Name] !(SC' t)
62 | FnCase Name [Name] !(SC' t) -- ^ reflection function
63 | ConstCase Const !(SC' t)
64 | SucCase Name !(SC' t)
65 | DefaultCase !(SC' t)
66 deriving (Show, Eq, Ord, Functor, Generic)
68deriving instance Binary CaseAlt'
69deriving instance NFData CaseAlt'
72type CaseAlt = CaseAlt' Term
74instance Show t => Show (SC' t) where
77 show' i (Case up n alts) = "case" ++ u ++ show n ++ " of\n" ++ indent i ++
78 showSep ("\n" ++ indent i) (map (showA i) alts)
82 show' i (ProjCase tm alts) = "case " ++ show tm ++ " of " ++
83 showSep ("\n" ++ indent i) (map (showA i) alts)
84 show' i (STerm tm) = show tm
85 show' i (UnmatchedCase str) = "error " ++ show str
86 show' i ImpossibleCase = "impossible"
88 indent i = concat $ take i (repeat " ")
90 showA i (ConCase n t args sc)
91 = show n ++ "(" ++ showSep (", ") (map show args) ++ ") => "
93 showA i (FnCase n args sc)
94 = "FN " ++ show n ++ "(" ++ showSep (", ") (map show args) ++ ") => "
96 showA i (ConstCase t sc)
97 = show t ++ " => " ++ show' (i+1) sc
98 showA i (SucCase n sc)
99 = show n ++ "+1 => " ++ show' (i+1) sc
100 showA i (DefaultCase sc)
101 = "_ => " ++ show' (i+1) sc
105type Clause = ([Pat], (Term, Term))
106type CS = ([Term], Int, [(Name, Type)])
108instance TermSize SC where
109 termsize n (Case _ n' as) = termsize n as
110 termsize n (ProjCase n' as) = termsize n as
111 termsize n (STerm t) = termsize n t
114instance TermSize CaseAlt where
115 termsize n (ConCase _ _ _ s) = termsize n s
116 termsize n (FnCase _ _ s) = termsize n s
117 termsize n (ConstCase _ s) = termsize n s
118 termsize n (SucCase _ s) = termsize n s
119 termsize n (DefaultCase s) = termsize n s
121-- simple terms can be inlined trivially - good for primitives in particular
122-- To avoid duplicating work, don't inline something which uses one
123-- of its arguments in more than one place
125small :: Name -> [Name] -> SC -> Bool
126small n args t = let as = findAllUsedArgs t args in
127 length as == length (nub as) &&
130namesUsed :: SC -> [Name]
131namesUsed sc = nub $ nu' [] sc where
132 nu' ps (Case _ n alts) = nub (concatMap (nua ps) alts) \\ [n]
133 nu' ps (ProjCase t alts) = nub $ nut ps t ++ concatMap (nua ps) alts
134 nu' ps (STerm t) = nub $ nut ps t
137 nua ps (ConCase n i args sc) = nub (nu' (ps ++ args) sc) \\ args
138 nua ps (FnCase n args sc) = nub (nu' (ps ++ args) sc) \\ args
139 nua ps (ConstCase _ sc) = nu' ps sc
140 nua ps (SucCase _ sc) = nu' ps sc
141 nua ps (DefaultCase sc) = nu' ps sc
143 nut ps (P _ n _) | n `elem` ps = []
145 nut ps (App _ f a) = nut ps f ++ nut ps a
146 nut ps (Proj t _) = nut ps t
147 nut ps (Bind n (Let t v) sc) = nut ps v ++ nut (n:ps) sc
148 nut ps (Bind n b sc) = nut (n:ps) sc
151-- | Return all called functions, and which arguments are used
152-- in each argument position for the call, in order to help reduce
153-- compilation time, and trace all unused arguments
154findCalls :: SC -> [Name] -> [(Name, [[Name]])]
155findCalls = findCalls' False
157findCalls' :: Bool -> SC -> [Name] -> [(Name, [[Name]])]
158findCalls' ignoreasserts sc topargs = nub $ nu' topargs sc where
159 nu' ps (Case _ n alts) = nub (concatMap (nua (n : ps)) alts)
160 nu' ps (ProjCase t alts) = nub $ nut ps t ++ concatMap (nua ps) alts
161 nu' ps (STerm t) = nub $ nut ps t
164 nua ps (ConCase n i args sc) = nub (nu' (ps ++ args) sc)
165 nua ps (FnCase n args sc) = nub (nu' (ps ++ args) sc)
166 nua ps (ConstCase _ sc) = nu' ps sc
167 nua ps (SucCase _ sc) = nu' ps sc
168 nua ps (DefaultCase sc) = nu' ps sc
170 nut ps (P _ n _) | n `elem` ps = []
171 | otherwise = [(n, [])] -- tmp
172 nut ps fn@(App _ f a)
173 | (P _ n _, args) <- unApply fn
174 = if ignoreasserts && n == sUN "assert_total"
177 then nut ps f ++ nut ps a
178 else [(n, map argNames args)] ++ concatMap (nut ps) args
179 | (P (TCon _ _) n _, _) <- unApply fn = []
180 | otherwise = nut ps f ++ nut ps a
181 nut ps (Bind n (Let t v) sc) = nut ps v ++ nut (n:ps) sc
182 nut ps (Proj t _) = nut ps t
183 nut ps (Bind n b sc) = nut (n:ps) sc
186 argNames tm = let ns = directUse tm in
187 filter (\x -> x `elem` ns) topargs
189-- Find names which are used directly (i.e. not in a function call) in a term
191directUse :: TT Name -> [Name]
192directUse (P _ n _) = [n]
193directUse (Bind n (Let t v) sc) = nub $ directUse v ++ (directUse sc \\ [n])
195directUse (Bind n b sc) = nub $ directUse (binderTy b) ++ (directUse sc \\ [n])
196directUse fn@(App _ f a)
197 | (P Ref (UN pfk) _, [App _ e w]) <- unApply fn,
198 pfk == txt "prim_fork"
199 = directUse e ++ directUse w -- HACK so that fork works
200 | (P Ref (UN fce) _, [_, _, a]) <- unApply fn,
202 = directUse a -- forcing a value counts as a use
203 | (P Ref n _, args) <- unApply fn = [] -- need to know what n does with them
204 | (P (TCon _ _) n _, args) <- unApply fn = [] -- type constructors not used at runtime
205 | otherwise = nub $ directUse f ++ directUse a
206directUse (Proj x i) = nub $ directUse x
209-- Find all directly used arguments (i.e. used but not in function calls)
211findUsedArgs :: SC -> [Name] -> [Name]
212findUsedArgs sc topargs = nub (findAllUsedArgs sc topargs)
214findAllUsedArgs sc topargs = filter (\x -> x `elem` topargs) (nu' sc) where
215 nu' (Case _ n alts) = n : concatMap nua alts
216 nu' (ProjCase t alts) = directUse t ++ concatMap nua alts
217 nu' (STerm t) = directUse t
220 nua (ConCase n i args sc) = nu' sc
221 nua (FnCase n args sc) = nu' sc
222 nua (ConstCase _ sc) = nu' sc
223 nua (SucCase _ sc) = nu' sc
224 nua (DefaultCase sc) = nu' sc
226-- Return whether name is used anywhere in a case tree
227isUsed :: SC -> Name -> Bool
228isUsed sc n = used sc where
230 used (Case _ n' alts) = n == n' || any usedA alts
231 used (ProjCase t alts) = n `elem` freeNames t || any usedA alts
232 used (STerm t) = n `elem` freeNames t
235 usedA (ConCase _ _ args sc) = used sc
236 usedA (FnCase _ args sc) = used sc
237 usedA (ConstCase _ sc) = used sc
238 usedA (SucCase _ sc) = used sc
239 usedA (DefaultCase sc) = used sc
241type ErasureInfo = Name -> [Int] -- name to list of inaccessible arguments; empty list if name not found
242type CaseBuilder a = ReaderT ErasureInfo (State CS) a
244runCaseBuilder :: ErasureInfo -> CaseBuilder a -> (CS -> (a, CS))
245runCaseBuilder ei bld = runState $ runReaderT bld ei
247data Phase = CompileTime | RunTime
250-- Generate a simple case tree
253simpleCase :: Bool -> SC -> Bool ->
254 Phase -> FC -> [Int] ->
255 [(Type, Bool)] -> -- (Argument type, whether it's canonical)
256 [([Name], Term, Term)] ->
259simpleCase tc defcase reflect phase fc inacc argtys cs erInfo
260 = sc' tc defcase phase fc (filter (\(_, _, r) ->
265 sc' tc defcase phase fc []
266 = return $ CaseDef [] (UnmatchedCase (show fc ++ ":No pattern clauses")) []
267 sc' tc defcase phase fc cs
268 = let proj = phase == RunTime
269 vnames = fstT (head cs)
270 pats = map (\ (avs, l, r) ->
271 (avs, toPats reflect tc l, (l, r))) cs
272 chkPats = mapM chkAccessible pats in
275 let numargs = length (fst (head pats))
276 ns = take numargs args
277 (ns', ps') = order phase [(n, i `elem` inacc) | (i,n) <- zip [0..] ns] pats (map snd argtys)
278 (tree, st) = runCaseBuilder erInfo
279 (match ns' ps' defcase)
281 t = CaseDef ns (prune proj (depatt ns' tree)) (fstT st) in
282 if proj then return (stripLambdas t)
284 Error err -> Error (At fc err)
285 where args = map (\i -> sMN i "e") [0..]
286 defaultCase True = STerm Erased
287 defaultCase False = UnmatchedCase "Error"
291 -- Check that all pattern variables are reachable by a case split
292 -- Otherwise, they won't make sense on the RHS.
293 chkAccessible (avs, l, c)
294 | phase == RunTime || reflect = return (l, c)
295 | otherwise = do mapM_ (acc l) avs
298 acc [] n = Error (Inaccessible n)
299 acc (PV x t : xs) n | x == n = OK ()
300 acc (PCon _ _ _ ps : xs) n = acc (ps ++ xs) n
301 acc (PSuc p : xs) n = acc (p : xs) n
302 acc (_ : xs) n = acc xs n
304-- For each 'Case', make sure every choice is in the same type family,
305-- as directed by the variable type (i.e. there is no implicit type casing
308checkSameTypes :: [(Name, Type)] -> SC -> Bool
309checkSameTypes tys (Case _ n alts)
310 = case lookup n tys of
311 Just t -> and (map (checkAlts t) alts)
312 _ -> and (map ((checkSameTypes tys).getSC) alts)
314 checkAlts t (ConCase n _ _ sc) = isType n t && checkSameTypes tys sc
315 checkAlts (Constant t) (ConstCase c sc) = isConstType c t && checkSameTypes tys sc
316 checkAlts _ (ConstCase c sc) = False
319 getSC (ConCase _ _ _ sc) = sc
320 getSC (FnCase _ _ sc) = sc
321 getSC (ConstCase _ sc) = sc
322 getSC (SucCase _ sc) = sc
323 getSC (DefaultCase sc) = sc
324checkSameTypes _ _ = True
326-- FIXME: All we're actually doing here is checking that we haven't arrived
327-- at a specific constructor for a polymorphic argument. I *think* this
328-- is sufficient, but if it turns out not to be, fix it!
330-- Issue #1718 on the issue tracker: https://github.com/idris-lang/Idris-dev/issues/1718
331isType n t | (P (TCon _ _) _ _, _) <- unApply t = True
332isType n t | (P Ref _ _, _) <- unApply t = True
335isConstType (I _) (AType (ATInt ITNative)) = True
336isConstType (BI _) (AType (ATInt ITBig)) = True
337isConstType (Fl _) (AType ATFloat) = True
338isConstType (Ch _) (AType (ATInt ITChar)) = True
339isConstType (Str _) StrType = True
340isConstType (B8 _) (AType (ATInt _)) = True
341isConstType (B16 _) (AType (ATInt _)) = True
342isConstType (B32 _) (AType (ATInt _)) = True
343isConstType (B64 _) (AType (ATInt _)) = True
344isConstType _ _ = False
346data Pat = PCon Bool Name Int [Pat]
349 | PSuc Pat -- special case for n+1 on Integer
350 | PReflected Name [Pat]
352 | PTyPat -- typecase, not allowed, inspect last
355-- If there are repeated variables, take the *last* one (could be name shadowing
356-- in a where clause, so take the most recent).
358toPats :: Bool -> Bool -> Term -> [Pat]
359toPats reflect tc f = reverse (toPat reflect tc (getArgs f)) where
360 getArgs (App _ f a) = a : getArgs f
363toPat :: Bool -> Bool -> [Term] -> [Pat]
364toPat reflect tc = map $ toPat' []
366 toPat' [_,_,arg] (P (DCon t a uniq) nm@(UN n) _)
368 = PCon uniq nm t [PAny, PAny, toPat' [] arg]
370 toPat' args (P (DCon t a uniq) nm@(NS (UN n) [own]) _)
371 | n == txt "Read" && own == txt "Ownership"
372 = PCon False nm t (map shareCons (map (toPat' []) args))
373 where shareCons (PCon _ n i ps) = PCon False n i (map shareCons ps)
376 toPat' args (P (DCon t a uniq) n _)
377 = PCon uniq n t $ map (toPat' []) args
380 toPat' [p, Constant (BI 1)] (P _ (UN pabi) _)
381 | pabi == txt "prim__addBigInt"
384 toPat' [] (P Bound n ty) = PV n ty
385 toPat' args (App _ f a) = toPat' (a : args) f
386 toPat' [] (Constant x) | isTypeConst x = PTyPat
387 | otherwise = PConst x
389 toPat' [] (Bind n (Pi _ t _) sc)
390 | reflect && noOccurrence n sc
391 = PReflected (sUN "->") [toPat' [] t, toPat' [] sc]
393 toPat' args (P _ n _)
395 = PReflected n $ map (toPat' []) args
400 fixedN IT16 = "Bits16"
401 fixedN IT32 = "Bits32"
402 fixedN IT64 = "Bits64"
405data Partition = Cons [Clause]
409isVarPat (PV _ _ : ps , _) = True
410isVarPat (PAny : ps , _) = True
411isVarPat (PTyPat : ps , _) = True
414isConPat (PCon _ _ _ _ : ps, _) = True
415isConPat (PReflected _ _ : ps, _) = True
416isConPat (PSuc _ : ps, _) = True
417isConPat (PConst _ : ps, _) = True
420partition :: [Clause] -> [Partition]
423 | isVarPat m = let (vars, rest) = span isVarPat ms in
424 Vars vars : partition rest
425 | isConPat m = let (cons, rest) = span isConPat ms in
426 Cons cons : partition rest
427partition xs = error $ "Partition " ++ show xs
429-- reorder the patterns so that the one with most distinct names
430-- comes next. Take rightmost first, otherwise (i.e. pick value rather
433-- The first argument means [(Name, IsInaccessible)].
435order :: Phase -> [(Name, Bool)] -> [Clause] -> [Bool] -> ([Name], [Clause])
436-- do nothing at compile time: FIXME (EB): Put this in after checking
437-- implications for Franck's reflection work... see issue 3233
438-- order CompileTime ns cs _ = (map fst ns, cs)
439order _ [] cs cans = ([], cs)
440order _ ns' [] cans = (map fst ns', [])
441order phase ns' cs cans
442 = let patnames = transpose (map (zip ns') (map (zip cans) (map fst cs)))
443 -- only sort the arguments where there is no clash in
444 -- constructor tags between families, the argument type is canonical,
445 -- and no constructor/constant
446 -- clash, because otherwise we can't reliable make the
447 -- case distinction on evaluation
448 (patnames_ord, patnames_rest)
449 = Data.List.partition (noClash . map snd) patnames
450 patnames_ord' = case phase of
451 CompileTime -> patnames_ord
452 -- reversing tends to make better case trees
454 RunTime -> reverse patnames_ord
455 pats' = transpose (sortBy moreDistinct patnames_ord'
457 (getNOrder pats', zipWith rebuild pats' cs)
459 getNOrder [] = error $ "Failed order on " ++ show (map fst ns', cs)
460 getNOrder (c : _) = map (fst . fst) c
462 rebuild patnames clause = (map (snd . snd) patnames, snd clause)
465 noClash ((can, p) : ps) = can && not (any (clashPat p) (map snd ps))
468 clashPat (PCon _ _ _ _) (PConst _) = True
469 clashPat (PConst _) (PCon _ _ _ _) = True
470 clashPat (PCon _ _ _ _) (PSuc _) = True
471 clashPat (PSuc _) (PCon _ _ _ _) = True
472 clashPat (PCon _ n i _) (PCon _ n' i' _) | i == i' = n /= n'
475 -- this compares (+isInaccessible, -numberOfCases)
477 = compare (snd . fst . head $ xs, numNames [] (map snd ys))
478 (snd . fst . head $ ys, numNames [] (map snd xs))
480 numNames xs ((_, PCon _ n _ _) : ps)
481 | not (Left n `elem` xs) = numNames (Left n : xs) ps
482 numNames xs ((_, PConst c) : ps)
483 | not (Right c `elem` xs) = numNames (Right c : xs) ps
484 numNames xs (_ : ps) = numNames xs ps
485 numNames xs [] = length xs
487match :: [Name] -> [Clause] -> SC -- error case
489match [] (([], ret) : xs) err
490 = do (ts, v, ntys) <- get
491 put (ts ++ (map (fst.snd) xs), v, ntys)
493 Impossible -> return ImpossibleCase
494 tm -> return $ STerm tm -- run out of arguments
495match vs cs err = do let ps = partition cs
498mixture :: [Name] -> [Partition] -> SC -> CaseBuilder SC
499mixture vs [] err = return err
500mixture vs (Cons ms : ps) err = do fallthrough <- mixture vs ps err
501 conRule vs ms fallthrough
502mixture vs (Vars ms : ps) err = do fallthrough <- mixture vs ps err
503 varRule vs ms fallthrough
505-- Return the list of inaccessible arguments of a data constructor.
506inaccessibleArgs :: Name -> CaseBuilder [Int]
507inaccessibleArgs n = do
508 getInaccessiblePositions <- ask -- this function is the only thing in the environment
509 return $ getInaccessiblePositions n
511data ConType = CName Name Int -- named constructor
512 | CFn Name -- reflected function name
514 | CConst Const -- constant, not implemented yet
517data Group = ConGroup Bool -- Uniqueness flag
518 ConType -- Constructor
519 [([Pat], Clause)] -- arguments and rest of alternative
522conRule :: [Name] -> [Clause] -> SC -> CaseBuilder SC
523conRule (v:vs) cs err = do groups <- groupCons cs
524 caseGroups (v:vs) groups err
526caseGroups :: [Name] -> [Group] -> SC -> CaseBuilder SC
527caseGroups (v:vs) gs err = do g <- altGroups gs
528 return $ Case (getShared gs) v (sort g)
530 getShared (ConGroup True _ _ : _) = Updatable
533 altGroups [] = return [DefaultCase err]
535 altGroups (ConGroup _ (CName n i) args : cs)
536 = (:) <$> altGroup n i args <*> altGroups cs
538 altGroups (ConGroup _ (CFn n) args : cs)
539 = (:) <$> altFnGroup n args <*> altGroups cs
541 altGroups (ConGroup _ CSuc args : cs)
542 = (:) <$> altSucGroup args <*> altGroups cs
544 altGroups (ConGroup _ (CConst c) args : cs)
545 = (:) <$> altConstGroup c args <*> altGroups cs
548 = do inacc <- inaccessibleArgs n
549 (newVars, accVars, inaccVars, nextCs) <- argsToAlt inacc args
550 matchCs <- match (accVars ++ vs ++ inaccVars) nextCs err
551 return $ ConCase n i newVars matchCs
553 altFnGroup n args = do (newVars, _, [], nextCs) <- argsToAlt [] args
554 matchCs <- match (newVars ++ vs) nextCs err
555 return $ FnCase n newVars matchCs
557 altSucGroup args = do ([newVar], _, [], nextCs) <- argsToAlt [] args
558 matchCs <- match (newVar:vs) nextCs err
559 return $ SucCase newVar matchCs
561 altConstGroup n args = do (_, _, [], nextCs) <- argsToAlt [] args
562 matchCs <- match vs nextCs err
563 return $ ConstCase n matchCs
566-- * names of all variables arising from match
567-- * names of accessible variables (subset of all variables)
568-- * names of inaccessible variables (subset of all variables)
569-- * clauses corresponding to (accVars ++ origVars ++ inaccVars)
570argsToAlt :: [Int] -> [([Pat], Clause)] -> CaseBuilder ([Name], [Name], [Name], [Clause])
571argsToAlt _ [] = return ([], [], [], [])
572argsToAlt inacc rs@((r, m) : rest) = do
573 newVars <- getNewVars r
574 let (accVars, inaccVars) = partitionAcc newVars
575 return (newVars, accVars, inaccVars, addRs rs)
577 -- Create names for new variables arising from the given patterns.
578 getNewVars :: [Pat] -> CaseBuilder [Name]
579 getNewVars [] = return []
580 getNewVars ((PV n t) : ns) = do v <- getVar "e"
583 -- Record the type of the variable.
585 -- It seems that the ordering is not important
586 -- and we can put (v,t) always in front of "ntys"
587 -- (the varName-type pairs seem to represent a mapping).
589 -- The code that reads this is currently
590 -- commented out, anyway.
592 put (cs, i, (v, t) : ntys)
596 getNewVars (PAny : ns) = (:) <$> getVar "i" <*> getNewVars ns
597 getNewVars (PTyPat : ns) = (:) <$> getVar "t" <*> getNewVars ns
598 getNewVars (_ : ns) = (:) <$> getVar "e" <*> getNewVars ns
600 -- Partition a list of things into (accessible, inaccessible) things,
601 -- according to the list of inaccessible indices.
603 ( [x | (i,x) <- zip [0..] xs, i `notElem` inacc]
604 , [x | (i,x) <- zip [0..] xs, i `elem` inacc]
608 addRs ((r, (ps, res)) : rs) = ((acc++ps++inacc, res) : addRs rs)
610 (acc, inacc) = partitionAcc r
612 uniq i (UN n) = MN i n
615getVar :: String -> CaseBuilder Name
616getVar b = do (t, v, ntys) <- get; put (t, v+1, ntys); return (sMN v b)
618groupCons :: [Clause] -> CaseBuilder [Group]
619groupCons cs = gc [] cs
621 gc acc [] = return acc
622 gc acc ((p : ps, res) : cs) =
623 do acc' <- addGroup p ps res acc
625 addGroup p ps res acc = case p of
626 PCon uniq con i args -> return $ addg uniq (CName con i) args (ps, res) acc
627 PConst cval -> return $ addConG cval (ps, res) acc
628 PSuc n -> return $ addg False CSuc [n] (ps, res) acc
629 PReflected fn args -> return $ addg False (CFn fn) args (ps, res) acc
630 pat -> fail $ show pat ++ " is not a constructor or constant (can't happen)"
632 addg uniq c conargs res []
633 = [ConGroup uniq c [(conargs, res)]]
634 addg uniq c conargs res (g@(ConGroup _ c' cs):gs)
635 | c == c' = ConGroup uniq c (cs ++ [(conargs, res)]) : gs
636 | otherwise = g : addg uniq c conargs res gs
638 addConG con res [] = [ConGroup False (CConst con) [([], res)]]
639 addConG con res (g@(ConGroup False (CConst n) cs) : gs)
640 | con == n = ConGroup False (CConst n) (cs ++ [([], res)]) : gs
641-- | otherwise = g : addConG con res gs
642 addConG con res (g : gs) = g : addConG con res gs
644varRule :: [Name] -> [Clause] -> SC -> CaseBuilder SC
645varRule (v : vs) alts err =
646 do alts' <- mapM (repVar v) alts
649 repVar v (PV p ty : ps , (lhs, res))
650 = do (cs, i, ntys) <- get
651 put (cs, i, (v, ty) : ntys)
652 return (ps, (lhs, subst p (P Bound v ty) res))
653 repVar v (PAny : ps , res) = return (ps, res)
654 repVar v (PTyPat : ps , res) = return (ps, res)
656-- fix: case e of S k -> f (S k) ==> case e of S k -> f e
658depatt :: [Name] -> SC -> SC
659depatt ns tm = dp [] tm
661 dp ms (STerm tm) = STerm (applyMaps ms tm)
662 dp ms (Case up x alts) = Case up x (map (dpa ms x) alts)
665 dpa ms x (ConCase n i args sc)
666 = ConCase n i args (dp ((x, (n, args)) : ms) sc)
667 dpa ms x (FnCase n args sc)
668 = FnCase n args (dp ((x, (n, args)) : ms) sc)
669 dpa ms x (ConstCase c sc) = ConstCase c (dp ms sc)
670 dpa ms x (SucCase n sc) = SucCase n (dp ms sc)
671 dpa ms x (DefaultCase sc) = DefaultCase (dp ms sc)
673 applyMaps ms f@(App _ _ _)
674 | (P nt cn pty, args) <- unApply f
675 = let args' = map (applyMaps ms) args in
676 applyMap ms nt cn pty args'
678 applyMap [] nt cn pty args' = mkApp (P nt cn pty) args'
679 applyMap ((x, (n, args)) : ms) nt cn pty args'
680 | and ((length args == length args') :
681 (n == cn) : zipWith same args args') = P Ref x Erased
682 | otherwise = applyMap ms nt cn pty args'
683 same n (P _ n' _) = n == n'
686 applyMaps ms (App s f a) = App s (applyMaps ms f) (applyMaps ms a)
689-- FIXME: Do this for SucCase too
690-- Issue #1719 on the issue tracker: https://github.com/idris-lang/Idris-dev/issues/1719
691prune :: Bool -- ^ Convert single branches to projections (only useful at runtime)
693prune proj (Case up n alts) = case alts' of
696 -- Projection transformations prevent us from seeing some uses of ctor fields
697 -- because they delete information about which ctor is being used.
699 -- f (X x) = ... x ...
703 -- Hence, we disable this step.
704 -- TODO: re-enable this in toIR
706 -- as@[ConCase cn i args sc]
707 -- | proj -> mkProj n 0 args (prune proj sc)
708 -- mkProj n i xs sc = foldr (\x -> projRep x n i) sc xs
710 -- If none of the args are used in the sc, however, we can just replace it
712 as@[ConCase cn i args sc]
713 | proj -> let sc' = prune proj sc in
714 if any (isUsed sc') args
715 then Case up n [ConCase cn i args sc']
720 -> projRep cn n (-1) $ prune proj sc
725 -- Bit of a hack here! The default case will always be 0, make sure
726 -- it gets caught first.
727 [s@(SucCase _ _), DefaultCase dc]
728 -> Case up n [ConstCase (BI 0) dc, s]
732 alts' = filter (not . erased) $ map pruneAlt alts
734 pruneAlt (ConCase cn i ns sc) = ConCase cn i ns (prune proj sc)
735 pruneAlt (FnCase cn ns sc) = FnCase cn ns (prune proj sc)
736 pruneAlt (ConstCase c sc) = ConstCase c (prune proj sc)
737 pruneAlt (SucCase n sc) = SucCase n (prune proj sc)
738 pruneAlt (DefaultCase sc) = DefaultCase (prune proj sc)
740 erased (DefaultCase (STerm Erased)) = True
741 erased (DefaultCase ImpossibleCase) = True
744 projRep :: Name -> Name -> Int -> SC -> SC
745 projRep arg n i (Case up x alts) | x == arg
746 = ProjCase (Proj (P Bound n Erased) i) $ map (projRepAlt arg n i) alts
747 projRep arg n i (Case up x alts)
748 = Case up x (map (projRepAlt arg n i) alts)
749 projRep arg n i (ProjCase t alts)
750 = ProjCase (projRepTm arg n i t) $ map (projRepAlt arg n i) alts
751 projRep arg n i (STerm t) = STerm (projRepTm arg n i t)
752 projRep arg n i c = c
754 projRepAlt arg n i (ConCase cn t args rhs)
755 = ConCase cn t args (projRep arg n i rhs)
756 projRepAlt arg n i (FnCase cn args rhs)
757 = FnCase cn args (projRep arg n i rhs)
758 projRepAlt arg n i (ConstCase t rhs)
759 = ConstCase t (projRep arg n i rhs)
760 projRepAlt arg n i (SucCase sn rhs)
761 = SucCase sn (projRep arg n i rhs)
762 projRepAlt arg n i (DefaultCase rhs)
763 = DefaultCase (projRep arg n i rhs)
765 projRepTm arg n i t = subst arg (Proj (P Bound n Erased) i) t
769stripLambdas :: CaseDef -> CaseDef
770stripLambdas (CaseDef ns (STerm (Bind x (Lam _) sc)) tm)
771 = stripLambdas (CaseDef (ns ++ [x]) (STerm (instantiate (P Bound x Erased) sc)) tm)
774substSC :: Name -> Name -> SC -> SC
775substSC n repl (Case up n' alts)
776 | n == n' = Case up repl (map (substAlt n repl) alts)
777 | otherwise = Case up n' (map (substAlt n repl) alts)
778substSC n repl (STerm t) = STerm $ subst n (P Bound repl Erased) t
779substSC n repl (UnmatchedCase errmsg) = UnmatchedCase errmsg
780substSC n repl ImpossibleCase = ImpossibleCase
781substSC n repl sc = error $ "unsupported in substSC: " ++ show sc
783substAlt :: Name -> Name -> CaseAlt -> CaseAlt
784substAlt n repl (ConCase cn a ns sc) = ConCase cn a ns (substSC n repl sc)
785substAlt n repl (FnCase fn ns sc) = FnCase fn ns (substSC n repl sc)
786substAlt n repl (ConstCase c sc) = ConstCase c (substSC n repl sc)
787substAlt n repl (SucCase n' sc)
788 | n == n' = SucCase n (substSC n repl sc)
789 | otherwise = SucCase n' (substSC n repl sc)
790substAlt n repl (DefaultCase sc) = DefaultCase (substSC n repl sc)
792-- mkForce n' n t updates the tree t under the assumption that
793-- n' = force n (so basically updating n to n')
794mkForce :: Name -> Name -> SC -> SC
797 mkForceSC n arg (Case up x alts) | x == arg
798 = Case up n $ map (mkForceAlt n arg) alts
800 mkForceSC n arg (Case up x alts)
801 = Case up x (map (mkForceAlt n arg) alts)
803 mkForceSC n arg (ProjCase t alts)
804 = ProjCase t $ map (mkForceAlt n arg) alts
806 mkForceSC n arg c = c
808 mkForceAlt n arg (ConCase cn t args rhs)
809 = ConCase cn t args (mkForceSC n arg rhs)
810 mkForceAlt n arg (FnCase cn args rhs)
811 = FnCase cn args (mkForceSC n arg rhs)
812 mkForceAlt n arg (ConstCase t rhs)
813 = ConstCase t (mkForceSC n arg rhs)
814 mkForceAlt n arg (SucCase sn rhs)
815 = SucCase sn (mkForceSC n arg rhs)
816 mkForceAlt n arg (DefaultCase rhs)
817 = DefaultCase (mkForceSC n arg rhs)
819 forceTm n arg t = subst n arg t
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