Rattus 0.5.0.1 → 0.5.1
raw patch · 12 files changed
+355/−98 lines, 12 filesdep ~ghcPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: ghc
API changes (from Hackage documentation)
+ Rattus: AllowRecursion :: Rattus
+ Rattus.Event: combine :: Box (a -> a -> a) -> Str a -> Event (Str a) -> Str a
+ Rattus.Event: dswitchTrans :: (Str a -> Str b) -> O (Event (Str a -> Str b)) -> Str a -> Str b
+ Rattus.Plugin: AllowRecursion :: Rattus
+ Rattus.Plugin.Annotation: AllowRecursion :: Rattus
+ Rattus.Plugin.Annotation: instance GHC.Classes.Ord Rattus.Plugin.Annotation.Rattus
+ Rattus.Strict: init' :: List a -> List a
+ Rattus.Strict: listDelay :: List (O a) -> O (List a)
- Rattus.Yampa: (>>>) :: forall k cat (a :: k) (b :: k) (c :: k). Category cat => cat a b -> cat b c -> cat a c
+ Rattus.Yampa: (>>>) :: forall {k} cat (a :: k) (b :: k) (c :: k). Category cat => cat a b -> cat b c -> cat a c
- Rattus.Yampa: integral :: (Stable a, VectorSpace a s) => a -> SF a a
+ Rattus.Yampa: integral :: (Stable a, VectorSpace a s, Fractional s) => a -> SF a a
Files
- Rattus.cabal +3/−3
- docs/paper.pdf binary
- src/Rattus/Event.hs +24/−1
- src/Rattus/Plugin.hs +11/−2
- src/Rattus/Plugin/Annotation.hs +7/−1
- src/Rattus/Plugin/CheckSingleTick.hs +16/−10
- src/Rattus/Plugin/Dependency.hs +107/−32
- src/Rattus/Plugin/ScopeCheck.hs +122/−43
- src/Rattus/Plugin/StableSolver.hs +12/−2
- src/Rattus/Plugin/Utils.hs +27/−3
- src/Rattus/Strict.hs +25/−0
- src/Rattus/Yampa.hs +1/−1
Rattus.cabal view
@@ -1,6 +1,6 @@ cabal-version: 1.18 name: Rattus-version: 0.5.0.1+version: 0.5.1 category: FRP synopsis: A modal FRP language description:@@ -131,7 +131,7 @@ custom-setup setup-depends: base >= 4.5 && < 5,- Cabal >= 1.18+ Cabal >= 1.18 && < 4 library@@ -155,7 +155,7 @@ Rattus.Plugin.Utils Rattus.Plugin.Dependency Rattus.Plugin.StableSolver- build-depends: base >=4.12 && <5, containers, ghc >= 8.6 && < 9.3, ghc-prim, simple-affine-space, transformers+ build-depends: base >=4.12 && <5, containers, ghc >= 8.6 && < 9.7, ghc-prim, simple-affine-space, transformers hs-source-dirs: src default-language: Haskell2010 ghc-options: -W
docs/paper.pdf view
binary file changed (326270 → 1411474 bytes)
src/Rattus/Event.hs view
@@ -9,6 +9,8 @@ , never , switch , switchTrans+ , dswitchTrans+ , combine , Event , trigger , triggerMap@@ -20,7 +22,7 @@ import Rattus.Stream hiding (map) import qualified Rattus.Stream as Str -import Prelude hiding (map)+import Prelude hiding (map,zipWith) -- | Events are simply streams of 'Maybe''s. type Event a = Str (Maybe' a)@@ -45,6 +47,16 @@ switch _xs (Just' (a ::: as) ::: fas) = a ::: (delay switch <#> as <#> fas) +-- | @combine f s e@ is similar to @switch s e@, but instead of+-- switching to new streams @s'@ every time the event 'e' occurs with+-- some value @s'@, the new stream @s'@ is combined with the current+-- stream @s@ using @zipWith f s' s@.+combine :: Box (a -> a -> a) -> Str a -> Event (Str a) -> Str a+combine f (x ::: xs) (Nothing' ::: fas) = x ::: delay (combine f (adv xs) (adv fas))+combine f xs (Just' as ::: fas) = x' ::: delay (combine f (adv xs') (adv fas))+ where (x' ::: xs') = zipWith f xs as++ -- | Like 'switch' but works on stream functions instead of -- streams. That is, @switchTrans s e@ will behave like @s@ but -- switches to @s'$ every time the event 'e' occurs with some value@@ -57,6 +69,17 @@ switchTrans' (b ::: bs) (Nothing' ::: fs) (_:::as) = b ::: (delay switchTrans' <#> bs <#> fs <#> as) switchTrans' _xs (Just' f ::: fs) as@(_:::as') = b' ::: (delay switchTrans' <#> bs' <#> fs <#> as') where (b' ::: bs') = f as++++-- | Like 'switchTrans' but takes a delayed event as input, which+-- allows the switch to incorporate feedback from itself.+dswitchTrans :: (Str a -> Str b) -> O (Event (Str a -> Str b)) -> (Str a -> Str b)+dswitchTrans f es as = dswitchTrans' (f as) es as++-- | Helper function for 'dswitchTrans'.+dswitchTrans' :: Str b -> O (Event (Str a -> Str b)) -> Str a -> Str b+dswitchTrans' (b ::: bs) de (_:::as) = b ::: (delay switchTrans' <#> bs <#> de <#> as) -- | Trigger an event as every time the given predicate turns true on
src/Rattus/Plugin.hs view
@@ -73,9 +73,11 @@ es' <- mapM (\ (v,e) -> do e' <- toSingleTick e lazy <- allowLazyData guts v+ allowRec <- allowRecursion guts v e'' <- strictifyExpr (SCxt (nameSrcSpan $ getName v) (not lazy))e' checkExpr CheckExpr{ recursiveSet = Set.fromList vs, oldExpr = e,- fatalError = False, verbose = debugMode opts} e''+ fatalError = False, verbose = debugMode opts,+ allowRecExp = allowRec} e'' return e'') bs return (Rec (zip vs es')) else return b@@ -88,9 +90,11 @@ -- liftIO $ putStrLn "-------- new --------" -- liftIO $ putStrLn (showSDocUnsafe (ppr e')) lazy <- allowLazyData guts v+ allowRec <- allowRecursion guts v e'' <- strictifyExpr (SCxt (nameSrcSpan $ getName v) (not lazy)) e' checkExpr CheckExpr{ recursiveSet = Set.empty, oldExpr = e,- fatalError = False, verbose = debugMode opts} e''+ fatalError = False, verbose = debugMode opts,+ allowRecExp = allowRec } e'' return (NonRec v e'') else return b @@ -108,6 +112,11 @@ allowLazyData guts bndr = do l <- annotationsOn guts bndr :: CoreM [Rattus] return (AllowLazyData `elem` l)++allowRecursion :: ModGuts -> CoreBndr -> CoreM Bool+allowRecursion guts bndr = do+ l <- annotationsOn guts bndr :: CoreM [Rattus]+ return (AllowRecursion `elem` l) shouldTransform :: ModGuts -> CoreBndr -> CoreM Bool
src/Rattus/Plugin/Annotation.hs view
@@ -26,8 +26,14 @@ -- > {-# ANN myFunction AllowLazyData #-} -- > -- > {-# ANN module AllowLazyData #-}+--+-- Rattus only allows guarded recursion, i.e. recursive calls must+-- occur in the scope of a tick. Structural recursion over strict data+-- types is safe as well, but is currently not checked. To disable the+-- guarded recursion check, annotate the module or function with+-- 'AllowRecursion'. -data Rattus = Rattus | NotRattus | AllowLazyData deriving (Typeable, Data, Show, Eq)+data Rattus = Rattus | NotRattus | AllowLazyData | AllowRecursion deriving (Typeable, Data, Show, Ord, Eq) -- | This annotation type is for internal use only.
src/Rattus/Plugin/CheckSingleTick.hs view
@@ -54,7 +54,8 @@ primAlias :: Map Var Prim, -- number of ticks (for recursive calls). This is to allow -- recursive definitions of the form @f = delay (delay (adv f))@.- ticks :: Int} + ticks :: Int,+ allowRecursion :: Bool} primMap :: Map FastString Prim primMap = Map.fromList@@ -89,14 +90,17 @@ getScope :: Ctx -> Var -> Scope getScope c v = if v `Set.member` recDef c then- if ticks c > 0 then Visible+ if ticks c > 0 || allowRecursion c then Visible else Hidden ("(Mutually) recursive call to " <> ppr v <> " must occur under delay") else case Map.lookup v (hidden c) of Just reason -> if (isStable (stableTypes c) (varType v)) then Visible else case reason of- NestedRec rv -> Hidden ("Variable " <> ppr v <> " is no longer in scope:" $$ "It appears in a local recursive definition (namely of " <> ppr rv <> ")"- $$ "and is of type " <> ppr (varType v) <> ", which is not stable.")+ NestedRec rv ->+ if allowRecursion c then Visible+ else Hidden ("Variable " <> ppr v <> " is no longer in scope:"+ $$ "It appears in a local recursive definition (namely of " <> ppr rv <> ")"+ $$ "and is of type " <> ppr (varType v) <> ", which is not stable.") BoxApp -> Hidden ("Variable " <> ppr v <> " is no longer in scope:" $$ "It occurs under " <> keyword "box" $$ "and is of type " <> ppr (varType v) <> ", which is not stable.") AdvApp -> Hidden ("Variable " <> ppr v <> " is no longer in scope: It occurs under adv.")@@ -123,16 +127,17 @@ return (Just (TypeError (pickFirst (srcLoc cxt) (nameSrcSpan (varName var))) doc)) -emptyCtx :: Set Var -> Ctx-emptyCtx vars =+emptyCtx :: CheckExpr -> Ctx+emptyCtx c = Ctx { current = Set.empty, earlier = Nothing, hidden = Map.empty, srcLoc = noLocationInfo,- recDef = vars,+ recDef = recursiveSet c, primAlias = Map.empty, stableTypes = Set.empty,- ticks = 0}+ ticks = 0,+ allowRecursion = allowRecExp c} isPrimExpr :: Ctx -> Expr Var -> Maybe (Prim,Var)@@ -169,12 +174,13 @@ recursiveSet :: Set Var, oldExpr :: Expr Var, fatalError :: Bool,- verbose :: Bool+ verbose :: Bool,+ allowRecExp :: Bool } checkExpr :: CheckExpr -> Expr Var -> CoreM () checkExpr c e = do- res <- checkExpr' (emptyCtx (recursiveSet c)) e+ res <- checkExpr' (emptyCtx c) e case res of Nothing -> return () Just (TypeError src doc) ->
src/Rattus/Plugin/Dependency.hs view
@@ -6,7 +6,7 @@ -- | This module is used to perform a dependency analysis of top-level -- function definitions, i.e. to find out which defintions are--- (mutual) recursive. To this end, this module also provides a+-- (mutual) recursive. To this end, this module also provides -- functions to compute, bound variables and variable occurrences. module Rattus.Plugin.Dependency (dependency, HasBV (..),printBinds) where@@ -37,7 +37,9 @@ import HsBinds #endif -#if __GLASGOW_HASKELL__ >= 902+#if __GLASGOW_HASKELL__ >= 904+import GHC.Parser.Annotation+#elif __GLASGOW_HASKELL__ >= 902 import Language.Haskell.Syntax.Extension import GHC.Parser.Annotation #endif@@ -77,11 +79,16 @@ printBind (L _ FunBind{fun_id = L _ name}) = liftIO $ putStr $ (getOccString name ++ " ")+printBind (L _ (VarBind {var_id = name})) = liftIO $ putStr $ (getOccString name ++ " ")+#if __GLASGOW_HASKELL__ < 904 printBind (L _ (AbsBinds {abs_exports = exp})) = +#else+printBind (L _ (XHsBindsLR (AbsBinds {abs_exports = exp}))) = +#endif mapM_ (\ e -> liftIO $ putStr $ ((getOccString $ abe_poly e) ++ " ")) exp-printBind (L _ (VarBind {var_id = name})) = liftIO $ putStr $ (getOccString name ++ " ") printBind _ = return () + -- | Computes the variables that are bound by a given piece of syntax. class HasBV a where@@ -89,12 +96,16 @@ instance HasBV (HsBindLR GhcTc GhcTc) where getBV (FunBind{fun_id = L _ v}) = Set.singleton v- getBV (AbsBinds {abs_exports = es}) = Set.fromList (map abe_poly es) getBV (PatBind {pat_lhs = pat}) = getBV pat getBV (VarBind {var_id = v}) = Set.singleton v getBV PatSynBind{} = Set.empty #if __GLASGOW_HASKELL__ < 900 getBV (XHsBindsLR e) = getBV e+ getBV (AbsBinds {abs_exports = es}) = Set.fromList (map abe_poly es)+#elif __GLASGOW_HASKELL__ < 904+ getBV (AbsBinds {abs_exports = es}) = Set.fromList (map abe_poly es)+#else+ getBV (XHsBindsLR (AbsBinds {abs_exports = es})) = Set.fromList (map abe_poly es) #endif instance HasBV a => HasBV (GenLocated b a) where@@ -103,7 +114,11 @@ instance HasBV a => HasBV [a] where getBV ps = foldl (\s p -> getBV p `Set.union` s) Set.empty ps -+#if __GLASGOW_HASKELL__ >= 904+getRecFieldRhs = hfbRHS+#else+getRecFieldRhs = hsRecFieldArg+#endif #if __GLASGOW_HASKELL__ >= 902 getConBV (PrefixCon _ ps) = getBV ps@@ -112,35 +127,54 @@ #endif getConBV (InfixCon p p') = getBV p `Set.union` getBV p' getConBV (RecCon (HsRecFields {rec_flds = fs})) = foldl run Set.empty fs- where run s (L _ f) = getBV (hsRecFieldArg f) `Set.union` s+ where run s (L _ f) = getBV (getRecFieldRhs f) `Set.union` s -#if __GLASGOW_HASKELL__ >= 900+#if __GLASGOW_HASKELL__ >= 900 && __GLASGOW_HASKELL__ < 904 instance HasBV CoPat where getBV CoPat {co_pat_inner = p} = getBV p+#elif __GLASGOW_HASKELL__ >= 904+instance HasBV XXPatGhcTc where+ getBV CoPat {co_pat_inner = p} = getBV p+ getBV (ExpansionPat _ p) = getBV p #endif instance HasBV (Pat GhcTc) where getBV (VarPat _ (L _ v)) = Set.singleton v getBV (LazyPat _ p) = getBV p+#if __GLASGOW_HASKELL__ >= 906+ getBV (AsPat _ (L _ v) _ p) = Set.insert v (getBV p)+#else getBV (AsPat _ (L _ v) p) = Set.insert v (getBV p)- getBV (ParPat _ p) = getBV p+#endif getBV (BangPat _ p) = getBV p getBV (ListPat _ ps) = getBV ps getBV (TuplePat _ ps _) = getBV ps getBV (SumPat _ p _ _) = getBV p getBV (ViewPat _ _ p) = getBV p+ getBV (SplicePat _ sp) = case sp of+#if __GLASGOW_HASKELL__ < 906 HsTypedSplice _ _ v _ -> Set.singleton v+ HsSpliced _ _ (HsSplicedPat p) -> getBV p HsUntypedSplice _ _ v _ -> Set.singleton v HsQuasiQuote _ p p' _ _ -> Set.fromList [p,p']- HsSpliced _ _ (HsSplicedPat p) -> getBV p _ -> Set.empty+#else+ HsUntypedSpliceExpr _ e -> getFV e+ HsQuasiQuote _ v _ -> Set.singleton v+#endif+ getBV (NPlusKPat _ (L _ v) _ _ _ _) = Set.singleton v getBV (NPat {}) = Set.empty getBV (XPat p) = getBV p getBV (WildPat {}) = Set.empty getBV (LitPat {}) = Set.empty+#if __GLASGOW_HASKELL__ >= 904 + getBV (ParPat _ _ p _) = getBV p+#else+ getBV (ParPat _ p) = getBV p+#endif #if __GLASGOW_HASKELL__ >= 900 getBV (ConPat {pat_args = con}) = getConBV con #else@@ -154,14 +188,16 @@ getBV (SigPat _ p) = getBV p #endif +#if __GLASGOW_HASKELL__ >= 904 -#if __GLASGOW_HASKELL__ >= 810+#elif __GLASGOW_HASKELL__ >= 810 instance HasBV NoExtCon where #else instance HasBV NoExt where #endif+#if __GLASGOW_HASKELL__ < 904 getBV _ = Set.empty-+#endif -- | Syntax that may contain variables. class HasFV a where@@ -235,8 +271,12 @@ getFV FunBind {fun_matches = ms} = getFV ms getFV PatBind {pat_rhs = rhs} = getFV rhs getFV VarBind {var_rhs = rhs} = getFV rhs- getFV AbsBinds {abs_binds = bs} = getFV bs getFV PatSynBind {} = Set.empty+#if __GLASGOW_HASKELL__ < 904+ getFV AbsBinds {abs_binds = bs} = getFV bs+#else+ getFV (XHsBindsLR AbsBinds {abs_binds = bs}) = getFV bs+#endif #if __GLASGOW_HASKELL__ < 900 getFV (XHsBindsLR e) = getFV e #endif@@ -295,21 +335,26 @@ #endif getFV HsRecFields{rec_flds = fs} = getFV fs --#if __GLASGOW_HASKELL__ >= 902+#if __GLASGOW_HASKELL__ >= 904+instance HasFV (HsFieldBind o (GenLocated SrcSpanAnnA (HsExpr GhcTc))) where+#elif __GLASGOW_HASKELL__ >= 902 instance HasFV (HsRecField' o (GenLocated SrcSpanAnnA (HsExpr GhcTc))) where #else instance HasFV (HsRecField' o (LHsExpr GhcTc)) where #endif- getFV HsRecField {hsRecFieldArg = arg} = getFV arg+ getFV rf = getFV (getRecFieldRhs rf) instance HasFV (ArithSeqInfo GhcTc) where getFV (From e) = getFV e getFV (FromThen e1 e2) = getFV e1 `Set.union` getFV e2 getFV (FromTo e1 e2) = getFV e1 `Set.union` getFV e2 getFV (FromThenTo e1 e2 e3) = getFV e1 `Set.union` getFV e2 `Set.union` getFV e3-+ +#if __GLASGOW_HASKELL__ >= 904+instance HasFV (HsQuote GhcTc) where+#else instance HasFV (HsBracket GhcTc) where+#endif getFV (ExpBr _ e) = getFV e getFV (VarBr _ _ e) = getFV e getFV _ = Set.empty@@ -319,12 +364,19 @@ getFV (HsCmdArrForm _ e _ _ cmd) = getFV e `Set.union` getFV cmd getFV (HsCmdApp _ e1 e2) = getFV e1 `Set.union` getFV e2 getFV (HsCmdLam _ l) = getFV l- getFV (HsCmdPar _ cmd) = getFV cmd getFV (HsCmdCase _ _ mg) = getFV mg getFV (HsCmdIf _ _ e1 e2 e3) = getFV e1 `Set.union` getFV e2 `Set.union` getFV e3- getFV (HsCmdLet _ bs _) = getFV bs getFV (HsCmdDo _ cmd) = getFV cmd-#if __GLASGOW_HASKELL__ >= 900+#if __GLASGOW_HASKELL__ >= 904+ getFV (HsCmdPar _ _ cmd _) = getFV cmd+ getFV (HsCmdLet _ _ bs _ _) = getFV bs+#else+ getFV (HsCmdPar _ cmd) = getFV cmd+ getFV (HsCmdLet _ bs _) = getFV bs+#endif+#if __GLASGOW_HASKELL__ >= 904+ getFV (HsCmdLamCase _ _ mg) = getFV mg+#elif __GLASGOW_HASKELL__ >= 900 getFV (HsCmdLamCase _ mg) = getFV mg #else getFV (HsCmdWrap _ _ cmd) = getFV cmd@@ -341,25 +393,20 @@ instance HasFV (HsExpr GhcTc) where getFV (HsVar _ v) = getFV v getFV HsUnboundVar {} = Set.empty- getFV HsConLikeOut {} = Set.empty- getFV HsRecFld {} = Set.empty getFV HsOverLabel {} = Set.empty getFV HsIPVar {} = Set.empty getFV HsOverLit {} = Set.empty getFV HsLit {} = Set.empty getFV (HsLam _ mg) = getFV mg- getFV (HsLamCase _ mg) = getFV mg getFV (HsApp _ e1 e2) = getFV e1 `Set.union` getFV e2 getFV (OpApp _ e1 e2 e3) = getFV e1 `Set.union` getFV e2 `Set.union` getFV e3 getFV (NegApp _ e _) = getFV e- getFV (HsPar _ e) = getFV e getFV (SectionL _ e1 e2) = getFV e1 `Set.union` getFV e2 getFV (SectionR _ e1 e2) = getFV e1 `Set.union` getFV e2 getFV (ExplicitTuple _ es _) = getFV es getFV (ExplicitSum _ _ _ e) = getFV e getFV (HsCase _ e mg) = getFV e `Set.union` getFV mg getFV (HsMultiIf _ es) = getFV es- getFV (HsLet _ bs e) = getFV bs `Set.union` getFV e getFV (HsDo _ _ e) = getFV e #if __GLASGOW_HASKELL__ >= 902 getFV HsProjection {} = Set.empty@@ -373,17 +420,39 @@ #endif getFV (RecordCon {rcon_flds = fs}) = getFV fs getFV (ArithSeq _ _ e) = getFV e- getFV (HsBracket _ e) = getFV e- getFV HsRnBracketOut {} = Set.empty- getFV HsTcBracketOut {} = Set.empty+#if __GLASGOW_HASKELL__ >= 906+ getFV HsTypedSplice{} = Set.empty+ getFV HsUntypedSplice{} = Set.empty+#else getFV HsSpliceE{} = Set.empty+#endif getFV (HsProc _ _ e) = getFV e- getFV (HsStatic _ e) = getFV e - getFV (HsTick _ _ e) = getFV e- getFV (HsBinTick _ _ _ e) = getFV e+ getFV (HsStatic _ e) = getFV e getFV (XExpr e) = getFV e- -#if __GLASGOW_HASKELL__ >= 808+#if __GLASGOW_HASKELL__ >= 904+ getFV (HsPar _ _ e _) = getFV e + getFV (HsLamCase _ _ mg) = getFV mg+ getFV (HsLet _ _ bs _ e) = getFV bs `Set.union` getFV e+ getFV HsRecSel {} = Set.empty+ getFV (HsTypedBracket _ e) = getFV e+ getFV (HsUntypedBracket _ e) = getFV e+#else + getFV (HsBinTick _ _ _ e) = getFV e+ getFV (HsTick _ _ e) = getFV e+ getFV (HsLet _ bs e) = getFV bs `Set.union` getFV e+ getFV (HsPar _ e) = getFV e+ getFV (HsLamCase _ mg) = getFV mg+ getFV HsConLikeOut {} = Set.empty+ getFV HsRecFld {} = Set.empty+ getFV (HsBracket _ e) = getFV e+ getFV HsRnBracketOut {} = Set.empty+ getFV HsTcBracketOut {} = Set.empty+#endif++#if __GLASGOW_HASKELL__ >= 906+ getFV (HsAppType _ e _ _) = getFV e+ getFV (ExprWithTySig _ e _) = getFV e +#elif __GLASGOW_HASKELL__ >= 808 getFV (HsAppType _ e _) = getFV e getFV (ExprWithTySig _ e _) = getFV e #else@@ -416,6 +485,12 @@ instance HasFV XXExprGhcTc where getFV (WrapExpr e) = getFV e getFV (ExpansionExpr (HsExpanded _e1 e2)) = getFV e2+#if __GLASGOW_HASKELL__ >= 904 + getFV (HsTick _ e) = getFV e+ getFV (HsBinTick _ _ e) = getFV e+ getFV ConLikeTc{} = Set.empty+#endif+ instance HasFV (e GhcTc) => HasFV (HsWrap e) where getFV (HsWrap _ e) = getFV e
src/Rattus/Plugin/ScopeCheck.hs view
@@ -5,6 +5,7 @@ {-# LANGUAGE TupleSections #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ImplicitParams #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE CPP #-} @@ -62,6 +63,8 @@ import Data.Either import Data.Maybe +import Data.Data hiding (tyConName)+ import Control.Monad type ErrorMsg = (Severity,SrcSpan,SDoc)@@ -100,7 +103,9 @@ -- | This flag indicates whether the context was 'stabilized' -- (stripped of all non-stable stuff). It is set when typechecking -- 'box', 'arr' and guarded recursion.- stabilized :: Maybe StableReason}+ stabilized :: Maybe StableReason,+ -- | Allow general recursion.+ allowRecursion :: Bool} @@ -108,8 +113,8 @@ -- non-recursive definitions, the argument is @Nothing@. Otherwise, it -- contains the recursively defined variables along with the location -- of the recursive definition.-emptyCtxt :: ErrorMsgsRef -> Maybe (Set Var,SrcSpan) -> Ctxt-emptyCtxt em mvar =+emptyCtxt :: ErrorMsgsRef -> Maybe (Set Var,SrcSpan) -> Bool -> Ctxt+emptyCtxt em mvar allowRec = Ctxt { errorMsgs = em, current = Set.empty, earlier = Left NoDelay,@@ -120,7 +125,8 @@ stableTypes = Set.empty, stabilized = case mvar of Just (_,loc) -> Just (StableRec loc)- _ -> Nothing}+ _ -> Nothing,+ allowRecursion = allowRec} -- | A local context, consisting of a set of variables. type LCtxt = Set Var@@ -336,8 +342,13 @@ checkPatBind' PatBind{} = do printMessage' SevError ("(Mutual) recursive pattern binding definitions are not supported in Rattus") return False- -checkPatBind' AbsBinds {abs_binds = binds} = liftM and (mapM checkPatBind (bagToList binds))+#if __GLASGOW_HASKELL__ < 904+checkPatBind' AbsBinds {abs_binds = binds} = +#else+checkPatBind' (XHsBindsLR AbsBinds {abs_binds = binds}) = +#endif+ liftM and (mapM checkPatBind (bagToList binds))+ checkPatBind' _ = return True @@ -390,11 +401,15 @@ getAllBV :: GenLocated l (HsBindLR GhcTc GhcTc) -> Set Var getAllBV (L _ b) = getAllBV' b where getAllBV' (FunBind{fun_id = L _ v}) = Set.singleton v+#if __GLASGOW_HASKELL__ < 904 getAllBV' (AbsBinds {abs_exports = es, abs_binds = bs}) = Set.fromList (map abe_poly es) `Set.union` foldMap getBV bs+ getAllBV' XHsBindsLR{} = Set.empty+#else+ getAllBV' (XHsBindsLR (AbsBinds {abs_exports = es, abs_binds = bs})) = Set.fromList (map abe_poly es) `Set.union` foldMap getBV bs+#endif getAllBV' (PatBind {pat_lhs = pat}) = getBV pat getAllBV' (VarBind {var_id = v}) = Set.singleton v getAllBV' PatSynBind{} = Set.empty- getAllBV' XHsBindsLR{} = Set.empty -- Check nested bindings@@ -508,26 +523,42 @@ <> " There is a delay, but its scope is interrupted by " <> tickHidden hr <> ".") _ -> liftM2 (&&) (check e1) (check e2) check HsUnboundVar{} = return True+#if __GLASGOW_HASKELL__ >= 904+ check (HsPar _ _ e _) = check e+ check (HsLamCase _ _ mg) = check mg+ check HsRecSel{} = return True+ check HsTypedBracket{} = notSupported "MetaHaskell"+ check HsUntypedBracket{} = notSupported "MetaHaskell"+#else check HsConLikeOut{} = return True check HsRecFld{} = return True+ check (HsPar _ e) = check e+ check (HsLamCase _ mg) = check mg+ check HsBracket{} = notSupported "MetaHaskell"+ check (HsTick _ _ e) = check e+ check (HsBinTick _ _ _ e) = check e+ check HsRnBracketOut{} = notSupported "MetaHaskell"+ check HsTcBracketOut{} = notSupported "MetaHaskell"+#endif+#if __GLASGOW_HASKELL__ >= 904+ check (HsLet _ _ bs _ e) = do+#else+ check (HsLet _ bs e) = do+#endif+ (l,vs) <- checkBind bs+ r <- addVars vs `modifyCtxt` (check e)+ return (r && l)+ check HsOverLabel{} = return True check HsIPVar{} = notSupported "implicit parameters" check HsOverLit{} = return True - check (HsTick _ _ e) = check e- check (HsBinTick _ _ _ e) = check e - check (HsPar _ e) = check e check HsLit{} = return True check (OpApp _ e1 e2 e3) = and <$> mapM check [e1,e2,e3] check (HsLam _ mg) = check mg- check (HsLamCase _ mg) = check mg check (HsCase _ e1 e2) = (&&) <$> check e1 <*> check e2 check (SectionL _ e1 e2) = (&&) <$> check e1 <*> check e2 check (SectionR _ e1 e2) = (&&) <$> check e1 <*> check e2 check (ExplicitTuple _ e _) = check e- check (HsLet _ bs e) = do- (l,vs) <- checkBind bs- r <- addVars vs `modifyCtxt` (check e)- return (r && l) check (NegApp _ e _) = check e check (ExplicitSum _ _ _ e) = check e check (HsMultiIf _ e) = check e@@ -542,16 +573,21 @@ #endif check RecordCon { rcon_flds = f} = check f check (ArithSeq _ _ e) = check e- check HsBracket{} = notSupported "MetaHaskell"- check HsRnBracketOut{} = notSupported "MetaHaskell"- check HsTcBracketOut{} = notSupported "MetaHaskell"+#if __GLASGOW_HASKELL__ >= 906+ check HsTypedSplice{} = notSupported "Template Haskell"+ check HsUntypedSplice{} = notSupported "Template Haskell"+#else check HsSpliceE{} = notSupported "Template Haskell"+#endif check (HsProc _ p e) = mod `modifyCtxt` check e where mod c = addVars (getBV p) (stabilize StableArr c) check (HsStatic _ e) = check e check (HsDo _ _ e) = fst <$> checkBind e check (XExpr e) = check e-#if __GLASGOW_HASKELL__ >= 808+#if __GLASGOW_HASKELL__ >= 906+ check (HsAppType _ e _ _) = check e+ check (ExprWithTySig _ e _) = check e+#elif __GLASGOW_HASKELL__ >= 808 check (HsAppType _ e _) = check e check (ExprWithTySig _ e _) = check e #else@@ -585,6 +621,11 @@ instance Scope XXExprGhcTc where check (WrapExpr (HsWrap _ e)) = check e check (ExpansionExpr (HsExpanded _ e)) = check e+#if __GLASGOW_HASKELL__ >= 904+ check ConLikeTc{} = return True+ check (HsTick _ e) = check e+ check (HsBinTick _ _ e) = check e+#endif #elif __GLASGOW_HASKELL__ >= 810 instance Scope NoExtCon where check _ = return True@@ -605,16 +646,25 @@ check (HsCmdArrForm _ e1 _ _ e2) = (&&) <$> check e1 <*> check e2 check (HsCmdApp _ e1 e2) = (&&) <$> check e1 <*> check e2 check (HsCmdLam _ e) = check e+#if __GLASGOW_HASKELL__ >= 904+ check (HsCmdPar _ _ e _) = check e+ check (HsCmdLamCase _ _ e) = check e + check (HsCmdLet _ _ bs _ e) = do+#else check (HsCmdPar _ e) = check e- check (HsCmdCase _ e1 e2) = (&&) <$> check e1 <*> check e2- check (HsCmdIf _ _ e1 e2 e3) = (&&) <$> ((&&) <$> check e1 <*> check e2) <*> check e3+#if __GLASGOW_HASKELL__ >= 900+ check (HsCmdLamCase _ e) = check e+#endif check (HsCmdLet _ bs e) = do+#endif (l,vs) <- checkBind bs r <- addVars vs `modifyCtxt` (check e) return (r && l)++ check (HsCmdCase _ e1 e2) = (&&) <$> check e1 <*> check e2+ check (HsCmdIf _ _ e1 e2 e3) = (&&) <$> ((&&) <$> check e1 <*> check e2) <*> check e3 #if __GLASGOW_HASKELL__ >= 900 check (XCmd (HsWrap _ e)) = check e- check (HsCmdLamCase _ e) = check e #else check (HsCmdWrap _ _ e) = check e check XCmd{} = return True@@ -630,8 +680,15 @@ instance Scope a => Scope (HsRecFields GhcTc a) where check HsRecFields {rec_flds = fs} = check fs +++#if __GLASGOW_HASKELL__ >= 904+instance Scope b => Scope (HsFieldBind a b) where+ check HsFieldBind{hfbRHS = a} = check a+#else instance Scope b => Scope (HsRecField' a b) where check HsRecField{hsRecFieldArg = a} = check a+#endif instance Scope (HsTupArg GhcTc) where check (Present _ e) = check e@@ -641,9 +698,14 @@ #endif instance Scope (HsBindLR GhcTc GhcTc) where- check AbsBinds {abs_binds = binds, abs_ev_vars = ev} = mod `modifyCtxt` check binds- where mod c = c { stableTypes= stableTypes c `Set.union`- Set.fromList (mapMaybe (isStableConstr . varType) ev)}+#if __GLASGOW_HASKELL__ >= 904+ check (XHsBindsLR AbsBinds {abs_binds = binds, abs_ev_vars = ev})+#else+ check AbsBinds {abs_binds = binds, abs_ev_vars = ev}+#endif+ = mod `modifyCtxt` check binds+ where mod c = c { stableTypes= stableTypes c `Set.union`+ Set.fromList (mapMaybe (isStableConstr . varType) ev)} check FunBind{fun_matches= matches, fun_id = L _ v, #if __GLASGOW_HASKELL__ >= 900 fun_ext = wrapper} =@@ -652,7 +714,7 @@ #endif mod `modifyCtxt` check matches where mod c = c { stableTypes= stableTypes c `Set.union`- Set.fromList (stableConstrFromWrapper wrapper) `Set.union`+ Set.fromList (stableConstrFromWrapper' wrapper) `Set.union` Set.fromList (extractStableConstr (varType v))} check PatBind{pat_lhs = lhs, pat_rhs=rhs} = addVars (getBV lhs) `modifyCtxt` check rhs check VarBind{var_rhs = rhs} = check rhs@@ -678,6 +740,15 @@ _ -> Nothing ++#if __GLASGOW_HASKELL__ >= 906+stableConstrFromWrapper' :: (HsWrapper , a) -> [TyVar]+stableConstrFromWrapper' (x , _) = stableConstrFromWrapper x+#else+stableConstrFromWrapper' :: HsWrapper -> [TyVar]+stableConstrFromWrapper' = stableConstrFromWrapper+#endif+ stableConstrFromWrapper :: HsWrapper -> [TyVar] stableConstrFromWrapper (WpCompose v w) = stableConstrFromWrapper v ++ stableConstrFromWrapper w stableConstrFromWrapper (WpEvLam v) = maybeToList $ isStableConstr (varType v)@@ -704,9 +775,10 @@ checkSCC' :: Module -> AnnEnv -> SCC (LHsBindLR GhcTc GhcTc, Set Var) -> TcM (Bool, [ErrorMsg]) checkSCC' mod anEnv scc = do err <- liftIO (newIORef [])- res <- checkSCC err scc+ let allowRec = AllowRecursion `Set.member` getAnn mod anEnv scc+ res <- checkSCC allowRec err scc msgs <- liftIO (readIORef err)- let anns = getInternalAnn mod anEnv scc+ let anns = getAnn mod anEnv scc if ExpectWarning `Set.member` anns then if ExpectError `Set.member` anns then return (False,[(SevError, getSCCLoc scc, "Annotation to expect both warning and error is not allowed.")])@@ -719,16 +791,15 @@ else return (True,[]) else return (res, msgs) --getInternalAnn :: Module -> AnnEnv -> SCC (LHsBindLR GhcTc GhcTc, Set Var) -> Set InternalAnn-getInternalAnn mod anEnv scc =+getAnn :: forall a . (Data a, Ord a) => Module -> AnnEnv -> SCC (LHsBindLR GhcTc GhcTc, Set Var) -> Set a+getAnn mod anEnv scc = case scc of (AcyclicSCC (_,vs)) -> Set.unions $ Set.map checkVar vs (CyclicSCC bs) -> Set.unions $ map (Set.unions . Set.map checkVar . snd) bs- where checkVar :: Var -> Set InternalAnn+ where checkVar :: Var -> Set a checkVar v =- let anns = findAnns deserializeWithData anEnv (NamedTarget name) :: [InternalAnn]- annsMod = findAnns deserializeWithData anEnv (ModuleTarget mod) :: [InternalAnn]+ let anns = findAnns deserializeWithData anEnv (NamedTarget name) :: [a]+ annsMod = findAnns deserializeWithData anEnv (ModuleTarget mod) :: [a] name :: Name name = varName v in Set.fromList anns `Set.union` Set.fromList annsMod@@ -739,13 +810,13 @@ -- non-recursive definition or a group of (mutual) recursive -- definitions. -checkSCC :: ErrorMsgsRef -> SCC (LHsBindLR GhcTc GhcTc, Set Var) -> TcM Bool-checkSCC errm (AcyclicSCC (b,_)) = setCtxt (emptyCtxt errm Nothing) (check b)+checkSCC :: Bool -> ErrorMsgsRef -> SCC (LHsBindLR GhcTc GhcTc, Set Var) -> TcM Bool+checkSCC allowRec errm (AcyclicSCC (b,_)) = setCtxt (emptyCtxt errm Nothing allowRec) (check b) -checkSCC errm (CyclicSCC bs) = (fmap and (mapM check' bs'))+checkSCC allowRec errm (CyclicSCC bs) = (fmap and (mapM check' bs')) where bs' = map fst bs vs = foldMap snd bs- check' b@(L l _) = setCtxt (emptyCtxt errm (Just (vs,getLocAnn' l))) (checkRec b)+ check' b@(L l _) = setCtxt (emptyCtxt errm (Just (vs,getLocAnn' l)) allowRec) (checkRec b) -- | Stabilizes the given context, i.e. remove all non-stable types -- and any tick. This is performed on checking 'box', 'arr' and@@ -767,8 +838,8 @@ getScope :: GetCtxt => Var -> VarScope getScope v = case ?ctxt of- Ctxt{recDef = Just (vs,_), earlier = e}- | v `Set.member` vs ->+ Ctxt{recDef = Just (vs,_), earlier = e, allowRecursion = allowRec} | v `Set.member` vs ->+ if allowRec then Visible else case e of Right _ -> Visible Left NoDelay -> Hidden ("The (mutually) recursive call to " <> ppr v <> " must occur in the scope of a delay")@@ -776,7 +847,7 @@ <> "There is a delay, but its scope is interrupted by " <> tickHidden hr <> ".") _ -> case Map.lookup v (hidden ?ctxt) of Just (Stabilize (StableRec rv)) ->- if (isStable (stableTypes ?ctxt) (varType v)) then Visible+ if (isStable (stableTypes ?ctxt) (varType v)) || allowRecursion ?ctxt then Visible else Hidden ("Variable " <> ppr v <> " is no longer in scope:" $$ "It appears in a local recursive definition (at " <> ppr rv <> ")" $$ "and is of type " <> ppr (varType v) <> ", which is not stable.")@@ -828,7 +899,9 @@ isPrimExpr (L _ e) = isPrimExpr' e where isPrimExpr' :: GetCtxt => HsExpr GhcTc -> Maybe (Prim,Var) isPrimExpr' (HsVar _ (L _ v)) = fmap (,v) (isPrim v)-#if __GLASGOW_HASKELL__ >= 808+#if __GLASGOW_HASKELL__ >= 906+ isPrimExpr' (HsAppType _ e _ _) = isPrimExpr e+#elif __GLASGOW_HASKELL__ >= 808 isPrimExpr' (HsAppType _ e _) = isPrimExpr e #else isPrimExpr' (HsAppType _ e) = isPrimExpr e@@ -844,9 +917,15 @@ isPrimExpr' (XExpr (ExpansionExpr (HsExpanded _ e))) = isPrimExpr' e isPrimExpr' (HsPragE _ _ e) = isPrimExpr e #endif+#if __GLASGOW_HASKELL__ < 904 isPrimExpr' (HsTick _ _ e) = isPrimExpr e- isPrimExpr' (HsBinTick _ _ _ e) = isPrimExpr e + isPrimExpr' (HsBinTick _ _ _ e) = isPrimExpr e isPrimExpr' (HsPar _ e) = isPrimExpr e+#else+ isPrimExpr' (XExpr (HsTick _ e)) = isPrimExpr e+ isPrimExpr' (XExpr (HsBinTick _ _ e)) = isPrimExpr e+ isPrimExpr' (HsPar _ _ e _) = isPrimExpr e+#endif isPrimExpr' _ = Nothing
src/Rattus/Plugin/StableSolver.hs view
@@ -37,8 +37,9 @@ import Data.Set (Set) import qualified Data.Set as Set--+#if __GLASGOW_HASKELL__ >= 904+import GHC.Types.Unique.FM+#endif @@ -48,6 +49,9 @@ { tcPluginInit = return () , tcPluginSolve = \ () -> stableSolver , tcPluginStop = \ () -> return ()+#if __GLASGOW_HASKELL__ >= 904+ , tcPluginRewrite = \ () -> emptyUFM+#endif } @@ -63,8 +67,14 @@ | isStable c ty = Just (wrap cl ty, ct) | otherwise = Nothing +#if __GLASGOW_HASKELL__ >= 904+stableSolver :: EvBindsVar -> [Ct] -> [Ct] -> TcPluginM TcPluginSolveResult+stableSolver _ given wanted = do+#else stableSolver :: [Ct] -> [Ct] -> [Ct] -> TcPluginM TcPluginResult stableSolver given _derived wanted = do+#endif+ let chSt = concatMap filterCt wanted let haveSt = Set.fromList $ concatMap (filterTypeVar . fst) $ concatMap filterCt given case mapM (solveStable haveSt) chSt of
src/Rattus/Plugin/Utils.hs view
@@ -22,6 +22,13 @@ getAlt, splitForAllTys') where+#if __GLASGOW_HASKELL__ >= 906+import GHC.Builtin.Types.Prim+import GHC.Tc.Utils.TcType+#endif+#if __GLASGOW_HASKELL__ >= 904+import qualified GHC.Data.Strict as Strict+#endif #if __GLASGOW_HASKELL__ >= 902 import GHC.Utils.Logger #endif@@ -36,6 +43,8 @@ import MonadUtils #endif ++ import Prelude hiding ((<>)) import Data.Set (Set)@@ -50,6 +59,11 @@ isType _ = False +#if __GLASGOW_HASKELL__ >= 906+isFunTyCon = isArrowTyCon+repSplitAppTys = splitAppTysNoView+#endif+ #if __GLASGOW_HASKELL__ >= 902 printMessage :: (HasDynFlags m, MonadIO m, HasLogger m) => Severity -> SrcSpan -> SDoc -> m ()@@ -58,7 +72,15 @@ Severity -> SrcSpan -> MsgDoc -> m () #endif printMessage sev loc doc = do-#if __GLASGOW_HASKELL__ >= 902+#if __GLASGOW_HASKELL__ >= 906+ logger <- getLogger+ liftIO $ putLogMsg logger (logFlags logger)+ (MCDiagnostic sev (if sev == SevError then ErrorWithoutFlag else WarningWithoutFlag) Nothing) loc doc+#elif __GLASGOW_HASKELL__ >= 904+ logger <- getLogger+ liftIO $ putLogMsg logger (logFlags logger)+ (MCDiagnostic sev (if sev == SevError then ErrorWithoutFlag else WarningWithoutFlag)) loc doc+#elif __GLASGOW_HASKELL__ >= 902 dflags <- getDynFlags logger <- getLogger liftIO $ putLogMsg logger dflags NoReason sev loc doc@@ -274,14 +296,16 @@ mkSysLocalFromExpr :: MonadUnique m => FastString -> CoreExpr -> m Id #if __GLASGOW_HASKELL__ >= 900-mkSysLocalFromExpr lit e = mkSysLocalM lit One (exprType e)+mkSysLocalFromExpr lit e = mkSysLocalM lit oneDataConTy (exprType e) #else mkSysLocalFromExpr lit e = mkSysLocalM lit (exprType e) #endif fromRealSrcSpan :: RealSrcSpan -> SrcSpan-#if __GLASGOW_HASKELL__ >= 900+#if __GLASGOW_HASKELL__ >= 904+fromRealSrcSpan span = RealSrcSpan span Strict.Nothing+#elif __GLASGOW_HASKELL__ >= 900 fromRealSrcSpan span = RealSrcSpan span Nothing #else fromRealSrcSpan span = RealSrcSpan span
src/Rattus/Strict.hs view
@@ -1,3 +1,5 @@+{-# OPTIONS -fplugin=Rattus.Plugin #-}+ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeOperators #-}@@ -10,6 +12,8 @@ module Rattus.Strict ( List(..),+ init',+ listDelay, reverse', (+++), listToMaybe',@@ -22,12 +26,33 @@ )where import Data.VectorSpace+import Rattus.Primitives+import Rattus.Plugin.Annotation infixr 2 :* infixr 8 :! -- | Strict list type. data List a = Nil | !a :! !(List a)+++{-# ANN module Rattus #-}+-- All recursive functions in this module are defined by structural+-- induction on a strict type.+{-# ANN module AllowRecursion #-}++-- | Turns a list of delayed computations into a delayed computation+-- that produces a list of values.+listDelay :: List (O a) -> O (List a)+listDelay Nil = delay Nil+listDelay (x :! xs) = let xs' = listDelay xs in delay (adv x :! adv xs')++-- | Remove the last element from a list if there is one, otherwise+-- return 'Nil'.+init' :: List a -> List a+init' Nil = Nil+init' (_ :! Nil) = Nil+init' (x :! xs) = x :! init' xs -- | Reverse a list. reverse' :: List a -> List a
src/Rattus/Yampa.hs view
@@ -61,7 +61,7 @@ -- | Compute the integral of a signal. The first argument is the -- offset.-integral :: (Stable a, VectorSpace a s) => a -> SF a a+integral :: (Stable a, VectorSpace a s, Fractional s) => a -> SF a a integral acc = SF sf' where sf' t a = let acc' = acc ^+^ (realToFrac t *^ a) in (delay (integral acc') :* acc')