1{-# LANGUAGE PatternGuards, TypeSynonymInstances, CPP #-}
3module IRTS.Compiler(compile, generate) where
7import IRTS.Defunctionalise
9import IRTS.CodegenCommon
12import IRTS.CodegenJavaScript
17import Idris.AbsSyntaxTree
25import Idris.Core.Evaluate
26import Idris.Core.CaseTree
28import Control.Category
29import Prelude hiding (id, (.))
31import Control.Applicative
32import Control.Monad.State
36import Data.IntSet (IntSet)
37import qualified Data.IntSet as IS
38import qualified Data.Map as M
39import qualified Data.Set as S
43import System.Directory
44import System.Environment
45import System.FilePath ((</>), addTrailingPathSeparator)
47-- | Given a 'main' term to compiler, return the IRs which can be used to
49compile :: Codegen -> FilePath -> Maybe Term -> Idris CodegenInfo
51 = do checkMVs -- check for undefined metavariables
52 checkTotality -- refuse to compile if there are totality problems
53 exports <- findExports
55 reachableNames <- performUsageAnalysis (getExpNames exports)
56 maindef <- case mtm of
58 Just tm -> do md <- irMain tm
59 iLOG $ "MAIN: " ++ show md
60 return [(sMN 0 "runMain", md)]
61 objs <- getObjectFiles codegen
62 libs <- getLibs codegen
63 flags <- getFlags codegen
64 hdrs <- getHdrs codegen
65 impdirs <- allImportDirs
66 defsIn <- mkDecls reachableNames
67 -- if no 'main term' given, generate interface files
68 let iface = case mtm of
72 let defs = defsIn ++ maindef
73 -- iputStrLn $ showSep "\n" (map show defs)
74 -- Inlined top level LDecl made here
75 let defsInlined = inlineAll defs
76 let defsUniq = map (allocUnique (addAlist defsInlined emptyContext))
79 let (nexttag, tagged) = addTags 65536 (liftAll defsUniq)
80 let ctxtIn = addAlist tagged emptyContext
82 iLOG "Defunctionalising"
83 let defuns_in = defunctionalise nexttag ctxtIn
84 logLvl 5 $ show defuns_in
86 let defuns = inline defuns_in
87 logLvl 5 $ show defuns
88 iLOG "Resolving variables for CG"
89 -- iputStrLn $ showSep "\n" (map show (toAlist defuns))
90 let checked = simplifyDefs defuns (toAlist defuns)
92 dumpCases <- getDumpCases
93 dumpDefun <- getDumpDefun
96 Just f -> runIO $ writeFile f (showCaseTrees defs)
99 Just f -> runIO $ writeFile f (dumpDefuns defuns)
100 triple <- Idris.AbsSyntax.targetTriple
101 cpu <- Idris.AbsSyntax.targetCPU
102 iLOG "Building output"
104 OK c -> do return $ CodegenInfo f outty triple cpu
105 hdrs impdirs objs libs flags
106 NONE c (toAlist defuns)
108-- runIO $ case codegen of
109-- ViaC -> codegenC cginfo
110-- ViaJava -> codegenJava cginfo
111-- ViaJavaScript -> codegenJavaScript cginfo
112-- ViaNode -> codegenNode cginfo
113-- ViaLLVM -> codegenLLVM cginfo
114-- Bytecode -> dumpBC c f
116 where checkMVs = do i <- getIState
117 case map fst (idris_metavars i) \\ primDefs of
119 ms -> ifail $ "There are undefined metavariables: " ++ show ms
120 checkTotality = do i <- getIState
121 case idris_totcheckfail i of
123 ((fc, msg):fs) -> ierror . At fc . Msg $ "Cannot compile:\n " ++ msg
124 inDir d h = do let f = d </> h
125 ex <- doesFileExist f
126 if ex then return f else return h
128generate :: Codegen -> FilePath -> CodegenInfo -> IO ()
129generate codegen mainmod ir
131 -- Built-in code generators (FIXME: lift these out!)
132 Via "c" -> codegenC ir
133 -- Any external code generator
134 Via cg -> do let cmd = "idris-" ++ cg
135 args = [mainmod, "-o", outputFile ir]
136 exit <- rawSystem cmd args
137 when (exit /= ExitSuccess) $
138 putStrLn ("FAILURE: " ++ show cmd ++ " " ++ show args)
139 Bytecode -> dumpBC (simpleDecls ir) (outputFile ir)
141irMain :: TT Name -> Idris LDecl
143 i <- irTerm M.empty [] tm
144 return $ LFun [] (sMN 0 "runMain") [] (LForce i)
146mkDecls :: [Name] -> Idris [(Name, LDecl)]
149 let ds = filter (\(n, d) -> n `elem` used || isCon d) $ ctxtAlist (tt_ctxt i)
150 decls <- mapM build ds
153showCaseTrees :: [(Name, LDecl)] -> String
154showCaseTrees = showSep "\n\n" . map showCT . sortBy (comparing defnRank)
156 showCT (n, LFun _ f args lexp)
157 = show n ++ " " ++ showSep " " (map show args) ++ " =\n\t"
159 showCT (n, LConstructor c t a) = "data " ++ show n ++ " " ++ show a
161 defnRank :: (Name, LDecl) -> String
162 defnRank (n, LFun _ _ _ _) = "1" ++ nameRank n
163 defnRank (n, LConstructor _ _ _) = "2" ++ nameRank n
165 nameRank :: Name -> String
166 nameRank (UN s) = "1" ++ show s
167 nameRank (MN i s) = "2" ++ show s ++ show i
168 nameRank (NS n ns) = "3" ++ concatMap show (reverse ns) ++ nameRank n
169 nameRank (SN sn) = "4" ++ snRank sn
170 nameRank n = "5" ++ show n
172 snRank :: SpecialName -> String
173 snRank (WhereN i n n') = "1" ++ nameRank n' ++ nameRank n ++ show i
174 snRank (InstanceN n args) = "2" ++ nameRank n ++ concatMap show args
175 snRank (ParentN n s) = "3" ++ nameRank n ++ show s
176 snRank (MethodN n) = "4" ++ nameRank n
177 snRank (CaseN n) = "5" ++ nameRank n
178 snRank (ElimN n) = "6" ++ nameRank n
179 snRank (InstanceCtorN n) = "7" ++ nameRank n
180 snRank (WithN i n) = "8" ++ nameRank n ++ show i
182isCon (TyDecl _ _) = True
185build :: (Name, Def) -> Idris (Name, LDecl)
188 case lookup n (idris_scprims i) of
190 let args = map (\x -> sMN x "op") [0..] in
191 return (n, (LFun [] n (take ar args)
192 (LOp op (map (LV . Glob) (take ar args)))))
193 _ -> do def <- mkLDecl n d
194 logLvl 3 $ "Compiled " ++ show n ++ " =\n\t" ++ show def
197declArgs args inl n (LLam xs x) = declArgs (args ++ xs) inl n x
198declArgs args inl n x = LFun (if inl then [Inline] else []) n args x
200mkLDecl n (Function tm _)
201 = declArgs [] True n <$> irTerm M.empty [] tm
203mkLDecl n (CaseOp ci _ _ _ pats cd)
204 = declArgs [] (case_inlinable ci || caseName n) n <$> irTree args sc
206 (args, sc) = cases_runtime cd
208 -- Always attempt to inline functions arising from 'case' expressions
209 caseName (SN (CaseN _)) = True
210 caseName (SN (WithN _ _)) = True
211 caseName (NS n _) = caseName n
214mkLDecl n (TyDecl (DCon tag arity _) _) =
215 LConstructor n tag . length <$> fgetState (cg_usedpos . ist_callgraph n)
217mkLDecl n (TyDecl (TCon t a) _) = return $ LConstructor n (-1) a
218mkLDecl n _ = return $ (declArgs [] True n LNothing) -- postulate, never run
221 { viMethod :: Maybe Name
225type Vars = M.Map Name VarInfo
227irTerm :: Vars -> [Name] -> Term -> Idris LExp
228irTerm vs env tm@(App f a) = case unApply tm of
230 | m == txt "mkForeignPrim"
231 -> doForeign vs env (reverse (drop 4 args)) -- drop implicits
233 (P _ (UN u) _, [_, arg])
234 | u == txt "unsafePerformPrimIO"
237 -- TMP HACK - until we get inlining.
238 (P _ (UN r) _, [_, _, _, _, _, arg])
242 -- Laziness, the old way
243 (P _ (UN l) _, [_, arg])
245 -> error "lazy has crept in somehow"
247 (P _ (UN l) _, [_, arg])
249 -> LForce <$> irTerm vs env arg
251 -- Laziness, the new way
252 (P _ (UN l) _, [_, _, arg])
254 -> LLazyExp <$> irTerm vs env arg
256 (P _ (UN l) _, [_, _, arg])
258 -> LForce <$> irTerm vs env arg
260 (P _ (UN a) _, [_, _, _, arg])
261 | a == txt "assert_smaller"
264 (P _ (UN a) _, [_, arg])
265 | a == txt "assert_total"
268 (P _ (UN p) _, [_, arg])
270 -> do arg' <- irTerm vs env arg
271 return $ LOp LPar [LLazyExp arg']
273 (P _ (UN pf) _, [arg])
274 | pf == txt "prim_fork"
275 -> do arg' <- irTerm vs env arg
276 return $ LOp LFork [LLazyExp arg']
278 (P _ (UN m) _, [_,size,t])
282 (P _ (UN tm) _, [_,t])
283 | tm == txt "trace_malloc"
284 -> irTerm vs env t -- TODO
286 -- This case is here until we get more general inlining. It's just
287 -- a really common case, and the laziness hurts...
288 (P _ (NS (UN be) [b,p]) _, [_,x,(App (App (App (P _ (UN d) _) _) _) t),
289 (App (App (App (P _ (UN d') _) _) _) e)])
290 | be == txt "boolElim"
294 x' <- irTerm vs env x
295 t' <- irTerm vs env t
296 e' <- irTerm vs env e
297 return (LCase Shared x'
298 [LConCase 0 (sNS (sUN "False") ["Bool","Prelude"]) [] e'
299 ,LConCase 1 (sNS (sUN "True" ) ["Bool","Prelude"]) [] t'
303 (P (DCon t arity _) n _, args) -> do
304 detag <- fgetState (opt_detaggable . ist_optimisation n)
305 used <- map fst <$> fgetState (cg_usedpos . ist_callgraph n)
307 let isNewtype = length used == 1 && detag
308 let argsPruned = [a | (i,a) <- zip [0..] args, i `elem` used]
310 -- The following code removes fields from data constructors
311 -- and performs the newtype optimisation.
313 -- The general rule here is:
314 -- Everything we get as input is not touched by erasure,
315 -- so it conforms to the official arities and types
316 -- and we can reason about it like it's plain TT.
318 -- It's only the data that leaves this point that's erased
319 -- and possibly no longer typed as the original TT version.
321 -- Especially, underapplied constructors must yield functions
322 -- even if all the remaining arguments are erased
323 -- (the resulting function *will* be applied, to NULLs).
325 -- This will probably need rethinking when we get erasure from functions.
327 -- "padLams" will wrap our term in LLam-bdas and give us
328 -- the "list of future unerased args" coming from these lambdas.
330 -- We can do whatever we like with the list of unerased args,
331 -- hence it takes a lambda: \unerased_argname_list -> resulting_LExp.
332 let padLams = padLambdas used (length args) arity
334 case compare (length args) arity of
337 GT -> ifail ("overapplied data constructor: " ++ show tm)
341 -> irTerm vs env (head argsPruned)
343 | otherwise -- not newtype, plain data ctor
344 -> buildApp (LV $ Glob n) argsPruned
346 -- not saturated, underapplied
347 LT | isNewtype -- newtype
348 , length argsPruned == 1 -- and we already have the value
349 -> padLams . (\tm [] -> tm) -- the [] asserts there are no unerased args
350 <$> irTerm vs env (head argsPruned)
352 | isNewtype -- newtype but the value is not among args yet
353 -> return . padLams $ \[vn] -> LApp False (LV $ Glob n) [LV $ Glob vn]
355 -- not a newtype, just apply to a constructor
357 -> padLams . applyToNames <$> buildApp (LV $ Glob n) argsPruned
360 (P (TCon t a) n _, args) -> return LNothing
362 -- a name applied to arguments
363 (P _ n _, args) -> do
365 case lookup n (idris_scprims ist) of
366 -- if it's a primitive that is already saturated,
367 -- compile to the corresponding op here already to save work
368 Just (arity, op) | length args == arity
369 -> LOp op <$> mapM (irTerm vs env) args
371 -- otherwise, just apply the name
372 _ -> applyName n ist args
374 -- turn de bruijn vars into regular named references and try again
375 (V i, args) -> irTerm vs env $ mkApp (P Bound (env !! i) Erased) args
380 <*> mapM (irTerm vs env) args
383 buildApp :: LExp -> [Term] -> Idris LExp
384 buildApp e [] = return e
385 buildApp e xs = LApp False e <$> mapM (irTerm vs env) xs
387 applyToNames :: LExp -> [Name] -> LExp
388 applyToNames tm [] = tm
389 applyToNames tm ns = LApp False tm $ map (LV . Glob) ns
391 padLambdas :: [Int] -> Int -> Int -> ([Name] -> LExp) -> LExp
392 padLambdas used startIdx endSIdx mkTerm
393 = LLam allNames $ mkTerm nonerasedNames
395 allNames = [sMN i "sat" | i <- [startIdx .. endSIdx-1]]
396 nonerasedNames = [sMN i "sat" | i <- [startIdx .. endSIdx-1], i `elem` used]
398 applyName :: Name -> IState -> [Term] -> Idris LExp
399 applyName n ist args =
400 LApp False (LV $ Glob n) <$> mapM (irTerm vs env . erase) (zip [0..] args)
403 | i >= arity || i `elem` used = x
406 arity = case fst4 <$> lookupCtxtExact n (definitions . tt_ctxt $ ist) of
407 Just (CaseOp ci ty tys def tot cdefs) -> length tys
408 Just (TyDecl (DCon tag ar _) _) -> ar
409 Just (TyDecl Ref ty) -> length $ getArgTys ty
410 Just (Operator ty ar op) -> ar
411 Just def -> error $ "unknown arity: " ++ show (n, def)
412 Nothing -> 0 -- no definition, probably local name => can't erase anything
414 -- name for purposes of usage info lookup
416 | Just n' <- viMethod =<< M.lookup n vs = n'
419 used = maybe [] (map fst . usedpos) $ lookupCtxtExact uName (idris_callgraph ist)
422irTerm vs env (P _ n _) = return $ LV (Glob n)
424 | i >= 0 && i < length env = return $ LV (Glob (env!!i))
425 | otherwise = ifail $ "bad de bruijn index: " ++ show i
427irTerm vs env (Bind n (Lam _) sc) = LLam [n'] <$> irTerm vs (n':env) sc
429 n' = uniqueName n env
431irTerm vs env (Bind n (Let _ v) sc)
432 = LLet n <$> irTerm vs env v <*> irTerm vs (n : env) sc
434irTerm vs env (Bind _ _ _) = return $ LNothing
436irTerm vs env (Proj t (-1)) = do
437 t' <- irTerm vs env t
438 return $ LOp (LMinus (ATInt ITBig))
441irTerm vs env (Proj t i) = LProj <$> irTerm vs env t <*> pure i
442irTerm vs env (Constant TheWorld) = return $ LNothing
443irTerm vs env (Constant c) = return $ LConst c
444irTerm vs env (TType _) = return $ LNothing
445irTerm vs env Erased = return $ LNothing
446irTerm vs env Impossible = return $ LNothing
448doForeign :: Vars -> [Name] -> [Term] -> Idris LExp
449doForeign vs env (ret : fname : world : args)
450 = do args' <- mapM splitArg args
451 let fname' = toFDesc fname
452 let ret' = toFDesc ret
453 return $ LForeign ret' fname' args'
455 splitArg tm | (_, [_,_,l,r]) <- unApply tm -- pair, two implicits
456 = do let l' = toFDesc l
457 r' <- irTerm vs env r
459 splitArg _ = ifail "Badly formed foreign function call"
461 toFDesc (Constant (Str str)) = FStr str
463 | (P _ n _, []) <- unApply tm = FCon (deNS n)
464 | (P _ n _, as) <- unApply tm = FApp (deNS n) (map toFDesc as)
469doForeign vs env xs = ifail "Badly formed foreign function call"
472 - | (_, (Constant (Str fgnName) : fgnArgTys : ret : [])) <- unApply fgn
473 = case getFTypes fgnArgTys of
474 Nothing -> ifail $ "Foreign type specification is not a constant list: " ++ show (fgn:args)
476 args' <- mapM (irTerm vs env) (init args)
477 return $ LForeign LANG_C (mkIty' ret) fgnName (zip tys args')
479 | otherwise = ifail "Badly formed foreign function call"
481 getFTypes :: TT Name -> Maybe [FType]
482 getFTypes tm = case unApply tm of
483 -- nil : {a : Type} -> List a
484 (nil, [_]) -> Just []
485 -- cons : {a : Type} -> a -> List a -> List a
486 (cons, [_, ty, xs]) -> (mkIty' ty :) <$> getFTypes xs
489 mkIty' (P _ (UN ty) _) = mkIty (str ty)
490 mkIty' (App (P _ (UN fi) _) (P _ (UN intTy) _))
492 = mkIntIty (str intTy)
494 mkIty' (App (App (P _ (UN ff) _) _) (App (P _ (UN fa) _) (App (P _ (UN io) _) _)))
495 | ff == txt "FFunction"
500 mkIty' (App (App (P _ (UN ff) _) _) _)
501 | ff == txt "FFunction"
506 -- would be better if these FInt types were evaluated at compile time
507 -- TODO: add %eval directive for such things
508 -- Issue #1742 on the issue tracker.
509 -- https://github.com/idris-lang/Idris-dev/issues/1742
510 mkIty "FFloat" = FArith ATFloat
511 mkIty "FInt" = mkIntIty "ITNative"
512 mkIty "FChar" = mkIntIty "ITChar"
513 mkIty "FByte" = mkIntIty "IT8"
514 mkIty "FShort" = mkIntIty "IT16"
515 mkIty "FLong" = mkIntIty "IT64"
516 mkIty "FBits8" = mkIntIty "IT8"
517 mkIty "FBits16" = mkIntIty "IT16"
518 mkIty "FBits32" = mkIntIty "IT32"
519 mkIty "FBits64" = mkIntIty "IT64"
520 mkIty "FString" = FString
522 mkIty "FManagedPtr" = FManagedPtr
523 mkIty "FUnit" = FUnit
524 mkIty "FFunction" = FFunction
525 mkIty "FFunctionIO" = FFunctionIO
526 mkIty "FBits8x16" = FArith (ATInt (ITVec IT8 16))
527 mkIty "FBits16x8" = FArith (ATInt (ITVec IT16 8))
528 mkIty "FBits32x4" = FArith (ATInt (ITVec IT32 4))
529 mkIty "FBits64x2" = FArith (ATInt (ITVec IT64 2))
530 mkIty x = error $ "Unknown type " ++ x
532 mkIntIty "ITNative" = FArith (ATInt ITNative)
533 mkIntIty "ITChar" = FArith (ATInt ITChar)
534 mkIntIty "IT8" = FArith (ATInt (ITFixed IT8))
535 mkIntIty "IT16" = FArith (ATInt (ITFixed IT16))
536 mkIntIty "IT32" = FArith (ATInt (ITFixed IT32))
537 mkIntIty "IT64" = FArith (ATInt (ITFixed IT64))
540irTree :: [Name] -> SC -> Idris LExp
542 logLvl 3 $ "Compiling " ++ show args ++ "\n" ++ show tree
543 LLam args <$> irSC M.empty tree
545irSC :: Vars -> SC -> Idris LExp
546irSC vs (STerm t) = irTerm vs [] t
547irSC vs (UnmatchedCase str) = return $ LError str
549irSC vs (ProjCase tm alts) = do
550 tm' <- irTerm vs [] tm
551 alts' <- mapM (irAlt vs tm') alts
552 return $ LCase Shared tm' alts'
554-- Transform matching on Delay to applications of Force.
555irSC vs (Case up n [ConCase (UN delay) i [_, _, n'] sc])
556 | delay == txt "Delay"
557 = do sc' <- irSC vs $ mkForce n' n sc
558 return $ LLet n' (LForce (LV (Glob n))) sc'
560-- There are two transformations in this case:
562-- 1. Newtype-case elimination:
564-- wrap({e1}) -> P({e1}) ==> P({e0})
566-- This is important because newtyped constructors are compiled away entirely
567-- and we need to do that everywhere.
569-- 2. Unused-case elimination (only valid for singleton branches):
571-- C(x,y) -> P[... x,y not used ...]
573-- This is important for runtime because sometimes we case on irrelevant data:
575-- In the example above, {e0} will most probably have been erased
576-- so this vain projection would make the resulting program segfault
577-- because the code generator still emits a PROJECT(...) G-machine instruction.
579-- Hence, we check whether the variables are used at all
580-- and erase the casesplit if they are not.
582irSC vs (Case up n [alt]) = do
583 replacement <- case alt of
584 ConCase cn a ns sc -> do
585 detag <- fgetState (opt_detaggable . ist_optimisation cn)
586 used <- map fst <$> fgetState (cg_usedpos . ist_callgraph cn)
587 if detag && length used == 1
588 then return . Just $ substSC (ns !! head used) n sc
593 Just sc -> irSC vs sc
595 alt' <- irAlt vs (LV (Glob n)) alt
596 return $ case namesBoundIn alt' `usedIn` subexpr alt' of
597 [] -> subexpr alt' -- strip the unused top-most case
598 _ -> LCase up (LV (Glob n)) [alt']
600 namesBoundIn :: LAlt -> [Name]
601 namesBoundIn (LConCase cn i ns sc) = ns
602 namesBoundIn (LConstCase c sc) = []
603 namesBoundIn (LDefaultCase sc) = []
605 subexpr :: LAlt -> LExp
606 subexpr (LConCase _ _ _ e) = e
607 subexpr (LConstCase _ e) = e
608 subexpr (LDefaultCase e) = e
610-- FIXME: When we have a non-singleton case-tree of the form
616-- and C is detaggable (the only constructor of the family), we can be sure
617-- that the first branch will be always taken -- so we add special handling
618-- to remove the dead default branch.
620-- If we don't do so and C is newtype-optimisable, we will miss this newtype
621-- transformation and the resulting code will probably segfault.
623-- This work-around is not entirely optimal; the best approach would be
624-- to ensure that such case trees don't arise in the first place.
626irSC vs (Case up n alts@[ConCase cn a ns sc, DefaultCase sc']) = do
627 detag <- fgetState (opt_detaggable . ist_optimisation cn)
629 then irSC vs (Case up n [ConCase cn a ns sc])
630 else LCase up (LV (Glob n)) <$> mapM (irAlt vs (LV (Glob n))) alts
632irSC vs sc@(Case up n alts) = do
633 -- check that neither alternative needs the newtype optimisation,
635 goneWrong <- or <$> mapM isDetaggable alts
637 $ ifail ("irSC: non-trivial case-match on detaggable data: " ++ show sc)
640 LCase up (LV (Glob n)) <$> mapM (irAlt vs (LV (Glob n))) alts
642 isDetaggable (ConCase cn _ _ _) = fgetState $ opt_detaggable . ist_optimisation cn
643 isDetaggable _ = return False
645irSC vs ImpossibleCase = return LNothing
647irAlt :: Vars -> LExp -> CaseAlt -> Idris LAlt
649-- this leaves out all unused arguments of the constructor
650irAlt vs _ (ConCase n t args sc) = do
651 used <- map fst <$> fgetState (cg_usedpos . ist_callgraph n)
652 let usedArgs = [a | (i,a) <- zip [0..] args, i `elem` used]
653 LConCase (-1) n usedArgs <$> irSC (methodVars `M.union` vs) sc
655 methodVars = case n of
656 SN (InstanceCtorN className)
657 -> M.fromList [(v, VI
658 { viMethod = Just $ mkFieldName n i
659 }) | (v,i) <- zip args [0..]]
661 -> M.empty -- not an instance constructor
663irAlt vs _ (ConstCase x rhs)
664 | matchable x = LConstCase x <$> irSC vs rhs
665 | matchableTy x = LDefaultCase <$> irSC vs rhs
667 matchable (I _) = True
668 matchable (BI _) = True
669 matchable (Ch _) = True
670 matchable (Str _) = True
673 matchableTy (AType (ATInt ITNative)) = True
674 matchableTy (AType (ATInt ITBig)) = True
675 matchableTy (AType (ATInt ITChar)) = True
676 matchableTy StrType = True
678 matchableTy (AType (ATInt (ITFixed IT8))) = True
679 matchableTy (AType (ATInt (ITFixed IT16))) = True
680 matchableTy (AType (ATInt (ITFixed IT32))) = True
681 matchableTy (AType (ATInt (ITFixed IT64))) = True
683 matchableTy _ = False
685irAlt vs tm (SucCase n rhs) = do
687 return $ LDefaultCase (LLet n (LOp (LMinus (ATInt ITBig))
689 LConst (BI 1)]) rhs')
691irAlt vs _ (ConstCase c rhs)
692 = ifail $ "Can't match on (" ++ show c ++ ")"
694irAlt vs _ (DefaultCase rhs)
695 = LDefaultCase <$> irSC vs 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