@@ -101,17 +101,18 @@ import Reflex.NotReady.Class
101101import Reflex.Patch
102102import qualified Reflex.Patch.DMapWithMove as PatchDMapWithMove
103103
104+
105+
104106#ifdef DEBUG_TRACE_EVENTS
105107import qualified Data.ByteString.Char8 as BS8
106108import System.IO (stderr)
107−#endif
108−
109−#ifdef DEBUG_TRACE_EVENTS
109+import Data.List (isPrefixOf)
110110
111111withStackOneLine :: (BS8.ByteString -> a) -> a
112112withStackOneLine expr = unsafePerformIO $ do
113113 stack <- currentCallStack
114− return (expr (BS8.pack (unwords (reverse stack))))
114+ return (expr . BS8.pack . unwords . dropInternal . reverse $ stack)
115+ where dropInternal = filter (not . isPrefixOf "Reflex.Spider.Internal")
115116
116117#endif
117118
@@ -277,13 +278,11 @@ cacheEvent e =
277278 occRef <- liftIO $ newIORef Nothing -- This should never be read prior to being set below
278279 (parentSub, occ) <- subscribeAndRead e $ Subscriber
279280 { subscriberPropagate = \a -> do
280− liftIO $ writeIORef occRef $ Just a
281+ liftIO $ writeIORef occRef (Just a)
281282 scheduleClear occRef
282283 propagateFast a subscribers
283− , subscriberInvalidateHeight = \old -> do
284− FastWeakBag.traverse subscribers $ invalidateSubscriberHeight old
285− , subscriberRecalculateHeight = \new -> do
286− FastWeakBag.traverse subscribers $ recalculateSubscriberHeight new
284+ , subscriberInvalidateHeight = FastWeakBag.traverse subscribers . invalidateSubscriberHeight
285+ , subscriberRecalculateHeight = FastWeakBag.traverse subscribers . recalculateSubscriberHeight
287286 }
288287 when (isJust occ) $ do
289288 liftIO $ writeIORef occRef occ -- Set the initial value of occRef; we don't need to do this if occ is Nothing
@@ -466,14 +465,14 @@ recalculateSubscriberHeight :: Height -> Subscriber x a -> IO ()
466465recalculateSubscriberHeight = flip subscriberRecalculateHeight
467466
468467-- | Propagate everything at the current height
469−propagate :: forall a x. HasSpiderTimeline x => a -> WeakBag (Subscriber x a) -> EventM x ()
468+propagate :: a -> WeakBag (Subscriber x a) -> EventM x ()
470469propagate a subscribers = withIncreasedDepth (Proxy::Proxy x) $ do
471470 -- Note: in the following traversal, we do not visit nodes that are added to the list during our traversal; they are new events, which will necessarily have full information already, so there is no need to traverse them
472471 --TODO: Should we check if nodes already have their values before propagating? Maybe we're re-doing work
473472 WeakBag.traverse subscribers $ \s -> subscriberPropagate s a
474473
475474-- | Propagate everything at the current height
476−propagateFast :: forall a x. HasSpiderTimeline x => a -> FastWeakBag (Subscriber x a) -> EventM x ()
475+propagateFast :: a -> FastWeakBag (Subscriber x a) -> EventM x ()
477476propagateFast a subscribers = withIncreasedDepth (Proxy::Proxy x) $ do
478477 -- Note: in the following traversal, we do not visit nodes that are added to the list during our traversal; they are new events, which will necessarily have full information already, so there is no need to traverse them
479478 --TODO: Should we check if nodes already have their values before propagating? Maybe we're re-doing work
@@ -1297,7 +1296,7 @@ traceM _ getMessage = do
12971296#else
12981297
12991298{-# INLINE withIncreasedDepth #-}
1300−withIncreasedDepth :: forall x m proxy a. HasSpiderTimeline x => proxy x -> m a -> m a
1299+withIncreasedDepth :: proxy x -> m a -> m a
13011300withIncreasedDepth _ = id
13021301
13031302{-# INLINE tracePropagate #-}
@@ -1309,7 +1308,7 @@ traceInvalidate :: String -> IO ()
13091308traceInvalidate _ = return ()
13101309
13111310{-# INLINE debugSubscriber #-}
1312−debugSubscriber :: HasSpiderTimeline x => String -> Subscriber x a -> IO (Subscriber x a)
1311+debugSubscriber :: String -> Subscriber x a -> IO (Subscriber x a)
13131312debugSubscriber _ = return
13141313
13151314{-# INLINE trace #-}
@@ -1861,6 +1860,23 @@ scheduleMergeSelf m height = scheduleMerge' height (_merge_heightRef m) $ do
18611860 --TODO: Assert that m is not empty
18621861 subscriberPropagate (_merge_sub m) vals
18631862
1863+checkCycle :: HasSpiderTimeline x => Height -> EventM x ()
1864+checkCycle height = do
1865+ currentHeight <- getCurrentHeight
1866+ when (height <= currentHeight) $ if height /= invalidHeight
1867+ then do
1868+ myStack <- liftIO $ whoCreatedIORef undefined --TODO
1869+ error $ "Height (" ++ show height ++ ") is not greater than current height (" ++ show currentHeight ++ ")\n" ++ unlines (reverse myStack)
1870+ else liftIO $ do
1871+#ifdef DEBUG_CYCLES
1872+ nodesInvolvedInCycle <- walkInvalidHeightParents $ eventSubscribedMerge subscribed
1873+ stacks <- forM nodesInvolvedInCycle $ \(Some es) -> whoCreatedEventSubscribed es
1874+ let cycleInfo = ":\n" <> drawForest (listsToForest stacks)
1875+#else
1876+ let cycleInfo = ""
1877+#endif
1878+ error $ "Causality loop found" <> cycleInfo
1879+
18641880mergeSubscriber :: forall x k v s a. (HasSpiderTimeline x, GCompare k) => Merge x k v s -> EventM x (k a) -> Subscriber x (v a)
18651881mergeSubscriber m getKey = Subscriber
18661882 { subscriberPropagate = \a -> do
@@ -1871,22 +1887,8 @@ mergeSubscriber m getKey = Subscriber
18711887 liftIO $ writeIORef (_merge_accumRef m) $! newM
18721888 when (DMap.null oldM) $ do -- Only schedule the firing once
18731889 height <- liftIO $ readIORef $ _merge_heightRef m
1874− --TODO: assertions about height
1875− currentHeight <- getCurrentHeight
1876− when (height <= currentHeight) $ do
1877− if height /= invalidHeight
1878− then do
1879− myStack <- liftIO $ whoCreatedIORef undefined --TODO
1880− error $ "Height (" ++ show height ++ ") is not greater than current height (" ++ show currentHeight ++ ")\n" ++ unlines (reverse myStack)
1881− else liftIO $ do
1882−#ifdef DEBUG_CYCLES
1883− nodesInvolvedInCycle <- walkInvalidHeightParents $ eventSubscribedMerge subscribed
1884− stacks <- forM nodesInvolvedInCycle $ \(Some es) -> whoCreatedEventSubscribed es
1885− let cycleInfo = ":\n" <> drawForest (listsToForest stacks)
1886−#else
1887− let cycleInfo = ""
1888−#endif
1889− error $ "Causality loop found" <> cycleInfo
1890+ checkCycle height --TODO: assertions about height
1891+
18901892 scheduleMergeSelf m height
18911893 , subscriberInvalidateHeight = \old -> do --TODO: When removing a parent doesn't actually change the height, maybe we can avoid invalidating
18921894 modifyIORef' (_merge_heightBagRef m) $ heightBagRemove old
@@ -1989,6 +1991,8 @@ mergeIntCheap d = Event $ \sub -> do
19891991 GT -> error $ "revalidateMergeHeight: more heights (" <> show (heightBagSize heights) <> ") than parents (" <> show numParents <> ") for Merge"
19901992 mySubscriber k = Subscriber
19911993 { subscriberPropagate = \a -> do
1994+ liftIO (readIORef heightRef) >>= checkCycle
1995+
19921996 wasEmpty <- liftIO $ FastMutableIntMap.isEmpty accum
19931997 liftIO $ FastMutableIntMap.insert accum k a
19941998 when wasEmpty scheduleSelf