@@ -5,7 +5,8 @@ Description : Coordinates the compilation process.
5License : BSD3
5License : BSD3
6Maintainer : The Idris Community.
6Maintainer : The Idris Community.
8−{-# LANGUAGE CPP, FlexibleContexts, PatternGuards, TypeSynonymInstances #-}
8+{-# LANGUAGE CPP, FlexibleContexts, MultiWayIf, NamedFieldPuns, PatternGuards,
9+ TypeSynonymInstances #-}
10module IRTS.Compiler(compile, generate) where
11module IRTS.Compiler(compile, generate) where
@@ -34,6 +35,7 @@ import Control.Category
34import Control.Monad.State
35import Control.Monad.State
35import Data.List
36import Data.List
36import qualified Data.Map as M
37import qualified Data.Map as M
38+import Data.Maybe (maybe)
37import Data.Ord
39import Data.Ord
38import qualified Data.Set as S
40import qualified Data.Set as S
39import System.Directory
41import System.Directory
@@ -393,6 +395,16 @@ irTerm top vs env tm@(App _ f a) = do
393 EQ | isNewtype
395 EQ | isNewtype
394 -> irTerm top vs env (head argsPruned)
396 -> irTerm top vs env (head argsPruned)
398+ -- compile Nat-likes as bigints
399+ | Just LikeZ <- isLikeNat ist n
400+ -> irTerm top vs env $ Constant (BI 0)
402+ -- compile Nat-likes as bigints
403+ | Just LikeS <- isLikeNat ist n
404+ -> irTerm top vs env $ mkApp
405+ (P Ref (sUN "prim__addBigInt") Erased)
406+ (Constant (BI 1) : argsPruned)
396 | otherwise -- not newtype, plain data ctor
408 | otherwise -- not newtype, plain data ctor
397 -> buildApp (LV n) argsPruned
409 -> buildApp (LV n) argsPruned
@@ -405,6 +417,14 @@ irTerm top vs env tm@(App _ f a) = do
405 | isNewtype -- newtype but the value is not among args yet
417 | isNewtype -- newtype but the value is not among args yet
406 -> return . padLams $ \[vn] -> LApp False (LV n) [LV vn]
418 -> return . padLams $ \[vn] -> LApp False (LV n) [LV vn]
420+ -- compile Nat-likes as bigints
421+ -- it seems that prim applications needn't be saturated
422+ | Just LikeS <- isLikeNat ist n
423+ -> irTerm top vs env $
425+ (P Ref (sUN "prim__addBigInt") Erased)
408 -- not a newtype, just apply to a constructor
428 -- not a newtype, just apply to a constructor
409 | otherwise
429 | otherwise
410 -> padLams . applyToNames <$> buildApp (LV n) argsPruned
430 -> padLams . applyToNames <$> buildApp (LV n) argsPruned
@@ -501,6 +521,58 @@ irTerm top vs env (TType _) = return LNothing
501irTerm top vs env Erased = return LNothing
521irTerm top vs env Erased = return LNothing
502irTerm top vs env Impossible = return LNothing
522irTerm top vs env Impossible = return LNothing
524+data LikeNat = LikeZ | LikeS
526+isLikeNat :: IState -> Name -> Maybe LikeNat
528+ -- Nat itself is special-cased in Idris/DataOpts.hs,
529+ -- which will have already happened at this point.
531+ -- If the optimisation is disabled then nothing looks like Nat.
532+ | GeneralisedNatHack `notElem` opt_optimise (idris_options ist)
535+ | Just cTy <- lookupTyExact cn $ tt_ctxt ist
536+ , (P TCon{} tyN _, _) <- unApply $ getRetTy cTy
537+ , Just (z, s) <- natLikeCtors tyN
538+ = if | cn == z -> Just LikeZ
539+ | cn == s -> Just LikeS
540+ | otherwise -> error $ "isLikeNat: constructor not found in its own family: " ++ show (cn, tyN)
542+ | otherwise = Nothing
544+ natLikeCtors :: Name -> Maybe (Name, Name)
545+ natLikeCtors tyN = case lookupCtxtExact tyN $ idris_datatypes ist of
546+ Just TI{con_names = [z, s]}
547+ | 0 <- getUsedCount z
551+ Just TI{con_names = [s, z]}
552+ | 0 <- getUsedCount z
558+ getUsedCount :: Name -> Int
560+ maybe 0 (length . usedpos)
562+ $ idris_callgraph ist
564+ looksLikeS :: Name -> Bool
566+ | Just [(i, _)] <- fmap usedpos $ lookupCtxtExact cn $ idris_callgraph ist
567+ , Just cTy <- lookupTyExact cn $ tt_ctxt ist
568+ , [recTy] <- [recTy | (j, (_n, recTy)) <- zip [0..] (getArgTys cTy), j == i]
569+ , (P TCon{} recTyN _, _) <- unApply recTy
570+ , (P TCon{} tyN _, _) <- unApply $ getRetTy cTy
504doForeign :: Vars -> [Name] -> [Term] -> Idris LExp
576doForeign :: Vars -> [Name] -> [Term] -> Idris LExp
505doForeign vs env (ret : fname : world : args)
577doForeign vs env (ret : fname : world : args)
506 = do args' <- mapM splitArg args
578 = do args' <- mapM splitArg args
@@ -616,18 +688,41 @@ irSC top vs (Case up n alts@[ConCase cn a ns sc, DefaultCase sc']) = do
616 detag <- fgetState (opt_detaggable . ist_optimisation cn)
688 detag <- fgetState (opt_detaggable . ist_optimisation cn)
618 then irSC top vs (Case up n [ConCase cn a ns sc])
690 then irSC top vs (Case up n [ConCase cn a ns sc])
692+ likeNat <- isLikeNat <$> getIState <*> pure cn
694+ -- the annoying case: LikeS is translated into a default case
695+ -- so we need to change the original DefaultCase to Z-case
696+ -- and reorder it before this one
698+ zCase <- LConstCase (BI 0) <$> irSC top vs sc'
699+ sCase <- irAlt top vs (LV n) (ConCase cn a ns sc)
700+ return $ LCase up (LV n) [zCase, sCase]
619− else LCase up (LV n) <$> mapM (irAlt top vs (LV n)) alts
703+ _ -> LCase up (LV n) <$> mapM (irAlt top vs (LV n)) alts
621−irSC top vs sc@(Case up n alts) = do
705+irSC top vs sc@(Case up n alts) = getIState >>= rhs
622− -- check that neither alternative needs the newtype optimisation,
623− -- see comment above
624− goneWrong <- or <$> mapM isDetaggable alts
626− $ ifail ("irSC: non-trivial case-match on detaggable data: " ++ show sc)
629− LCase up (LV n) <$> mapM (irAlt top vs (LV n)) alts
708+ | [ConCase cns as nss scs, ConCase cnz az nsz scz] <- alts
709+ , Just LikeS <- isLikeNat ist cns
711+ -- reorder to make the Z case come first
712+ zCase <- LConstCase (BI 0) <$> irSC top vs scz
713+ sCase <- irAlt top vs (LV n) (ConCase cns as nss scs)
714+ return $ LCase up (LV n) [zCase, sCase]
717+ -- check that neither alternative needs the newtype optimisation,
718+ -- see comment above
719+ goneWrong <- or <$> mapM isDetaggable alts
721+ $ ifail ("irSC: non-trivial case-match on detaggable data: " ++ show sc)
724+ LCase up (LV n) <$> mapM (irAlt top vs (LV n)) alts
631 isDetaggable (ConCase cn _ _ _) = fgetState $ opt_detaggable . ist_optimisation cn
726 isDetaggable (ConCase cn _ _ _) = fgetState $ opt_detaggable . ist_optimisation cn
632 isDetaggable _ = return False
727 isDetaggable _ = return False
@@ -636,10 +731,32 @@ irSC top vs ImpossibleCase = return LNothing
636irAlt :: Name -> Vars -> LExp -> CaseAlt -> Idris LAlt
731irAlt :: Name -> Vars -> LExp -> CaseAlt -> Idris LAlt
638-- this leaves out all unused arguments of the constructor
733-- this leaves out all unused arguments of the constructor
639−irAlt top vs _ (ConCase n t args sc) = do
734+irAlt top vs tm (ConCase n t args sc) = do
735+ likeNat <- isLikeNat <$> getIState <*> pure n
640 used <- map fst <$> fgetState (cg_usedpos . ist_callgraph n)
736 used <- map fst <$> fgetState (cg_usedpos . ist_callgraph n)
641 let usedArgs = [a | (i,a) <- zip [0..] args, i `elem` used]
737 let usedArgs = [a | (i,a) <- zip [0..] args, i `elem` used]
742+ sc' <- irSC top vs sc
744+ [pv] -> return $ LDefaultCase $ LLet pv
746+ (LMinus (ATInt ITBig))
753+ _ -> ifail $ "irAlt/LikeS: multiple used args: " ++ show usedArgs
756+ Just LikeZ -> LConstCase (BI 0) <$> irSC top vs sc
642− LConCase (-1) n usedArgs <$> irSC top (methodVars `M.union` vs) sc
759+ Nothing -> LConCase (-1) n usedArgs <$> irSC top (methodVars `M.union` vs) sc
644 methodVars = case n of
761 methodVars = case n of
645 SN (ImplementationCtorN interfaceName)
762 SN (ImplementationCtorN interfaceName)