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 DeriveFunctor, DeriveGeneric, PatternGuards, 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.Reader
35import Control.Monad.State
36import Data.List hiding (partition)
37import qualified Data.List (partition)
39import qualified Data.Set as S
41import GHC.Generics (Generic)
43data CaseDef = CaseDef [Name] !SC [Term]
46data SC' t = Case CaseType Name [CaseAlt' t] -- ^ invariant: lowest tags first
47 | ProjCase t [CaseAlt' t] -- ^ special case for projections/thunk-forcing before inspection
49 | UnmatchedCase String -- ^ error message
50 | ImpossibleCase -- ^ already checked to be impossible
51 deriving (Eq, Ord, Functor, Generic)
53deriving instance Binary 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'
71type CaseAlt = CaseAlt' Term
73instance Show t => Show (SC' t) where
76 show' i (Case up n alts) = "case" ++ u ++ show n ++ " of\n" ++ indent i ++
77 showSep ("\n" ++ indent i) (map (showA i) alts)
81 show' i (ProjCase tm alts) = "case " ++ show tm ++ " of " ++
82 showSep ("\n" ++ indent i) (map (showA i) alts)
83 show' i (STerm tm) = show tm
84 show' i (UnmatchedCase str) = "error " ++ show str
85 show' i ImpossibleCase = "impossible"
87 indent i = concat $ take i (repeat " ")
89 showA i (ConCase n t args sc)
90 = show n ++ "(" ++ showSep (", ") (map show args) ++ ") => "
92 showA i (FnCase n args sc)
93 = "FN " ++ show n ++ "(" ++ showSep (", ") (map show args) ++ ") => "
95 showA i (ConstCase t sc)
96 = show t ++ " => " ++ show' (i+1) sc
97 showA i (SucCase n sc)
98 = show n ++ "+1 => " ++ show' (i+1) sc
99 showA i (DefaultCase sc)
100 = "_ => " ++ show' (i+1) sc
104type Clause = ([Pat], (Term, Term))
105type CS = ([Term], Int, [(Name, Type)])
107instance TermSize SC where
108 termsize n (Case _ n' as) = termsize n as
109 termsize n (ProjCase n' as) = termsize n as
110 termsize n (STerm t) = termsize n t
113instance TermSize CaseAlt where
114 termsize n (ConCase _ _ _ s) = termsize n s
115 termsize n (FnCase _ _ s) = termsize n s
116 termsize n (ConstCase _ s) = termsize n s
117 termsize n (SucCase _ s) = termsize n s
118 termsize n (DefaultCase s) = termsize n s
120-- simple terms can be inlined trivially - good for primitives in particular
121-- To avoid duplicating work, don't inline something which uses one
122-- of its arguments in more than one place
124small :: Name -> [Name] -> SC -> Bool
125small n args t = let as = findAllUsedArgs t args in
126 length as == length (nub as) &&
129namesUsed :: SC -> [Name]
130namesUsed sc = nub $ nu' [] sc where
131 nu' ps (Case _ n alts) = nub (concatMap (nua ps) alts) \\ [n]
132 nu' ps (ProjCase t alts) = nub $ nut ps t ++ concatMap (nua ps) alts
133 nu' ps (STerm t) = nub $ nut ps t
136 nua ps (ConCase n i args sc) = nub (nu' (ps ++ args) sc) \\ args
137 nua ps (FnCase n args sc) = nub (nu' (ps ++ args) sc) \\ args
138 nua ps (ConstCase _ sc) = nu' ps sc
139 nua ps (SucCase _ sc) = nu' ps sc
140 nua ps (DefaultCase sc) = nu' ps sc
142 nut ps (P _ n _) | n `elem` ps = []
144 nut ps (App _ f a) = nut ps f ++ nut ps a
145 nut ps (Proj t _) = nut ps t
146 nut ps (Bind n (Let t v) sc) = nut ps v ++ nut (n:ps) sc
147 nut ps (Bind n b sc) = nut (n:ps) sc
150-- | Return all called functions, and which arguments are used
151-- in each argument position for the call, in order to help reduce
152-- compilation time, and trace all unused arguments
153findCalls :: SC -> [Name] -> [(Name, [[Name]])]
154findCalls = findCalls' False
156findCalls' :: Bool -> SC -> [Name] -> [(Name, [[Name]])]
157findCalls' ignoreasserts sc topargs = S.toList $ nu' topargs sc where
158 nu' ps (Case _ n alts) = S.unions $ map (nua (n : ps)) alts
159 nu' ps (ProjCase t alts) = S.unions $ nut ps t : map (nua ps) alts
160 nu' ps (STerm t) = nut ps t
163 nua ps (ConCase n i args sc) = nu' (ps ++ args) sc
164 nua ps (FnCase n args sc) = nu' (ps ++ args) sc
165 nua ps (ConstCase _ sc) = nu' ps sc
166 nua ps (SucCase _ sc) = nu' ps sc
167 nua ps (DefaultCase sc) = nu' ps sc
169 nut ps (P _ n _) | n `elem` ps = S.empty
170 | otherwise = S.singleton (n, [])
171 nut ps fn@(App _ f a)
172 | (P _ n _, args) <- unApply fn
173 = if ignoreasserts && n == sUN "assert_total"
176 then S.union (nut ps f) (nut ps a)
177 else S.insert (n, map argNames args)
178 (S.unions $ map (nut ps) args)
179 | (P (TCon _ _) n _, _) <- unApply fn = S.empty
180 | otherwise = S.union (nut ps f) (nut ps a)
181 nut ps (Bind n (Let t v) sc) = S.union (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 = CoverageCheck [Int] -- list of positions explicitly given
252-- Generate a simple case tree
255simpleCase :: Bool -> SC -> Bool ->
257 -- Following two can be empty lists when Phase = CoverageCheck
258 [Int] -> -- Inaccessible argument positions
259 [(Type, Bool)] -> -- (Argument type, whether it's canonical)
260 [([Name], Term, Term)] ->
263simpleCase tc defcase reflect phase fc inacc argtys cs erInfo
264 = sc' tc defcase phase fc (filter (\(_, _, r) ->
269 sc' tc defcase phase fc []
270 = return $ CaseDef [] (UnmatchedCase (show fc ++ ":No pattern clauses")) []
271 sc' tc defcase phase fc cs
272 = let proj = phase == RunTime
273 vnames = fstT (head cs)
274 pats = map (\ (avs, l, r) ->
275 (avs, toPats reflect tc l, (l, r))) cs
276 chkPats = mapM chkAccessible pats in
279 let numargs = length (fst (head pats))
280 ns = take numargs args
281 (ns', ps') = order phase [(n, i `elem` inacc) | (i,n) <- zip [0..] ns] pats (map snd argtys)
282 (tree, st) = runCaseBuilder erInfo
283 (match ns' ps' defcase)
285 t = CaseDef ns (prune proj (depatt ns' tree)) (fstT st) in
286 if proj then return (stripLambdas t)
288 Error err -> Error (At fc err)
289 where args = map (\i -> sMN i "e") [0..]
290 defaultCase True = STerm Erased
291 defaultCase False = UnmatchedCase "Error"
295 -- Check that all pattern variables are reachable by a case split
296 -- Otherwise, they won't make sense on the RHS.
297 chkAccessible (avs, l, c)
298 | phase /= CompileTime || reflect = return (l, c)
299 | otherwise = do mapM_ (acc l) avs
302 acc [] n = Error (Inaccessible n)
303 acc (PV x t : xs) n | x == n = OK ()
304 acc (PCon _ _ _ ps : xs) n = acc (ps ++ xs) n
305 acc (PSuc p : xs) n = acc (p : xs) n
306 acc (_ : xs) n = acc xs n
308-- For each 'Case', make sure every choice is in the same type family,
309-- as directed by the variable type (i.e. there is no implicit type casing
312checkSameTypes :: [(Name, Type)] -> SC -> Bool
313checkSameTypes tys (Case _ n alts)
314 = case lookup n tys of
315 Just t -> and (map (checkAlts t) alts)
316 _ -> and (map ((checkSameTypes tys).getSC) alts)
318 checkAlts t (ConCase n _ _ sc) = isType n t && checkSameTypes tys sc
319 checkAlts (Constant t) (ConstCase c sc) = isConstType c t && checkSameTypes tys sc
320 checkAlts _ (ConstCase c sc) = False
323 getSC (ConCase _ _ _ sc) = sc
324 getSC (FnCase _ _ sc) = sc
325 getSC (ConstCase _ sc) = sc
326 getSC (SucCase _ sc) = sc
327 getSC (DefaultCase sc) = sc
328checkSameTypes _ _ = True
330-- FIXME: All we're actually doing here is checking that we haven't arrived
331-- at a specific constructor for a polymorphic argument. I *think* this
332-- is sufficient, but if it turns out not to be, fix it!
334-- Issue #1718 on the issue tracker: https://github.com/idris-lang/Idris-dev/issues/1718
335isType n t | (P (TCon _ _) _ _, _) <- unApply t = True
336isType n t | (P Ref _ _, _) <- unApply t = True
339isConstType (I _) (AType (ATInt ITNative)) = True
340isConstType (BI _) (AType (ATInt ITBig)) = True
341isConstType (Fl _) (AType ATFloat) = True
342isConstType (Ch _) (AType (ATInt ITChar)) = True
343isConstType (Str _) StrType = True
344isConstType (B8 _) (AType (ATInt _)) = True
345isConstType (B16 _) (AType (ATInt _)) = True
346isConstType (B32 _) (AType (ATInt _)) = True
347isConstType (B64 _) (AType (ATInt _)) = True
348isConstType _ _ = False
350data Pat = PCon Bool Name Int [Pat]
354 | PSuc Pat -- special case for n+1 on Integer
355 | PReflected Name [Pat]
357 | PTyPat -- typecase, not allowed, inspect last
360-- If there are repeated variables, take the *last* one (could be name shadowing
361-- in a where clause, so take the most recent).
363toPats :: Bool -> Bool -> Term -> [Pat]
364toPats reflect tc f = reverse (toPat reflect tc (getArgs f)) where
365 getArgs (App _ f a) = a : getArgs f
368toPat :: Bool -> Bool -> [Term] -> [Pat]
369toPat reflect tc = map $ toPat' []
371 toPat' [_,_,arg] (P (DCon t a uniq) nm@(UN n) _)
373 = PCon uniq nm t [PAny, PAny, toPat' [] arg]
375 toPat' args (P (DCon t a uniq) nm@(NS (UN n) [own]) _)
376 | n == txt "Read" && own == txt "Ownership"
377 = PCon False nm t (map shareCons (map (toPat' []) args))
378 where shareCons (PCon _ n i ps) = PCon False n i (map shareCons ps)
381 toPat' args (P (DCon t a uniq) n _)
382 = PCon uniq n t $ map (toPat' []) args
385 toPat' [p, Constant (BI 1)] (P _ (UN pabi) _)
386 | pabi == txt "prim__addBigInt"
389 toPat' [] (P Bound n ty) = PV n ty
390 toPat' args (App _ f a) = toPat' (a : args) f
391 toPat' args (Inferred tm) = PInferred (toPat' args tm)
392 toPat' [] (Constant x) | isTypeConst x = PTyPat
393 | otherwise = PConst x
395 toPat' [] (Bind n (Pi _ _ t _) sc)
396 | reflect && noOccurrence n sc
397 = PReflected (sUN "->") [toPat' [] t, toPat' [] sc]
399 toPat' args (P _ n _)
401 = PReflected n $ map (toPat' []) args
406 fixedN IT16 = "Bits16"
407 fixedN IT32 = "Bits32"
408 fixedN IT64 = "Bits64"
411data Partition = Cons [Clause]
415isVarPat (PV _ _ : ps , _) = True
416isVarPat (PAny : ps , _) = True
417isVarPat (PTyPat : ps , _) = True
420isConPat (PCon _ _ _ _ : ps, _) = True
421isConPat (PReflected _ _ : ps, _) = True
422isConPat (PSuc _ : ps, _) = True
423isConPat (PConst _ : ps, _) = True
426partition :: [Clause] -> [Partition]
429 | isVarPat m = let (vars, rest) = span isVarPat ms in
430 Vars vars : partition rest
431 | isConPat m = let (cons, rest) = span isConPat ms in
432 Cons cons : partition rest
433partition xs = error $ "Partition " ++ show xs
435-- reorder the patterns so that the one with most distinct names
436-- comes next. Take rightmost first, otherwise (i.e. pick value rather
439-- The first argument means [(Name, IsInaccessible)].
441order :: Phase -> [(Name, Bool)] -> [Clause] -> [Bool] -> ([Name], [Clause])
442-- do nothing at compile time: FIXME (EB): Put this in after checking
443-- implications for Franck's reflection work... see issue 3233
444-- order CompileTime ns cs _ = (map fst ns, cs)
445order _ [] cs cans = ([], cs)
446order _ ns' [] cans = (map fst ns', [])
447order (CoverageCheck pos) ns' cs cans
448 = let ns_out = pick 0 [] (map fst ns')
449 cs_out = map pickClause cs in
452 pickClause (pats, def) = (pick 0 [] pats, def)
454 -- Order the list so that things in a position in 'pos' are in the first
455 -- part, then all the other things later. Otherwise preserve order.
456 pick i skipped [] = reverse skipped
457 pick i skipped (x : xs)
458 | i `elem` pos = x : pick (i + 1) skipped xs
459 | otherwise = pick (i + 1) (x : skipped) xs
461order phase ns' cs cans
462 = let patnames = transpose (map (zip ns') (map (zip cans) (map fst cs)))
463 -- only sort the arguments where there is no clash in
464 -- constructor tags between families, the argument type is canonical,
465 -- and no constructor/constant
466 -- clash, because otherwise we can't reliable make the
467 -- case distinction on evaluation
468 (patnames_ord, patnames_rest)
469 = Data.List.partition (noClash . map snd) patnames
470 patnames_ord' = case phase of
471 CompileTime -> patnames_ord
472 -- reversing tends to make better case trees
474 RunTime -> reverse patnames_ord
475 pats' = transpose (sortBy moreDistinct patnames_ord'
477 (getNOrder pats', zipWith rebuild pats' cs)
479 getNOrder [] = error $ "Failed order on " ++ show (map fst ns', cs)
480 getNOrder (c : _) = map (fst . fst) c
482 rebuild patnames clause = (map (snd . snd) patnames, snd clause)
485 noClash ((can, p) : ps) = can && not (any (clashPat p) (map snd ps))
488 clashPat (PCon _ _ _ _) (PConst _) = True
489 clashPat (PConst _) (PCon _ _ _ _) = True
490 clashPat (PCon _ _ _ _) (PSuc _) = True
491 clashPat (PSuc _) (PCon _ _ _ _) = True
492 clashPat (PCon _ n i _) (PCon _ n' i' _) | i == i' = n /= n'
495 -- this compares (+isInaccessible, -numberOfCases)
497 = compare (snd . fst . head $ xs, numNames [] (map snd ys))
498 (snd . fst . head $ ys, numNames [] (map snd xs))
500 numNames xs ((_, PCon _ n _ _) : ps)
501 | not (Left n `elem` xs) = numNames (Left n : xs) ps
502 numNames xs ((_, PConst c) : ps)
503 | not (Right c `elem` xs) = numNames (Right c : xs) ps
504 numNames xs (_ : ps) = numNames xs ps
505 numNames xs [] = length xs
507-- Reorder the patterns in the clause so that the PInferred patterns come
508-- last. Also strip 'PInferred' from the top level patterns so that we can
509-- go ahead and match.
510orderByInf :: [Name] -> [Clause] -> ([Name], [Clause])
511orderByInf vs cs = let alwaysInf = getInf cs in
512 (selectInf alwaysInf vs,
513 map deInf (map (selectExp alwaysInf) cs))
516 getInf [(pats, def)] = infPos 0 pats
517 getInf ((pats, def) : cs) = infPos 0 pats `intersect` getInf cs
519 selectExp :: [Int] -> Clause -> Clause
520 selectExp infs (pats, def)
521 = let (notInf, inf) = splitPats 0 infs [] [] pats in
524 selectInf :: [Int] -> [a] -> [a]
525 selectInf infs ns = let (notInf, inf) = splitPats 0 infs [] [] ns in
528 splitPats i infpos notInf inf [] = (reverse notInf, reverse inf)
529 splitPats i infpos notInf inf (p : ps)
530 | i `elem` infpos = splitPats (i + 1) infpos notInf (p : inf) ps
531 | otherwise = splitPats (i + 1) infpos (p : notInf) inf ps
534 infPos i (PInferred p : ps) = i : infPos (i + 1) ps
535 infPos i (_ : ps) = infPos (i + 1) ps
537 deInf (pats, def) = (map deInfPat pats, def)
539 deInfPat (PInferred p) = p
542match :: [Name] -> [Clause] -> SC -- error case
544match [] (([], ret) : xs) err
545 = do (ts, v, ntys) <- get
546 put (ts ++ (map (fst.snd) xs), v, ntys)
548 Impossible -> return ImpossibleCase
549 tm -> return $ STerm tm -- run out of arguments
550match vs cs err = do let (vs', de_inf) = orderByInf vs cs
551 ps = partition de_inf
554mixture :: [Name] -> [Partition] -> SC -> CaseBuilder SC
555mixture vs [] err = return err
556mixture vs (Cons ms : ps) err = do fallthrough <- mixture vs ps err
557 conRule vs ms fallthrough
558mixture vs (Vars ms : ps) err = do fallthrough <- mixture vs ps err
559 varRule vs ms fallthrough
561-- Return the list of inaccessible arguments of a data constructor.
562inaccessibleArgs :: Name -> CaseBuilder [Int]
563inaccessibleArgs n = do
564 getInaccessiblePositions <- ask -- this function is the only thing in the environment
565 return $ getInaccessiblePositions n
567data ConType = CName Name Int -- named constructor
568 | CFn Name -- reflected function name
570 | CConst Const -- constant, not implemented yet
573data Group = ConGroup Bool -- Uniqueness flag
574 ConType -- Constructor
575 [([Pat], Clause)] -- arguments and rest of alternative
578conRule :: [Name] -> [Clause] -> SC -> CaseBuilder SC
579conRule (v:vs) cs err = do groups <- groupCons cs
580 caseGroups (v:vs) groups err
582caseGroups :: [Name] -> [Group] -> SC -> CaseBuilder SC
583caseGroups (v:vs) gs err = do g <- altGroups gs
584 return $ Case (getShared gs) v (sort g)
586 getShared (ConGroup True _ _ : _) = Updatable
589 altGroups [] = return [DefaultCase err]
591 altGroups (ConGroup _ (CName n i) args : cs)
592 = (:) <$> altGroup n i args <*> altGroups cs
594 altGroups (ConGroup _ (CFn n) args : cs)
595 = (:) <$> altFnGroup n args <*> altGroups cs
597 altGroups (ConGroup _ CSuc args : cs)
598 = (:) <$> altSucGroup args <*> altGroups cs
600 altGroups (ConGroup _ (CConst c) args : cs)
601 = (:) <$> altConstGroup c args <*> altGroups cs
604 = do inacc <- inaccessibleArgs n
605 (newVars, accVars, inaccVars, nextCs) <- argsToAlt inacc args
606 matchCs <- match (accVars ++ vs ++ inaccVars) nextCs err
607 return $ ConCase n i newVars matchCs
609 altFnGroup n args = do (newVars, _, [], nextCs) <- argsToAlt [] args
610 matchCs <- match (newVars ++ vs) nextCs err
611 return $ FnCase n newVars matchCs
613 altSucGroup args = do ([newVar], _, [], nextCs) <- argsToAlt [] args
614 matchCs <- match (newVar:vs) nextCs err
615 return $ SucCase newVar matchCs
617 altConstGroup n args = do (_, _, [], nextCs) <- argsToAlt [] args
618 matchCs <- match vs nextCs err
619 return $ ConstCase n matchCs
622-- * names of all variables arising from match
623-- * names of accessible variables (subset of all variables)
624-- * names of inaccessible variables (subset of all variables)
625-- * clauses corresponding to (accVars ++ origVars ++ inaccVars)
626argsToAlt :: [Int] -> [([Pat], Clause)] -> CaseBuilder ([Name], [Name], [Name], [Clause])
627argsToAlt _ [] = return ([], [], [], [])
628argsToAlt inacc rs@((r, m) : rest) = do
629 newVars <- getNewVars r
630 let (accVars, inaccVars) = partitionAcc newVars
631 return (newVars, accVars, inaccVars, addRs rs)
633 -- Create names for new variables arising from the given patterns.
634 getNewVars :: [Pat] -> CaseBuilder [Name]
635 getNewVars [] = return []
636 getNewVars ((PV n t) : ns) = do v <- getVar "e"
639 -- Record the type of the variable.
641 -- It seems that the ordering is not important
642 -- and we can put (v,t) always in front of "ntys"
643 -- (the varName-type pairs seem to represent a mapping).
645 -- The code that reads this is currently
646 -- commented out, anyway.
648 put (cs, i, (v, t) : ntys)
652 getNewVars (PAny : ns) = (:) <$> getVar "i" <*> getNewVars ns
653 getNewVars (PTyPat : ns) = (:) <$> getVar "t" <*> getNewVars ns
654 getNewVars (_ : ns) = (:) <$> getVar "e" <*> getNewVars ns
656 -- Partition a list of things into (accessible, inaccessible) things,
657 -- according to the list of inaccessible indices.
659 ( [x | (i,x) <- zip [0..] xs, i `notElem` inacc]
660 , [x | (i,x) <- zip [0..] xs, i `elem` inacc]
664 addRs ((r, (ps, res)) : rs) = ((acc++ps++inacc, res) : addRs rs)
666 (acc, inacc) = partitionAcc r
668 uniq i (UN n) = MN i n
671getVar :: String -> CaseBuilder Name
672getVar b = do (t, v, ntys) <- get; put (t, v+1, ntys); return (sMN v b)
674groupCons :: [Clause] -> CaseBuilder [Group]
675groupCons cs = gc [] cs
677 gc acc [] = return acc
678 gc acc ((p : ps, res) : cs) =
679 do acc' <- addGroup p ps res acc
681 addGroup p ps res acc = case p of
682 PCon uniq con i args -> return $ addg uniq (CName con i) args (ps, res) acc
683 PConst cval -> return $ addConG cval (ps, res) acc
684 PSuc n -> return $ addg False CSuc [n] (ps, res) acc
685 PReflected fn args -> return $ addg False (CFn fn) args (ps, res) acc
686 pat -> fail $ show pat ++ " is not a constructor or constant (can't happen)"
688 addg uniq c conargs res []
689 = [ConGroup uniq c [(conargs, res)]]
690 addg uniq c conargs res (g@(ConGroup _ c' cs):gs)
691 | c == c' = ConGroup uniq c (cs ++ [(conargs, res)]) : gs
692 | otherwise = g : addg uniq c conargs res gs
694 addConG con res [] = [ConGroup False (CConst con) [([], res)]]
695 addConG con res (g@(ConGroup False (CConst n) cs) : gs)
696 | con == n = ConGroup False (CConst n) (cs ++ [([], res)]) : gs
697-- | otherwise = g : addConG con res gs
698 addConG con res (g : gs) = g : addConG con res gs
700varRule :: [Name] -> [Clause] -> SC -> CaseBuilder SC
701varRule (v : vs) alts err =
702 do alts' <- mapM (repVar v) alts
705 repVar v (PV p ty : ps , (lhs, res))
706 = do (cs, i, ntys) <- get
707 put (cs, i, (v, ty) : ntys)
708 return (ps, (lhs, subst p (P Bound v ty) res))
709 repVar v (PAny : ps , res) = return (ps, res)
710 repVar v (PTyPat : ps , res) = return (ps, res)
712-- fix: case e of S k -> f (S k) ==> case e of S k -> f e
714depatt :: [Name] -> SC -> SC
715depatt ns tm = dp [] tm
717 dp ms (STerm tm) = STerm (applyMaps ms tm)
718 dp ms (Case up x alts) = Case up x (map (dpa ms x) alts)
721 dpa ms x (ConCase n i args sc)
722 = ConCase n i args (dp ((x, (n, args)) : ms) sc)
723 dpa ms x (FnCase n args sc)
724 = FnCase n args (dp ((x, (n, args)) : ms) sc)
725 dpa ms x (ConstCase c sc) = ConstCase c (dp ms sc)
726 dpa ms x (SucCase n sc) = SucCase n (dp ms sc)
727 dpa ms x (DefaultCase sc) = DefaultCase (dp ms sc)
729 applyMaps ms f@(App _ _ _)
730 | (P nt cn pty, args) <- unApply f
731 = let args' = map (applyMaps ms) args in
732 applyMap ms nt cn pty args'
734 applyMap [] nt cn pty args' = mkApp (P nt cn pty) args'
735 applyMap ((x, (n, args)) : ms) nt cn pty args'
736 | and ((length args == length args') :
737 (n == cn) : zipWith same args args') = P Ref x Erased
738 | otherwise = applyMap ms nt cn pty args'
739 same n (P _ n' _) = n == n'
742 applyMaps ms (App s f a) = App s (applyMaps ms f) (applyMaps ms a)
745-- FIXME: Do this for SucCase too
746-- Issue #1719 on the issue tracker: https://github.com/idris-lang/Idris-dev/issues/1719
747prune :: Bool -- ^ Convert single branches to projections (only useful at runtime)
749prune proj (Case up n alts) = case alts' of
752 -- Projection transformations prevent us from seeing some uses of ctor fields
753 -- because they delete information about which ctor is being used.
755 -- f (X x) = ... x ...
759 -- Hence, we disable this step.
760 -- TODO: re-enable this in toIR
762 -- as@[ConCase cn i args sc]
763 -- | proj -> mkProj n 0 args (prune proj sc)
764 -- mkProj n i xs sc = foldr (\x -> projRep x n i) sc xs
766 -- If none of the args are used in the sc, however, we can just replace it
768 as@[ConCase cn i args sc]
769 | proj -> let sc' = prune proj sc in
770 if any (isUsed sc') args
771 then Case up n [ConCase cn i args sc']
776 -> projRep cn n (-1) $ prune proj sc
781 -- Bit of a hack here! The default case will always be 0, make sure
782 -- it gets caught first.
783 [s@(SucCase _ _), DefaultCase dc]
784 -> Case up n [ConstCase (BI 0) dc, s]
788 alts' = filter (not . erased) $ map pruneAlt alts
790 pruneAlt (ConCase cn i ns sc) = ConCase cn i ns (prune proj sc)
791 pruneAlt (FnCase cn ns sc) = FnCase cn ns (prune proj sc)
792 pruneAlt (ConstCase c sc) = ConstCase c (prune proj sc)
793 pruneAlt (SucCase n sc) = SucCase n (prune proj sc)
794 pruneAlt (DefaultCase sc) = DefaultCase (prune proj sc)
796 erased (DefaultCase (STerm Erased)) = True
797 erased (DefaultCase ImpossibleCase) = True
800 projRep :: Name -> Name -> Int -> SC -> SC
801 projRep arg n i (Case up x alts) | x == arg
802 = ProjCase (Proj (P Bound n Erased) i) $ map (projRepAlt arg n i) alts
803 projRep arg n i (Case up x alts)
804 = Case up x (map (projRepAlt arg n i) alts)
805 projRep arg n i (ProjCase t alts)
806 = ProjCase (projRepTm arg n i t) $ map (projRepAlt arg n i) alts
807 projRep arg n i (STerm t) = STerm (projRepTm arg n i t)
808 projRep arg n i c = c
810 projRepAlt arg n i (ConCase cn t args rhs)
811 = ConCase cn t args (projRep arg n i rhs)
812 projRepAlt arg n i (FnCase cn args rhs)
813 = FnCase cn args (projRep arg n i rhs)
814 projRepAlt arg n i (ConstCase t rhs)
815 = ConstCase t (projRep arg n i rhs)
816 projRepAlt arg n i (SucCase sn rhs)
817 = SucCase sn (projRep arg n i rhs)
818 projRepAlt arg n i (DefaultCase rhs)
819 = DefaultCase (projRep arg n i rhs)
821 projRepTm arg n i t = subst arg (Proj (P Bound n Erased) i) t
825stripLambdas :: CaseDef -> CaseDef
826stripLambdas (CaseDef ns (STerm (Bind x (Lam _ _) sc)) tm)
827 = stripLambdas (CaseDef (ns ++ [x]) (STerm (instantiate (P Bound x Erased) sc)) tm)
830substSC :: Name -> Name -> SC -> SC
831substSC n repl (Case up n' alts)
832 | n == n' = Case up repl (map (substAlt n repl) alts)
833 | otherwise = Case up n' (map (substAlt n repl) alts)
834substSC n repl (STerm t) = STerm $ subst n (P Bound repl Erased) t
835substSC n repl (UnmatchedCase errmsg) = UnmatchedCase errmsg
836substSC n repl ImpossibleCase = ImpossibleCase
837substSC n repl sc = error $ "unsupported in substSC: " ++ show sc
839substAlt :: Name -> Name -> CaseAlt -> CaseAlt
840substAlt n repl (ConCase cn a ns sc) = ConCase cn a ns (substSC n repl sc)
841substAlt n repl (FnCase fn ns sc) = FnCase fn ns (substSC n repl sc)
842substAlt n repl (ConstCase c sc) = ConstCase c (substSC n repl sc)
843substAlt n repl (SucCase n' sc)
844 | n == n' = SucCase n (substSC n repl sc)
845 | otherwise = SucCase n' (substSC n repl sc)
846substAlt n repl (DefaultCase sc) = DefaultCase (substSC n repl sc)
848-- mkForce n' n t updates the tree t under the assumption that
849-- n' = force n (so basically updating n to n')
850mkForce :: Name -> Name -> SC -> SC
853 mkForceSC n arg (Case up x alts) | x == arg
854 = Case up n $ map (mkForceAlt n arg) alts
856 mkForceSC n arg (Case up x alts)
857 = Case up x (map (mkForceAlt n arg) alts)
859 mkForceSC n arg (ProjCase t alts)
860 = ProjCase t $ map (mkForceAlt n arg) alts
862 mkForceSC n arg c = c
864 mkForceAlt n arg (ConCase cn t args rhs)
865 = ConCase cn t args (mkForceSC n arg rhs)
866 mkForceAlt n arg (FnCase cn args rhs)
867 = FnCase cn args (mkForceSC n arg rhs)
868 mkForceAlt n arg (ConstCase t rhs)
869 = ConstCase t (mkForceSC n arg rhs)
870 mkForceAlt n arg (SucCase sn rhs)
871 = SucCase sn (mkForceSC n arg rhs)
872 mkForceAlt n arg (DefaultCase rhs)
873 = DefaultCase (mkForceSC n arg rhs)
875 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