@@ -101,17 +101,18 @@ import Reflex.NotReady.Class
101import Reflex.Patch
101import Reflex.Patch
102import qualified Reflex.Patch.DMapWithMove as PatchDMapWithMove
102import qualified Reflex.Patch.DMapWithMove as PatchDMapWithMove
104#ifdef DEBUG_TRACE_EVENTS
106#ifdef DEBUG_TRACE_EVENTS
105import qualified Data.ByteString.Char8 as BS8
107import qualified Data.ByteString.Char8 as BS8
106import System.IO (stderr)
108import System.IO (stderr)
107−#endif
109+import Data.List (isPrefixOf)
109−#ifdef DEBUG_TRACE_EVENTS
111withStackOneLine :: (BS8.ByteString -> a) -> a
111withStackOneLine :: (BS8.ByteString -> a) -> a
112withStackOneLine expr = unsafePerformIO $ do
112withStackOneLine expr = unsafePerformIO $ do
113 stack <- currentCallStack
113 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")
@@ -277,13 +278,11 @@ cacheEvent e =
277 occRef <- liftIO $ newIORef Nothing -- This should never be read prior to being set below
278 occRef <- liftIO $ newIORef Nothing -- This should never be read prior to being set below
278 (parentSub, occ) <- subscribeAndRead e $ Subscriber
279 (parentSub, occ) <- subscribeAndRead e $ Subscriber
279 { subscriberPropagate = \a -> do
280 { subscriberPropagate = \a -> do
280− liftIO $ writeIORef occRef $ Just a
281+ liftIO $ writeIORef occRef (Just a)
281 scheduleClear occRef
282 scheduleClear occRef
282 propagateFast a subscribers
283 propagateFast a subscribers
283− , subscriberInvalidateHeight = \old -> do
284− FastWeakBag.traverse subscribers $ invalidateSubscriberHeight old
284+ , subscriberInvalidateHeight = FastWeakBag.traverse subscribers . invalidateSubscriberHeight
285− , subscriberRecalculateHeight = \new -> do
286− FastWeakBag.traverse subscribers $ recalculateSubscriberHeight new
285+ , subscriberRecalculateHeight = FastWeakBag.traverse subscribers . recalculateSubscriberHeight
288 when (isJust occ) $ do
287 when (isJust occ) $ do
289 liftIO $ writeIORef occRef occ -- Set the initial value of occRef; we don't need to do this if occ is Nothing
288 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 ()
466recalculateSubscriberHeight = flip subscriberRecalculateHeight
465recalculateSubscriberHeight = flip subscriberRecalculateHeight
468-- | Propagate everything at the current height
467-- | 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 ()
470propagate a subscribers = withIncreasedDepth (Proxy::Proxy x) $ do
469propagate a subscribers = withIncreasedDepth (Proxy::Proxy x) $ do
471 -- 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
470 -- 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
472 --TODO: Should we check if nodes already have their values before propagating? Maybe we're re-doing work
471 --TODO: Should we check if nodes already have their values before propagating? Maybe we're re-doing work
473 WeakBag.traverse subscribers $ \s -> subscriberPropagate s a
472 WeakBag.traverse subscribers $ \s -> subscriberPropagate s a
475-- | Propagate everything at the current height
474-- | 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 ()
477propagateFast a subscribers = withIncreasedDepth (Proxy::Proxy x) $ do
476propagateFast a subscribers = withIncreasedDepth (Proxy::Proxy x) $ do
478 -- 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
477 -- 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
479 --TODO: Should we check if nodes already have their values before propagating? Maybe we're re-doing work
478 --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
1299{-# INLINE withIncreasedDepth #-}
1298{-# 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
1301withIncreasedDepth _ = id
1300withIncreasedDepth _ = id
1303{-# INLINE tracePropagate #-}
1302{-# INLINE tracePropagate #-}
@@ -1309,7 +1308,7 @@ traceInvalidate :: String -> IO ()
1309traceInvalidate _ = return ()
1308traceInvalidate _ = return ()
1311{-# INLINE debugSubscriber #-}
1310{-# INLINE debugSubscriber #-}
1312−debugSubscriber :: HasSpiderTimeline x => String -> Subscriber x a -> IO (Subscriber x a)
1311+debugSubscriber :: String -> Subscriber x a -> IO (Subscriber x a)
1313debugSubscriber _ = return
1312debugSubscriber _ = return
1315{-# INLINE trace #-}
1314{-# INLINE trace #-}
@@ -1861,6 +1860,23 @@ scheduleMergeSelf m height = scheduleMerge' height (_merge_heightRef m) $ do
1861 --TODO: Assert that m is not empty
1860 --TODO: Assert that m is not empty
1862 subscriberPropagate (_merge_sub m) vals
1861 subscriberPropagate (_merge_sub m) vals
1863+checkCycle :: HasSpiderTimeline x => Height -> EventM x ()
1864+checkCycle height = do
1865+ currentHeight <- getCurrentHeight
1866+ when (height <= currentHeight) $ if height /= invalidHeight
1868+ myStack <- liftIO $ whoCreatedIORef undefined --TODO
1869+ error $ "Height (" ++ show height ++ ") is not greater than current height (" ++ show currentHeight ++ ")\n" ++ unlines (reverse myStack)
1872+ nodesInvolvedInCycle <- walkInvalidHeightParents $ eventSubscribedMerge subscribed
1873+ stacks <- forM nodesInvolvedInCycle $ \(Some es) -> whoCreatedEventSubscribed es
1874+ let cycleInfo = ":\n" <> drawForest (listsToForest stacks)
1878+ error $ "Causality loop found" <> cycleInfo
1864mergeSubscriber :: forall x k v s a. (HasSpiderTimeline x, GCompare k) => Merge x k v s -> EventM x (k a) -> Subscriber x (v a)
1880mergeSubscriber :: forall x k v s a. (HasSpiderTimeline x, GCompare k) => Merge x k v s -> EventM x (k a) -> Subscriber x (v a)
1865mergeSubscriber m getKey = Subscriber
1881mergeSubscriber m getKey = Subscriber
1866 { subscriberPropagate = \a -> do
1882 { subscriberPropagate = \a -> do
@@ -1871,22 +1887,8 @@ mergeSubscriber m getKey = Subscriber
1871 liftIO $ writeIORef (_merge_accumRef m) $! newM
1887 liftIO $ writeIORef (_merge_accumRef m) $! newM
1872 when (DMap.null oldM) $ do -- Only schedule the firing once
1888 when (DMap.null oldM) $ do -- Only schedule the firing once
1873 height <- liftIO $ readIORef $ _merge_heightRef m
1889 height <- liftIO $ readIORef $ _merge_heightRef m
1874− --TODO: assertions about height
1890+ checkCycle height --TODO: assertions about height
1875− currentHeight <- getCurrentHeight
1891+
1876− when (height <= currentHeight) $ do
1877− if height /= invalidHeight
1879− myStack <- liftIO $ whoCreatedIORef undefined --TODO
1880− error $ "Height (" ++ show height ++ ") is not greater than current height (" ++ show currentHeight ++ ")\n" ++ unlines (reverse myStack)
1883− nodesInvolvedInCycle <- walkInvalidHeightParents $ eventSubscribedMerge subscribed
1884− stacks <- forM nodesInvolvedInCycle $ \(Some es) -> whoCreatedEventSubscribed es
1885− let cycleInfo = ":\n" <> drawForest (listsToForest stacks)
1889− error $ "Causality loop found" <> cycleInfo
1890 scheduleMergeSelf m height
1892 scheduleMergeSelf m height
1891 , subscriberInvalidateHeight = \old -> do --TODO: When removing a parent doesn't actually change the height, maybe we can avoid invalidating
1893 , subscriberInvalidateHeight = \old -> do --TODO: When removing a parent doesn't actually change the height, maybe we can avoid invalidating
1892 modifyIORef' (_merge_heightBagRef m) $ heightBagRemove old
1894 modifyIORef' (_merge_heightBagRef m) $ heightBagRemove old
@@ -1989,6 +1991,8 @@ mergeIntCheap d = Event $ \sub -> do
1989 GT -> error $ "revalidateMergeHeight: more heights (" <> show (heightBagSize heights) <> ") than parents (" <> show numParents <> ") for Merge"
1991 GT -> error $ "revalidateMergeHeight: more heights (" <> show (heightBagSize heights) <> ") than parents (" <> show numParents <> ") for Merge"
1990 mySubscriber k = Subscriber
1992 mySubscriber k = Subscriber
1991 { subscriberPropagate = \a -> do
1993 { subscriberPropagate = \a -> do
1994+ liftIO (readIORef heightRef) >>= checkCycle
1992 wasEmpty <- liftIO $ FastMutableIntMap.isEmpty accum
1996 wasEmpty <- liftIO $ FastMutableIntMap.isEmpty accum
1993 liftIO $ FastMutableIntMap.insert accum k a
1997 liftIO $ FastMutableIntMap.insert accum k a
1994 when wasEmpty scheduleSelf
1998 when wasEmpty scheduleSelf