Teo Camarasu pushed to branch wip/abstract-q at Glasgow Haskell Compiler / GHC
Commits:
-
6047c446
by Teo Camarasu at 2026-03-19T23:27:24+00:00
3 changed files:
- compiler/GHC/Tc/Gen/Splice.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Monad.hs
- libraries/ghci/GHCi/TH.hs
Changes:
| ... | ... | @@ -1140,7 +1140,7 @@ convertAnnotationWrapper fhv = do |
| 1140 | 1140 | -}
|
| 1141 | 1141 | |
| 1142 | 1142 | runQuasi :: TH.Q a -> TcM a
|
| 1143 | -runQuasi (TH.Q act) = unliftIOEnv $ \runInIO -> liftIO $ act runInIO metaHandlersTcM
|
|
| 1143 | +runQuasi (TH.Q act) = unliftIOEnv $ \runInIO -> liftIO $ act (metaHandlersTcM runInIO)
|
|
| 1144 | 1144 | |
| 1145 | 1145 | runRemoteModFinalizers :: ThModFinalizers -> TcM ()
|
| 1146 | 1146 | runRemoteModFinalizers (ThModFinalizers finRefs) = do
|
| ... | ... | @@ -1557,71 +1557,71 @@ location = do { m <- getModule |
| 1557 | 1557 | , TH.loc_start = (srcSpanStartLine r, srcSpanStartCol r)
|
| 1558 | 1558 | , TH.loc_end = (srcSpanEndLine r, srcSpanEndCol r) }) }
|
| 1559 | 1559 | |
| 1560 | -metaHandlersTcM :: TH.MetaHandlers TcM
|
|
| 1561 | -metaHandlersTcM = TH.MetaHandlers {
|
|
| 1562 | - mFail = fail
|
|
| 1563 | - , mNewName = \s -> do { u <- newUnique
|
|
| 1560 | +metaHandlersTcM :: (forall x. TcM x -> IO x) -> TH.MetaHandlers IO
|
|
| 1561 | +metaHandlersTcM runInIO = TH.MetaHandlers {
|
|
| 1562 | + mFail = \s -> runInIO $ fail s
|
|
| 1563 | + , mNewName = \s -> runInIO $ do { u <- newUnique
|
|
| 1564 | 1564 | ; let i = toInteger (getKey u)
|
| 1565 | 1565 | ; return (TH.mkNameU s i) }
|
| 1566 | 1566 | |
| 1567 | 1567 | -- 'msg' is forced to ensure exceptions don't escape,
|
| 1568 | 1568 | -- see Note [Exceptions in TH]
|
| 1569 | - , mReport = report
|
|
| 1570 | - |
|
| 1571 | - , mLocation = location
|
|
| 1572 | - |
|
| 1573 | - , mLookupName = lookupName
|
|
| 1574 | - , mReify = reify
|
|
| 1575 | - , mReifyFixity = \nm -> lookupThName nm >>= reifyFixity
|
|
| 1576 | - , mReifyType = reifyTypeOfThing
|
|
| 1577 | - , mReifyInstances = reifyInstances
|
|
| 1578 | - , mReifyRoles = reifyRoles
|
|
| 1579 | - , mReifyAnnotations = reifyAnnotations
|
|
| 1580 | - , mReifyModule = reifyModule
|
|
| 1581 | - , mReifyConStrictness = \nm -> do { nm' <- lookupThName nm
|
|
| 1569 | + , mReport = fmap runInIO . report
|
|
| 1570 | + |
|
| 1571 | + , mLocation = runInIO location
|
|
| 1572 | + |
|
| 1573 | + , mLookupName = fmap runInIO . lookupName
|
|
| 1574 | + , mReify = runInIO . reify
|
|
| 1575 | + , mReifyFixity = \nm -> runInIO $ lookupThName nm >>= reifyFixity
|
|
| 1576 | + , mReifyType = runInIO . reifyTypeOfThing
|
|
| 1577 | + , mReifyInstances = fmap runInIO . reifyInstances
|
|
| 1578 | + , mReifyRoles = runInIO . reifyRoles
|
|
| 1579 | + , mReifyAnnotations = runInIO . reifyAnnotations
|
|
| 1580 | + , mReifyModule = runInIO . reifyModule
|
|
| 1581 | + , mReifyConStrictness = \nm -> runInIO $ do { nm' <- lookupThName nm
|
|
| 1582 | 1582 | ; dc <- tcLookupDataCon nm'
|
| 1583 | 1583 | ; let bangs = dataConImplBangs dc
|
| 1584 | 1584 | ; return (map reifyDecidedStrictness bangs) }
|
| 1585 | 1585 | |
| 1586 | - -- For qRecover, discard error messages if
|
|
| 1587 | - -- the recovery action is chosen. Otherwise
|
|
| 1588 | - -- we'll only fail higher up.
|
|
| 1589 | - -- NB: extremely subtle!!! TODO: write up note
|
|
| 1590 | - -- tryTcDiscardingErrs manipulates the reader env so we need to be careful we don't sneak in the outside env
|
|
| 1591 | - , mRecover = \recover main -> tryTcDiscardingErrs (runQuasi recover) (runQuasi main)
|
|
| 1586 | + -- -- For qRecover, discard error messages if
|
|
| 1587 | + -- -- the recovery action is chosen. Otherwise
|
|
| 1588 | + -- -- we'll only fail higher up.
|
|
| 1589 | + -- -- NB: extremely subtle!!! TODO: write up note
|
|
| 1590 | + -- -- tryTcDiscardingErrs manipulates the reader env so we need to be careful we don't sneak in the outside env
|
|
| 1591 | + , mRecover = \recover main -> runInIO $ tryTcDiscardingErrs (runQuasi recover) (runQuasi main)
|
|
| 1592 | 1592 | |
| 1593 | - , mGetPackageRoot = do
|
|
| 1593 | + , mGetPackageRoot = runInIO $ do
|
|
| 1594 | 1594 | dflags <- getDynFlags
|
| 1595 | 1595 | return $ fromMaybe "." (workingDirectory dflags)
|
| 1596 | 1596 | |
| 1597 | - , mAddDependentFile = \fp -> do
|
|
| 1597 | + , mAddDependentFile = \fp -> runInIO $ do
|
|
| 1598 | 1598 | ref <- fmap tcg_dependent_files getGblEnv
|
| 1599 | 1599 | dep_files <- readTcRef ref
|
| 1600 | 1600 | writeTcRef ref (fp:dep_files)
|
| 1601 | 1601 | |
| 1602 | - , mAddDependentDirectory = \dp -> do
|
|
| 1602 | + , mAddDependentDirectory = \dp -> runInIO $ do
|
|
| 1603 | 1603 | ref <- fmap tcg_dependent_dirs getGblEnv
|
| 1604 | 1604 | dep_dirs <- readTcRef ref
|
| 1605 | 1605 | writeTcRef ref (dp:dep_dirs)
|
| 1606 | 1606 | |
| 1607 | - , mAddTempFile = \suffix -> do
|
|
| 1607 | + , mAddTempFile = \suffix -> runInIO $ do
|
|
| 1608 | 1608 | dflags <- getDynFlags
|
| 1609 | 1609 | logger <- getLogger
|
| 1610 | 1610 | tmpfs <- hsc_tmpfs <$> getTopEnv
|
| 1611 | 1611 | liftIO $ newTempName logger tmpfs (tmpDir dflags) TFL_GhcSession suffix
|
| 1612 | 1612 | |
| 1613 | - , mAddTopDecls = addTopDecls
|
|
| 1613 | + , mAddTopDecls = runInIO . addTopDecls
|
|
| 1614 | 1614 | |
| 1615 | - , mAddForeignFilePath = \lang fp -> do
|
|
| 1615 | + , mAddForeignFilePath = \lang fp -> runInIO $ do
|
|
| 1616 | 1616 | var <- fmap tcg_th_foreign_files getGblEnv
|
| 1617 | 1617 | updTcRef var ((lang, fp) :)
|
| 1618 | 1618 | |
| 1619 | - , mAddModFinalizer = \fin -> do
|
|
| 1619 | + , mAddModFinalizer = \fin -> runInIO $ do
|
|
| 1620 | 1620 | r <- liftIO $ mkRemoteRef fin
|
| 1621 | 1621 | fref <- liftIO $ mkForeignRef r (freeRemoteRef r)
|
| 1622 | 1622 | addModFinalizerRef fref
|
| 1623 | 1623 | |
| 1624 | - , mAddCorePlugin = \plugin -> do
|
|
| 1624 | + , mAddCorePlugin = \plugin -> runInIO $ do
|
|
| 1625 | 1625 | hsc_env <- getTopEnv
|
| 1626 | 1626 | let fc = hsc_FC hsc_env
|
| 1627 | 1627 | let home_unit = hsc_home_unit hsc_env
|
| ... | ... | @@ -1636,20 +1636,20 @@ metaHandlersTcM = TH.MetaHandlers { |
| 1636 | 1636 | th_coreplugins_var <- tcg_th_coreplugins <$> getGblEnv
|
| 1637 | 1637 | updTcRef th_coreplugins_var (plugin:)
|
| 1638 | 1638 | |
| 1639 | - , mGetQ = getQ
|
|
| 1639 | + , mGetQ = runInIO getQ
|
|
| 1640 | 1640 | |
| 1641 | - , mPutQ = \x -> do
|
|
| 1641 | + , mPutQ = \x -> runInIO $ do
|
|
| 1642 | 1642 | th_state_var <- fmap tcg_th_state getGblEnv
|
| 1643 | 1643 | updTcRef th_state_var (\m -> Map.insert (typeOf x) (toDyn x) m)
|
| 1644 | 1644 | |
| 1645 | - , mIsExtEnabled = xoptM
|
|
| 1645 | + , mIsExtEnabled = runInIO . xoptM
|
|
| 1646 | 1646 | |
| 1647 | - , mExtsEnabled =
|
|
| 1647 | + , mExtsEnabled = runInIO $
|
|
| 1648 | 1648 | EnumSet.toList . extensionFlags . hsc_dflags <$> getTopEnv
|
| 1649 | 1649 | |
| 1650 | - , mPutDoc = putDoc
|
|
| 1650 | + , mPutDoc = fmap runInIO . putDoc
|
|
| 1651 | 1651 | |
| 1652 | - , mGetDoc = getDoc
|
|
| 1652 | + , mGetDoc = runInIO . getDoc
|
|
| 1653 | 1653 | }
|
| 1654 | 1654 | |
| 1655 | 1655 | -- | Looks up documentation for a declaration in first the current module,
|
| ... | ... | @@ -150,7 +150,7 @@ class (MonadIO m, MonadFail m) => Quasi m where |
| 150 | 150 | -- type environment, so reification isn't going to
|
| 151 | 151 | -- work.
|
| 152 | 152 | instance Quasi IO where
|
| 153 | - qRunQ (Q m) = m id metaHandlersIO
|
|
| 153 | + qRunQ (Q m) = m metaHandlersIO
|
|
| 154 | 154 | qNewName = newNameIO
|
| 155 | 155 | |
| 156 | 156 | qReport True msg = hPutStrLn stderr ("Template Haskell error: " ++ msg)
|
| ... | ... | @@ -332,7 +332,7 @@ counter = unsafePerformIO (newIORef 0) |
| 332 | 332 | -- inversion](https://en.wikipedia.org/wiki/Dependency_inversion_principle),
|
| 333 | 333 | -- providing an abstract interface for the user which is later concretely
|
| 334 | 334 | -- fufilled by an concrete 'Quasi' instance, internal to GHC.
|
| 335 | -newtype Q a = Q { unQ :: forall m. (forall x. m x -> IO x) -> MetaHandlers m -> IO a }
|
|
| 335 | +newtype Q a = Q { unQ :: MetaHandlers IO -> IO a }
|
|
| 336 | 336 | |
| 337 | 337 | -- | \"Runs\" the 'Q' monad. Normal users of Template Haskell
|
| 338 | 338 | -- should not need this function, as the splice brackets @$( ... )@
|
| ... | ... | @@ -349,19 +349,19 @@ runQ :: Quasi m => Q a -> m a |
| 349 | 349 | runQ = qRunQ
|
| 350 | 350 | |
| 351 | 351 | instance Monad Q where
|
| 352 | - Q m >>= k = Q $ \r h -> (m r h >>= \x -> unQ (k x) r h)
|
|
| 352 | + Q m >>= k = Q $ \h -> (m h >>= \x -> unQ (k x) h)
|
|
| 353 | 353 | (>>) = (*>)
|
| 354 | 354 | |
| 355 | 355 | instance MonadFail Q where
|
| 356 | - fail s = report True s >> Q (\r h -> r $ mFail h "Q monad failure")
|
|
| 356 | + fail s = report True s >> Q (\h -> mFail h "Q monad failure")
|
|
| 357 | 357 | |
| 358 | 358 | instance Functor Q where
|
| 359 | - fmap f (Q x) = Q $ \r h -> fmap f (x r h)
|
|
| 359 | + fmap f (Q x) = Q $ \h -> fmap f (x h)
|
|
| 360 | 360 | |
| 361 | 361 | instance Applicative Q where
|
| 362 | - pure x = Q $ \_ _ -> pure x
|
|
| 363 | - Q f <*> Q x = Q $ \r h -> (f r h <*> x r h)
|
|
| 364 | - Q m *> Q n = Q $ \r h -> (m r h *> n r h)
|
|
| 362 | + pure x = Q $ \_ -> pure x
|
|
| 363 | + Q f <*> Q x = Q $ \h -> (f h <*> x h)
|
|
| 364 | + Q m *> Q n = Q $ \h -> (m h *> n h)
|
|
| 365 | 365 | |
| 366 | 366 | -- | @since 2.17.0.0
|
| 367 | 367 | instance Semigroup a => Semigroup (Q a) where
|
| ... | ... | @@ -431,13 +431,13 @@ class Monad m => Quote m where |
| 431 | 431 | newName :: String -> m Name
|
| 432 | 432 | |
| 433 | 433 | runHandler :: (forall m. MetaHandlers m -> m a) -> Q a
|
| 434 | -runHandler op = Q $ \r h -> r (op h)
|
|
| 434 | +runHandler op = Q $ \h -> (op h)
|
|
| 435 | 435 | |
| 436 | 436 | runHandler1 :: (forall m. MetaHandlers m -> a -> m b) -> a -> Q b
|
| 437 | -runHandler1 op = \x -> Q $ \r h -> r (op h x)
|
|
| 437 | +runHandler1 op = \x -> Q $ \h -> (op h x)
|
|
| 438 | 438 | |
| 439 | 439 | runHandler2 :: (forall m. MetaHandlers m -> a -> b -> m c) -> a -> b -> Q c
|
| 440 | -runHandler2 op = \x y -> Q $ \r h -> r (op h x y)
|
|
| 440 | +runHandler2 op = \x y -> Q $ \h -> (op h x y)
|
|
| 441 | 441 | |
| 442 | 442 | instance Quote Q where
|
| 443 | 443 | newName = runHandler1 mNewName
|
| ... | ... | @@ -653,7 +653,7 @@ reportWarning = report False |
| 653 | 653 | recover :: Q a -- ^ handler to invoke on failure
|
| 654 | 654 | -> Q a -- ^ computation to run
|
| 655 | 655 | -> Q a
|
| 656 | -recover rec main = Q $ \r h -> r $ mRecover h rec main
|
|
| 656 | +recover rec main = Q $ \h -> mRecover h rec main
|
|
| 657 | 657 | |
| 658 | 658 | -- We don't export lookupName; the Bool isn't a great API
|
| 659 | 659 | -- Instead we export lookupTypeName, lookupValueName
|
| ... | ... | @@ -920,7 +920,7 @@ location = runHandler mLocation |
| 920 | 920 | -- necessarily flushed when the compiler finishes running, so you should
|
| 921 | 921 | -- flush them yourself.
|
| 922 | 922 | runIO :: IO a -> Q a
|
| 923 | -runIO m = Q $ \_ _ -> m
|
|
| 923 | +runIO m = Q $ \_ -> m
|
|
| 924 | 924 | |
| 925 | 925 | -- | Get the package root for the current package which is being compiled.
|
| 926 | 926 | -- This can be set explicitly with the -package-root flag but is normally
|
| 1 | 1 | {-# LANGUAGE ScopedTypeVariables, StandaloneDeriving, DeriveGeneric,
|
| 2 | - TupleSections, RecordWildCards, InstanceSigs, CPP #-}
|
|
| 2 | + TupleSections, RecordWildCards, InstanceSigs, CPP, RankNTypes #-}
|
|
| 3 | 3 | {-# OPTIONS_GHC -fno-warn-name-shadowing #-}
|
| 4 | 4 | |
| 5 | 5 | -- |
|
| ... | ... | @@ -174,18 +174,19 @@ reifyAnnotations lookup = |
| 174 | 174 | where typerep = typeOf (undefined :: a)
|
| 175 | 175 | |
| 176 | 176 | runQinGHCiQ :: TH.Q a -> GHCiQ a
|
| 177 | -runQinGHCiQ (TH.Q m) = GHCiQ $ \sRef -> m (runInIO sRef) metaHandlersGHCiQ
|
|
| 177 | +runQinGHCiQ (TH.Q m) = GHCiQ $ \sRef -> m (metaHandlersGHCiQ (runInIO sRef))
|
|
| 178 | 178 | where
|
| 179 | 179 | runInIO :: IORef QState -> GHCiQ a -> IO a
|
| 180 | 180 | runInIO sRef (GHCiQ m) = m sRef
|
| 181 | 181 | |
| 182 | -metaHandlersGHCiQ = TH.MetaHandlers {
|
|
| 183 | - mFail = fail
|
|
| 184 | - , mNewName = \str -> ghcCmd (NewName str)
|
|
| 185 | - , mReport = \isError msg -> ghcCmd (Report isError msg)
|
|
| 182 | +metaHandlersGHCiQ :: (forall x. GHCiQ x -> IO x) -> TH.MetaHandlers IO
|
|
| 183 | +metaHandlersGHCiQ runInIO = TH.MetaHandlers {
|
|
| 184 | + mFail = runInIO . fail
|
|
| 185 | + , mNewName = \str -> runInIO $ ghcCmd (NewName str)
|
|
| 186 | + , mReport = \isError msg -> runInIO $ ghcCmd (Report isError msg)
|
|
| 186 | 187 | |
| 187 | 188 | -- See Note [TH recover with -fexternal-interpreter] in GHC.Tc.Gen.Splice
|
| 188 | - , mRecover = \h a -> GHCiQ $ \sRef -> mask $ \unmask -> do
|
|
| 189 | + , mRecover = \h a -> runInIO $ GHCiQ $ \sRef -> mask $ \unmask -> do
|
|
| 189 | 190 | s <- readIORef sRef
|
| 190 | 191 | remoteTHCall (qsPipe s) StartRecover
|
| 191 | 192 | e <- try $ unmask $ runGHCiQ (runQinGHCiQ a <* ghcCmd FailIfErrs) sRef
|
| ... | ... | @@ -195,37 +196,37 @@ metaHandlersGHCiQ = TH.MetaHandlers { |
| 195 | 196 | -- in case of error, restore the state to the start of the `recover` block.
|
| 196 | 197 | newIORef s >>= runGHCiQ (runQinGHCiQ h)
|
| 197 | 198 | Right r -> return r
|
| 198 | - , mLookupName = \isType occ -> ghcCmd (LookupName isType occ)
|
|
| 199 | - , mReify = \name -> ghcCmd (Reify name)
|
|
| 200 | - , mReifyFixity = \name -> ghcCmd (ReifyFixity name)
|
|
| 201 | - , mReifyType = \name -> ghcCmd (ReifyType name)
|
|
| 202 | - , mReifyInstances = \name tys -> ghcCmd (ReifyInstances name tys)
|
|
| 203 | - , mReifyRoles = \name -> ghcCmd (ReifyRoles name)
|
|
| 204 | - |
|
| 205 | - , mReifyAnnotations = reifyAnnotations
|
|
| 206 | - , mReifyModule = \m -> ghcCmd (ReifyModule m)
|
|
| 207 | - , mReifyConStrictness = \name -> ghcCmd (ReifyConStrictness name)
|
|
| 208 | - , mLocation = fromMaybe noLoc . qsLocation <$> getState
|
|
| 209 | - , mGetPackageRoot = ghcCmd GetPackageRoot
|
|
| 210 | - , mAddDependentFile = \file -> ghcCmd (AddDependentFile file)
|
|
| 211 | - , mAddDependentDirectory = \dir -> ghcCmd (AddDependentDirectory dir)
|
|
| 212 | - , mAddTempFile = \suffix -> ghcCmd (AddTempFile suffix)
|
|
| 213 | - , mAddTopDecls = \decls -> ghcCmd (AddTopDecls decls)
|
|
| 214 | - , mAddForeignFilePath = \lang fp -> ghcCmd (AddForeignFilePath lang fp)
|
|
| 215 | - , mAddModFinalizer = \fin -> GHCiQ (\s -> mkRemoteRef fin) >>=
|
|
| 199 | + , mLookupName = \isType occ -> runInIO $ ghcCmd (LookupName isType occ)
|
|
| 200 | + , mReify = \name ->runInIO $ ghcCmd (Reify name)
|
|
| 201 | + , mReifyFixity = \name ->runInIO $ ghcCmd (ReifyFixity name)
|
|
| 202 | + , mReifyType = \name -> runInIO $ ghcCmd (ReifyType name)
|
|
| 203 | + , mReifyInstances = \name tys -> runInIO $ghcCmd (ReifyInstances name tys)
|
|
| 204 | + , mReifyRoles = \name -> runInIO $ ghcCmd (ReifyRoles name)
|
|
| 205 | + |
|
| 206 | + , mReifyAnnotations = runInIO . reifyAnnotations
|
|
| 207 | + , mReifyModule = \m -> runInIO $ ghcCmd (ReifyModule m)
|
|
| 208 | + , mReifyConStrictness = \name -> runInIO $ ghcCmd (ReifyConStrictness name)
|
|
| 209 | + , mLocation = runInIO $ fromMaybe noLoc . qsLocation <$> getState
|
|
| 210 | + , mGetPackageRoot = runInIO $ ghcCmd GetPackageRoot
|
|
| 211 | + , mAddDependentFile = \file -> runInIO $ ghcCmd (AddDependentFile file)
|
|
| 212 | + , mAddDependentDirectory = \dir -> runInIO $ ghcCmd (AddDependentDirectory dir)
|
|
| 213 | + , mAddTempFile = \suffix -> runInIO $ ghcCmd (AddTempFile suffix)
|
|
| 214 | + , mAddTopDecls = \decls -> runInIO $ ghcCmd (AddTopDecls decls)
|
|
| 215 | + , mAddForeignFilePath = \lang fp -> runInIO $ ghcCmd (AddForeignFilePath lang fp)
|
|
| 216 | + , mAddModFinalizer = \fin -> runInIO $ GHCiQ (\s -> mkRemoteRef fin) >>=
|
|
| 216 | 217 | ghcCmd . AddModFinalizer
|
| 217 | - , mAddCorePlugin = \str -> ghcCmd (AddCorePlugin str)
|
|
| 218 | - , mGetQ = do
|
|
| 218 | + , mAddCorePlugin = \str -> runInIO $ ghcCmd (AddCorePlugin str)
|
|
| 219 | + , mGetQ = runInIO $ do
|
|
| 219 | 220 | s <- getState
|
| 220 | 221 | let lookup :: forall a. Typeable a => Map TypeRep Dynamic -> Maybe a
|
| 221 | 222 | lookup m = fromDynamic =<< M.lookup (typeOf (undefined::a)) m
|
| 222 | 223 | return $ lookup (qsMap s)
|
| 223 | - , mPutQ = \k -> GHCiQ $ \sRef ->
|
|
| 224 | + , mPutQ = \k -> runInIO $ GHCiQ $ \sRef ->
|
|
| 224 | 225 | modifyIORef' sRef (\s -> s { qsMap = M.insert (typeOf k) (toDyn k) (qsMap s) })
|
| 225 | - , mIsExtEnabled = \x -> ghcCmd (IsExtEnabled x)
|
|
| 226 | - , mExtsEnabled = ghcCmd ExtsEnabled
|
|
| 227 | - , mPutDoc = \l s -> ghcCmd (PutDoc l s)
|
|
| 228 | - , mGetDoc = \l -> ghcCmd (GetDoc l)
|
|
| 226 | + , mIsExtEnabled = \x -> runInIO $ ghcCmd (IsExtEnabled x)
|
|
| 227 | + , mExtsEnabled = runInIO $ ghcCmd ExtsEnabled
|
|
| 228 | + , mPutDoc = \l s -> runInIO $ ghcCmd (PutDoc l s)
|
|
| 229 | + , mGetDoc = \l -> runInIO $ ghcCmd (GetDoc l)
|
|
| 229 | 230 | }
|
| 230 | 231 | |
| 231 | 232 | -- | The implementation of the 'StartTH' message: create
|