diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,5 @@
 # Revision history for `ghc-internal`
 
-## 0.1.0.0 -- YYYY-mm-dd
+## 9.1001.0 -- 2024-05-01
 
-* First version. Released on an unsuspecting world.
+* Package created containing implementation moved from `base`.
diff --git a/ghc-internal.cabal b/ghc-internal.cabal
--- a/ghc-internal.cabal
+++ b/ghc-internal.cabal
@@ -1,8 +1,10 @@
 cabal-version:  3.0
+-- WARNING: ghc-internal.cabal is automatically generated from ghc-internal.cabal.in by
+-- the top-level ./configure script. Make sure you are editing ghc-internal.cabal.in, not ghc-internal.cabal.
 name:           ghc-internal
-version:        9.1001.0
--- NOTE: Don't forget to update ./changelog.md
-
+-- The project is ghc's version plus ghc-internal's version suffix.
+-- For example, for ghc=9.10.1, ghc-internal's version will be 9.1001.0.
+version:        9.1002.0
 license:        BSD-3-Clause
 license-file:   LICENSE
 maintainer:     Core Libraries Committee <core-libraries-committee@haskell.org>
@@ -87,7 +89,7 @@
 
     build-depends:
         rts == 1.0.*,
-        ghc-prim >= 0.11 && < 0.12,
+        ghc-prim >= 0.11 && < 0.13,
         ghc-bignum >= 1.0 && < 2.0
 
     exposed-modules:
@@ -172,7 +174,6 @@
         GHC.Internal.Conc.Signal
         GHC.Internal.Conc.Sync
         GHC.Internal.ConsoleHandler
-        GHC.Internal.Constants
         GHC.Internal.Desugar
         GHC.Internal.Encoding.UTF8
         GHC.Internal.Enum
diff --git a/jsbits/base.js b/jsbits/base.js
--- a/jsbits/base.js
+++ b/jsbits/base.js
@@ -912,7 +912,7 @@
     }
 } else if(h$isJsCore()) {
     h$base_readStdin = function(fd, fdo, buf, buf_offset, n, c) {
-	c(0);
+        c(0);
     }
     var h$base_stdoutLeftover = { f: print, val: null };
     var h$base_stderrLeftover = { f: debug, val: null };
@@ -1077,3 +1077,12 @@
   }
   return 0;
 }
+
+// It is required by Google Closure Compiler to be at least defined if
+// somewhere it is used
+var h$stg_cloneMyStackzh, h$stg_decodeStackzh
+h$stg_cloneMyStackzh
+  = h$stg_decodeStackzh
+  = function () {
+    throw new Error('Stack Cloning Decoding: Not Implemented Yet')
+  }
diff --git a/jsbits/platform.js b/jsbits/platform.js
--- a/jsbits/platform.js
+++ b/jsbits/platform.js
@@ -46,18 +46,36 @@
 }
 
 // load all required node.js modules
-if(typeof process !== 'undefined' && (typeof h$TH !== 'undefined' || (typeof require !== 'undefined' && typeof module !== 'undefined' && module.exports))) {
+if(typeof global !== 'undefined' && typeof process !== 'undefined' && (typeof h$TH !== 'undefined' || (typeof require !== 'undefined' && typeof module !== 'undefined' && module.exports))) {
     h$isNode_ = true;
-    // we have to use these names for the closure compiler externs to work
-    var fs            = require('fs');
-    var path          = require('path');
-    var os            = require('os');
-    var child_process = require('child_process');
-    var h$fs          = fs;
-    var h$path        = path;
-    var h$os          = os;
-    var h$child       = child_process;
+    // we have to put fs var into closure to prevent name clashes with emscripten compiler code injections
+    // we use additional suffix to have more guarantees over possible clashes
+    // we should use amd/commonjs module wrappers to avoid such ugly things
+    global.h$nodeOS_modules_qvsKGchAmE = (function() {
+      var fs = require('fs');
+      var path = require('path');
+      var os = require('os');
+      var child_process = require('child_process');
+      return {
+        'fs' : fs,
+        'path': path,
+        'os': os,
+        'child_process': child_process
+      };
+    })();
+    // we dictionary-like access strictly prevents
+    // google closure compiler names mangling
+    var h$fs          = global.h$nodeOS_modules_qvsKGchAmE['fs'];
+    var h$path        = global.h$nodeOS_modules_qvsKGchAmE['path'];
+    var h$os          = global.h$nodeOS_modules_qvsKGchAmE['os'];
+    var h$child       = global.h$nodeOS_modules_qvsKGchAmE['child_process'];
+
+    // we forcibly delete temporary lexical environment variable
+    // to prevent any clashes
+    delete global.h$nodeOS_modules_qvsKGchAmE;
+
     var h$process     = process;
+
     function h$getProcessConstants() {
       // this is a non-public API, but we need these values for things like file access modes
       var cs = process['binding']('constants');
@@ -76,7 +94,7 @@
       }
     }
     var h$processConstants = h$getProcessConstants();
-} else if(typeof Java !== 'undefined') {
+} else if(typeof Java !== 'undefined' && typeof java !== 'undefined') {
     h$isJvm_ = true;
     this.console = {
       log: function(s) {
diff --git a/src/GHC/Internal/Base.hs b/src/GHC/Internal/Base.hs
--- a/src/GHC/Internal/Base.hs
+++ b/src/GHC/Internal/Base.hs
@@ -326,8 +326,7 @@
 import GHC.Internal.Maybe
 import {-# SOURCE #-} GHC.Internal.IO (mkUserError, mplusIO)
 
-import GHC.Tuple (Solo (MkSolo)) -- Note [Depend on GHC.Tuple]
-import GHC.Num.Integer ()        -- Note [Depend on GHC.Num.Integer]
+import GHC.Tuple (Solo (MkSolo))
 
 -- See Note [Semigroup stimes cycle]
 import {-# SOURCE #-} GHC.Internal.Num (Num (..))
@@ -348,38 +347,120 @@
 default ()              -- Double isn't available yet
 
 {-
-Note [Depend on GHC.Num.Integer]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The Integer type is special because GHC.CoreToStg.Prep.mkConvertNumLiteral
-lookups names in ghc-bignum interfaces to construct Integer literal values.
-Currently it reads the interface file whether or not the current module *has*
-any Integer literals, so it's important that GHC.Num.Integer is compiled before
-any other module.
+Note [Tracking dependencies on primitives]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+When desugaring certain program constructs, GHC will insert references
+to the primitives used to implement those constructs even if those
+primitives have not actually been imported.  For example, the function
+``fst (x,_) = x`` will be desugared using references to the 2-tuple
+data constructor, which lives in GHC.Tuple.
 
-The danger is that if the build system doesn't know about the implicit
-dependency on Integer, it'll compile some base module before GHC.Num.Integer,
-resulting in:
-  Failed to load interface for ‘GHC.Num.Integer’
-    There are files missing in the ‘ghc-bignum’ package,
+When bootstrapping GHC, it is important that we do not attempt to
+compile any such reference to GHC.Tuple before GHC.Tuple itself has
+been built, otherwise compilation will fail with an error like this one:
+    Failed to load interface for ‘GHC.Tuple’.
+    There are files missing in the ‘ghc-prim-0.10.0’ package,
+    try running 'ghc-pkg check'.
+    Use -v to see a list of the files searched for.
 
-To ensure that GHC.Num.Integer is there, we must ensure that there is a visible
-dependency on GHC.Num.Integer from every module in base.  We make GHC.Internal.Base
-depend on GHC.Num.Integer; and everything else either depends on GHC.Base,
-directly on GHC.Num.Integer, or does not have NoImplicitPrelude (and hence
-depends on Prelude).
+To prevent such errors, we insist that if any boot library module X
+implicitly depends on primitives in module Y, then the transitive
+imports of X must include Y.
 
-The lookup is only disabled for packages ghc-prim and ghc-bignum, which aren't
-allowed to contain any Integer literal.
+Such implicit dependencies can be introduced in at least the following ways:
 
+W1:
+  Common awkward dependencies:
+   * TypeRep metadata introduces references to GHC.Types in EVERY module.
+   * A String literal introduces a reference to GHC.CString, for either
+     unpackCString# or unpackCStringUtf8# depending on its contents.
+   * Tuple-notation introduces references to GHC.Tuple.
+   * Constraint tuples introduce references to GHC.Classes.
+   * Short lists like [3,8,2] produce references to GHC.Internal.Base.build
 
-Note [Depend on GHC.Tuple]
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-Similarly, tuple syntax (or ()) creates an implicit dependency on
-GHC.Tuple, so we use the same rule as for Integer --- see Note [Depend on
-GHC.Num.Integer] --- to explain this to the build system.  We make GHC.Internal.Base
-depend on GHC.Tuple, and everything else depends on GHC.Internal.Base or Prelude.
+  A module can transitively depend on all of these by importing any of
+  GHC.Internal.Base, GHC.Base, or Prelude.  The latter in particular
+  means that an explicit import for this reason is only necessary when
+  ImplicitPrelude is disabled, so this primarily comes up in the
+  dependencies of base and in the compiler itself.
 
+   * Most modules in ghc-internal import GHC.Internal.Base.
+   * Most modules in compiler/ import GHC.Prelude, which imports Prelude.
+   * Most hs-boot files that would otherwise have no imports can get
+     away with just importing GHC.Types.
 
+  Unfortunately, the requirement to transitively import these modules
+  when they are implicitly used is obscure and causes only /intermittent/
+  build failures, so enforcement of that requirement has historically
+  been pretty spotty, causing issues like #23942.
+
+  Improving this situation is discussed at #24520.
+
+W2:
+  Non-exhaustive pattern matches, incomplete record selectors,
+  missing record fields, and missing class instance methods all
+  introduce references to GHC.Internal.Control.Exception.Base.
+
+  These constructs are therefore not allowed in ghc-prim or ghc-bignum.
+  But since they generally have bad code smell and are avoided by
+  developers anyway, this restriction has not been very burdensome.
+
+W3:
+  Various "overloaded" bits of syntax:
+   * Overloaded integer literals introduce references to GHC.Internal.Num.
+     * Likewise overloaded fractional literals to GHC.Internal.Real
+     * Likewise overloaded string literals to GHC.Internal.Data.String
+     * Likewise overloaded list literals to GHC.Internal.IsList
+   * Overloaded labels introduce references to GHC.Internal.OverloadedLabels
+   * Uses of OverloadedRecordDot introduce references to GHC.Internal.Records.
+   * Do-notation introduces references to GHC.Internal.Base for Monad stuff.
+     * Likewise arrow-notation to GHC.Internal.Control.Arrow
+     * Likewise RecursiveDo stuff to GHC.Internal.Control.Monad.Fix
+   * (Does TemplateHaskellQuotes fall into this category as well?)
+
+  These are not problematic in practice.  For example, a program
+  that uses arrow-notation but does not otherwise import the Arrow
+  type class will almost certainly fail to type-check anyway.
+  (The "Arrow m" constraint will be very hard to solve!)
+
+W4:
+  Stock derived instances introduce references to various things.
+  Derived Eq instances can reference GHC.Magic.dataToTag#, for example.
+  But since any module containing a derived Eq instance must import Eq,
+  as long as the module which defines Eq imports GHC.Magic this cannot
+  cause trouble.
+
+  Embarrassingly, we do not follow this plan for the Lift class.
+  Derived Lift instances refer to machinery in Language.Haskell.TH.Lib,
+  which is not imported by the module Language.Haskell.TH.Syntax that
+  defines the Lift class.  This is still causing annoyance for boot
+  library maintainers as of March 2024:  See #22229.
+
+W5:
+  If no explicit "default" declaration is present, the assumed
+  "default (Integer, Double)" creates a dependency on GHC.Num.Integer
+  for the Integer type if defaulting is ever attempted during
+  type-checking.  (This doesn't apply to hs-boot files, which can't
+  be given "default" declarations anyway.)
+
+W6:
+  In the wasm backend, JSFFI imports and exports pull in a bunch of stuff;
+  see Note [Desugaring JSFFI static export] and Note [Desugaring JSFFI import]
+  in GHC.HsToCore.Foreign.Wasm.
+
+A complete list could probably be made by going through the known-key
+names in GHC.Builtin.Names and GHC.Builtin.Names.TH.  To test whether
+the transitive imports are sufficient for any single module, instruct
+the build system to build /only/ that module in stage 2.  For example,
+a command to check whether the transitive imports for GHC.Internal.Maybe
+are sufficient is:
+
+  hadrian/build -o_checkDeps _checkDeps/stage1/libraries/ghc-internal/build/GHC/Internal/Maybe.o
+
+Use the ".o-boot" suffix instead of ".o" to check an hs-boot file's
+transitive imports.
+
+
 Note [Semigroup stimes cycle]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Semigroup is defined in this module, GHC.Base, with the method
@@ -388,12 +469,13 @@
 This presents a problem.
 * We use Integral methods (quot, rem) and Num methods (-) in stimes definitions
   in this module. Num is a superclass of Integral.
-* Num is defined in GHC.Num, which imports GHC.Base.
-* Enum is defined in GHC.Enum, which imports GHC.Internal.Base and GHC.Num. Enum is a
-  superclass of Integral. We don't use any Enum methods here, but it is relevant
+* Num is defined in GHC.Internal.Num, which imports GHC.Internal.Base.
+* Enum is defined in GHC.Internal.Enum, which imports
+  GHC.Internal.Base and GHC.Internal.Num. Enum is a superclass of
+  Integral. We don't use any Enum methods here, but it is relevant
   (read on).
-* Integral is defined in GHC.Real, which imports GHC.Base, GHC.Num, and
-  GHC.Enum.
+* Integral is defined in GHC.Internal.Real, which imports
+  GHC.Internal.Base, GHC.Internal.Num, and GHC.Internal.Enum.
 
 We resolve this web of dependencies with hs-boot files. The rules
 https://ghc.gitlab.haskell.org/ghc/doc/users_guide/separate_compilation.html#how-to-compile-mutually-recursive-modules
@@ -2268,7 +2350,7 @@
 getTag = dataToTag#
 
 ----------------------------------------------
--- GHC.Internal.Numeric primops
+-- Numeric primops
 ----------------------------------------------
 
 -- Definitions of the boxed PrimOps; these will be
diff --git a/src/GHC/Internal/ByteOrder.hs-boot b/src/GHC/Internal/ByteOrder.hs-boot
--- a/src/GHC/Internal/ByteOrder.hs-boot
+++ b/src/GHC/Internal/ByteOrder.hs-boot
@@ -19,6 +19,7 @@
 
 module GHC.Internal.ByteOrder where
 
+-- See W1 of Note [Tracking dependencies on primitives] in GHC.Internal.Base
 import GHC.Types ()
 
 data ByteOrder
diff --git a/src/GHC/Internal/Conc/Sync.hs b/src/GHC/Internal/Conc/Sync.hs
--- a/src/GHC/Internal/Conc/Sync.hs
+++ b/src/GHC/Internal/Conc/Sync.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE CPP #-}
 {-# LANGUAGE MagicHash #-}
 {-# LANGUAGE NoImplicitPrelude #-}
 {-# LANGUAGE RankNTypes #-}
@@ -394,13 +393,14 @@
 getNumProcessors = fmap fromIntegral c_getNumberOfProcessors
 
 foreign import ccall unsafe "getNumberOfProcessors"
-  c_getNumberOfProcessors :: IO CUInt
+  c_getNumberOfProcessors :: IO Word32
 
 -- | Returns the number of sparks currently in the local spark pool
 numSparks :: IO Int
 numSparks = IO $ \s -> case numSparks# s of (# s', n #) -> (# s', I# n #)
 
-foreign import ccall "&enabled_capabilities" enabled_capabilities :: Ptr CInt
+foreign import ccall "&enabled_capabilities"
+  enabled_capabilities :: Ptr Word32
 
 childHandler :: SomeException -> IO ()
 childHandler err = catch (real_handler err) childHandler
diff --git a/src/GHC/Internal/ConsoleHandler.hsc b/src/GHC/Internal/ConsoleHandler.hsc
--- a/src/GHC/Internal/ConsoleHandler.hsc
+++ b/src/GHC/Internal/ConsoleHandler.hsc
@@ -22,7 +22,8 @@
 #if !defined(mingw32_HOST_OS)
         where
 
-import GHC.Internal.Base ()  -- dummy dependency
+-- See W1 of Note [Tracking dependencies on primitives] in GHC.Internal.Base
+import GHC.Types ()
 #else /* whole file */
         ( Handler(..)
         , installHandler
diff --git a/src/GHC/Internal/Constants.hs b/src/GHC/Internal/Constants.hs
deleted file mode 100644
--- a/src/GHC/Internal/Constants.hs
+++ /dev/null
@@ -1,10 +0,0 @@
-{-# LANGUAGE Trustworthy #-}
-{-# LANGUAGE NoImplicitPrelude #-}
-
-module GHC.Internal.Constants where
-
--- TODO: This used to include HaskellConstants.hs, but that has now gone.
--- We probably want to include the constants in platformConstants somehow
--- instead.
-
-import GHC.Internal.Base () -- dummy dependency
diff --git a/src/GHC/Internal/Data/Coerce.hs b/src/GHC/Internal/Data/Coerce.hs
--- a/src/GHC/Internal/Data/Coerce.hs
+++ b/src/GHC/Internal/Data/Coerce.hs
@@ -26,7 +26,3 @@
         ) where
 import GHC.Prim (coerce)
 import GHC.Types (Coercible)
-
--- The import of GHC.Internal.Base is for build ordering; see Notes in GHC.Internal.Base for
--- more info.
-import GHC.Internal.Base ()
diff --git a/src/GHC/Internal/Data/Tuple.hs b/src/GHC/Internal/Data/Tuple.hs
--- a/src/GHC/Internal/Data/Tuple.hs
+++ b/src/GHC/Internal/Data/Tuple.hs
@@ -25,7 +25,6 @@
   , swap
   ) where
 
-import GHC.Internal.Base ()      -- Note [Depend on GHC.Tuple]
 import GHC.Tuple (Solo (..), getSolo)
 
 default ()              -- Double isn't available yet
diff --git a/src/GHC/Internal/Data/Version.hs-boot b/src/GHC/Internal/Data/Version.hs-boot
--- a/src/GHC/Internal/Data/Version.hs-boot
+++ b/src/GHC/Internal/Data/Version.hs-boot
@@ -5,7 +5,15 @@
   , makeVersion
   ) where
 
-import GHC.Internal.Base
+import GHC.Types
+
+
+-- The generated module GHC.Internal.Unicode.Version depends on
+-- GHC.Internal.Base.build via built-in list syntax, and its only
+-- import is this hs-boot file, so until someone fixes the generator,
+-- this import has to stay here to ensure sound build ordering.  See also
+-- W1 of Note [Tracking dependencies on primitives] in GHC.Internal.Base.
+import GHC.Internal.Base ()
 
 data Version
 
diff --git a/src/GHC/Internal/Enum.hs-boot b/src/GHC/Internal/Enum.hs-boot
--- a/src/GHC/Internal/Enum.hs-boot
+++ b/src/GHC/Internal/Enum.hs-boot
@@ -1,10 +1,11 @@
 {-# LANGUAGE NoImplicitPrelude #-}
 
-module GHC.Internal.Enum (Enum) where
-
 -- For why this file exists
 -- See Note [Semigroup stimes cycle] in GHC.Internal.Base
 
+module GHC.Internal.Enum (Enum) where
+
+-- See W1 of Note [Tracking dependencies on primitives] in GHC.Internal.Base
 import GHC.Types ()
 
 class Enum a
diff --git a/src/GHC/Internal/Event/KQueue.hsc b/src/GHC/Internal/Event/KQueue.hsc
--- a/src/GHC/Internal/Event/KQueue.hsc
+++ b/src/GHC/Internal/Event/KQueue.hsc
@@ -44,8 +44,8 @@
 import GHC.Internal.Real (quotRem, fromIntegral)
 import GHC.Internal.Show (Show(show))
 import GHC.Internal.Event.Internal (Timeout(..))
-import GHC.Internal.System.Posix.Internals (c_close)
-import GHC.Internal.System.Posix.Types (Fd(..))
+import GHC.Internal.System.Posix.Internals (c_close,c_getpid)
+import GHC.Internal.System.Posix.Types (Fd(..), CPid)
 import qualified GHC.Internal.Event.Array as A
 
 #if defined(netbsd_HOST_OS)
@@ -73,19 +73,26 @@
 data KQueue = KQueue {
       kqueueFd     :: {-# UNPACK #-} !KQueueFd
     , kqueueEvents :: {-# UNPACK #-} !(A.Array Event)
+    , kqueuePid    :: {-# UNPACK #-} !CPid -- ^ pid, used to detect forks
     }
 
 new :: IO E.Backend
 new = do
   kqfd <- kqueue
   events <- A.new 64
-  let !be = E.backend poll modifyFd modifyFdOnce delete (KQueue kqfd events)
+  pid <- c_getpid
+  let !be = E.backend poll modifyFd modifyFdOnce delete (KQueue kqfd events pid)
   return be
 
 delete :: KQueue -> IO ()
 delete kq = do
-  _ <- c_close . fromKQueueFd . kqueueFd $ kq
-  return ()
+  -- detect forks: the queue isn't inherited by a child process created with
+  -- fork. Hence we mustn't try to close the old fd or we might close a random
+  -- one (e.g. the one used by timerfd, cf #24672).
+  pid <- c_getpid
+  when (pid == kqueuePid kq) $ do
+    _ <- c_close . fromKQueueFd . kqueueFd $ kq
+    return ()
 
 modifyFd :: KQueue -> Fd -> E.Event -> E.Event -> IO Bool
 modifyFd kq fd oevt nevt = do
diff --git a/src/GHC/Internal/Exception.hs b/src/GHC/Internal/Exception.hs
--- a/src/GHC/Internal/Exception.hs
+++ b/src/GHC/Internal/Exception.hs
@@ -79,11 +79,88 @@
 -- WARNING: You may want to use 'throwIO' instead so that your pure code
 -- stays exception-free.
 throw :: forall (r :: RuntimeRep). forall (a :: TYPE r). forall e.
-         (?callStack :: CallStack, Exception e) => e -> a
+         (HasCallStack, Exception e) => e -> a
 throw e =
-    let !se = unsafePerformIO (toExceptionWithBacktrace e)
+    -- Note the absolutely crucial bang "!" on this binding!
+    --   See Note [Capturing the backtrace in throw]
+    -- Note also the absolutely crucial `noinine` in the RHS!
+    --   See Note [Hiding precise exception signature in throw]
+    let se :: SomeException
+        !se = noinline (unsafePerformIO (toExceptionWithBacktrace e))
     in raise# se
 
+-- Note [Capturing the backtrace in throw]
+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-- When `throw` captures a backtrace, it must be the backtrace *at the moment
+-- that `throw` is called*.   That is why the binding of `se` is marked strict,
+-- via the `!`:
+--
+--     !se = <rhs>
+--
+-- GHC can capture /four/ different sorts of backtraces (See Note [Backtrace
+-- mechanisms] in "Control.Exception.Backtrace" for details). One of them
+-- (`CallStack` constraints) does not need this strict-binding treatment,
+-- because the `CallStack` constraint is captured in the thunk. However, the
+-- other two (DWARF stack unwinding, and native Haskell stack unwinding) are
+-- much more fragile, and can only be captured right at the call of `throw`.
+--
+-- However, making `se` strict has downsides: see
+-- Note [Hiding precise exception signature in throw] below.
+--
+--
+-- Note [Hiding precise exception signature in throw]
+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-- In 'throw' we use `unsafePerformIO . toExceptionWithBacktrace' to collect
+-- the backtraces which will be attached as the exception's 'ExceptionContext'.
+-- We must ensure that this is evaluated immediately in `throw` since
+-- `toExceptionWithBacktrace` must capture the execution state at the moment
+-- that the exception is thrown (see Note [Capturing the backtrace in throw]).
+-- Unfortunately, unless we take particular care this can lead to a
+-- catastrophic regression in 'throw's demand signature which will infect
+-- all callers (#25066)
+--
+-- Specifically, GHC's demand analysis has an approximate heuristic for tracking
+-- whether divergent functions diverge with precise or imprecise exceptions (namely
+-- the 'ExnOrDiv' and 'Diverges' constructors of 'GHC.Types.Demand.Divergence',
+-- respectively). This is because we can take considerably more liberties in
+-- optimising around functions which are known not to diverge via precise
+-- exception (see Note [Precise exceptions and strictness analysis]).
+-- For this reason, it is important that 'throw' have a 'Diverges' divergence
+-- type.
+--
+-- Unfortunately, this is broken if we allow `unsafePerformIO` to inline. Specifically,
+-- if we allow this inlining we will end up with Core of the form:
+--
+--   throw = \e ->
+--     case runRW# (\s -> ... toExceptionWithBacktrace e s ...) of
+--       se -> raise# se
+--
+-- so far this is fine; the demand analyzer's divergence heuristic
+-- will give 'throw' the expected 'Diverges' divergence.
+--
+-- However, the simplifier will subsequently notice that `raise#` can be fruitfully
+-- floated into the body of the `runRW#`:
+--
+--   throw = \e ->
+--     runRW# (\s -> case toExceptionWithBacktrace e s of
+--                     (# s', se #) -> raise# se)
+--
+-- This is problematic as one of the demand analyser's heuristics examines
+-- `case` scrutinees, looking for those that result in a `RealWorld#` token
+-- (see Note [Which scrutinees may throw precise exceptions], test (1)). The
+-- `case toExceptionWithBacktrace e of ...` here fails this check, causing the
+-- heuristic to conclude that `throw` may indeed diverge with a precise
+-- exception. This resulted in the significant performance regression noted in
+-- #25066.
+--
+-- To avoid this, we use `noinline` to ensure that `unsafePerformIO` does not unfold,
+-- meaning that the `raise#` cannot be floated under the `toExceptionWithBacktrace`
+-- case analysis.
+--
+-- Ultimately this is a bit of a horrible hack; the right solution would be to have
+-- primops which allow more precise guidance of the demand analyser's heuristic
+-- (e.g. #23847).
+
 -- | @since base-4.20.0.0
 toExceptionWithBacktrace :: (HasCallStack, Exception e)
                          => e -> IO SomeException
@@ -120,12 +197,12 @@
 
 errorCallWithCallStackException :: String -> CallStack -> SomeException
 errorCallWithCallStackException s stk = unsafeDupablePerformIO $ do
-  ccsStack <- currentCallStack
-  let
-    implicitParamCallStack = prettyCallStackLines stk
-    ccsCallStack = showCCSStack ccsStack
-    stack = intercalate "\n" $ implicitParamCallStack ++ ccsCallStack
-  toExceptionWithBacktrace (ErrorCallWithLocation s stack)
+    ccsStack <- currentCallStack
+    let implicitParamCallStack = prettyCallStackLines stk
+        ccsCallStack = showCCSStack ccsStack
+        stack = intercalate "\n" $ implicitParamCallStack ++ ccsCallStack
+    toExceptionWithBacktrace (ErrorCallWithLocation s stack)
+  where ?callStack = stk
 
 showCCSStack :: [String] -> [String]
 showCCSStack [] = []
diff --git a/src/GHC/Internal/Exception/Backtrace.hs b/src/GHC/Internal/Exception/Backtrace.hs
--- a/src/GHC/Internal/Exception/Backtrace.hs
+++ b/src/GHC/Internal/Exception/Backtrace.hs
@@ -33,7 +33,7 @@
   = CostCentreBacktrace
   -- | collect 'HasCallStack' backtraces
   | HasCallStackBacktrace
-  -- | collect backtraces from native execution stack unwinding
+  -- | collect backtraces via native execution stack unwinding (e.g. using DWARF debug information)
   | ExecutionBacktrace
   -- | collect backtraces from Info Table Provenance Entries
   | IPEBacktrace
diff --git a/src/GHC/Internal/Exception/Context.hs-boot b/src/GHC/Internal/Exception/Context.hs-boot
--- a/src/GHC/Internal/Exception/Context.hs-boot
+++ b/src/GHC/Internal/Exception/Context.hs-boot
@@ -2,5 +2,8 @@
 
 module GHC.Internal.Exception.Context where
 
+-- See W1 of Note [Tracking dependencies on primitives] in GHC.Internal.Base
+import GHC.Types ()
+
 data ExceptionContext
 
diff --git a/src/GHC/Internal/Exception/Type.hs-boot b/src/GHC/Internal/Exception/Type.hs-boot
--- a/src/GHC/Internal/Exception/Type.hs-boot
+++ b/src/GHC/Internal/Exception/Type.hs-boot
@@ -9,7 +9,8 @@
   , underflowException
   ) where
 
-import GHC.Num.Integer ()   -- See Note [Depend on GHC.Num.Integer] in GHC.Internal.Base
+-- See W1 of Note [Tracking dependencies on primitives] in GHC.Internal.Base
+import GHC.Types ()
 
 data SomeException
 divZeroException, overflowException,
diff --git a/src/GHC/Internal/Exts.hs b/src/GHC/Internal/Exts.hs
--- a/src/GHC/Internal/Exts.hs
+++ b/src/GHC/Internal/Exts.hs
@@ -18,10 +18,42 @@
 -- Stability   :  internal
 -- Portability :  non-portable (GHC Extensions)
 --
--- GHC Extensions: this is the Approved Way to get at GHC-specific extensions.
+-- GHC Extensions: This is a unstable way to get at GHC-specific extensions.
+--                 If possible prefer using GHC.PrimOps from ghc-experimental
+--                 or GHC.Exts from base.
 --
--- Note: no other base module should import this module.
+-- Note: no other ghc-internal module should import this module.
 -----------------------------------------------------------------------------
+
+{- Note [Where do we export PrimOps]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Built in primops are automatically exported via the magical module
+GHC.Prim (See Note [GHC.Prim]).
+However we don't want users to use GHC.Prim directly. Among other reasons that
+would prevent us from giving those primops a regular haskell or cmm
+implementation in the future.
+
+So instead we provide a hirarchy of Modules through which we expose PrimOps.
+* ghc-internal:GHC.Exts.Internal re-exports GHC.Prim along with some other
+  builtin functionality. It gives zero stability guarantee and is mostly inteded
+  for ghc internal use.
+* ghc-experimental:GHC.PrimOps contains a more stable subset of GHC.Exts.Internal.
+  This module does not offer any more stability *guarantees* than ghc-internal,
+  but we try to keep things slightly more stable there and be backwards compatible
+  if it's easy to do. For example an export from ghc-experimental is likely to get
+  deprecated before being removed. While exports from ghc-internal could be removed
+  without advanced notice between ghc versions!
+* base:GHC.Exts: Contains all kinds of re-exports from ghc-internal:GHC.Exts.Internal
+  which have been grandfathered into this module from pre ghc-9.10.
+  Starting with 9.10.1 only definitions with a fairly high level of expected
+  stability should be exposed through GHC.Exts and changing the API provided by
+  this module now follows the CLC process.
+
+If there is a desire to create a module for a specific group of primitives they
+should still be exported by the catch-all modules GHC.Exts.Internal and GHC.PrimOps,
+with their specific module being placed under ghc-experimental:GHC.PrimOps
+in the module structure.
+-}
 
 module GHC.Internal.Exts
        (
diff --git a/src/GHC/Internal/Float/RealFracMethods.hs b/src/GHC/Internal/Float/RealFracMethods.hs
--- a/src/GHC/Internal/Float/RealFracMethods.hs
+++ b/src/GHC/Internal/Float/RealFracMethods.hs
@@ -62,7 +62,8 @@
 import GHC.Num.Integer
 
 import GHC.Internal.Base hiding (uncheckedIShiftRA64#, uncheckedIShiftL64#)
-import GHC.Internal.Num ()
+import GHC.Internal.Num () -- instance Num Integer
+                           -- (We could remove uses with a little effort)
 
 #if WORD_SIZE_IN_BITS < 64
 
diff --git a/src/GHC/Internal/Foreign/C/Types.hs b/src/GHC/Internal/Foreign/C/Types.hs
--- a/src/GHC/Internal/Foreign/C/Types.hs
+++ b/src/GHC/Internal/Foreign/C/Types.hs
@@ -47,7 +47,7 @@
         , CLLong(..),   CULLong(..), CBool(..)
         , CIntPtr(..),  CUIntPtr(..), CIntMax(..),   CUIntMax(..)
 
-          -- ** GHC.Internal.Numeric types
+          -- ** Numeric types
           -- | These types are represented as @newtype@s of basic
           -- foreign types, and are instances of
           -- 'Prelude.Eq', 'Prelude.Ord', 'Prelude.Num', 'Prelude.Read',
diff --git a/src/GHC/Internal/IO.hs b/src/GHC/Internal/IO.hs
--- a/src/GHC/Internal/IO.hs
+++ b/src/GHC/Internal/IO.hs
@@ -210,7 +210,7 @@
 -- | Execute an 'IO' action, adding the given 'ExceptionContext'
 -- to any thrown synchronous exceptions.
 --
--- @since base-2.20.0.0
+-- @since base-4.20.0.0
 annotateIO :: forall e a. ExceptionAnnotation e => e -> IO a -> IO a
 annotateIO ann (IO io) = IO (catch# io handler)
   where
diff --git a/src/GHC/Internal/IO/Encoding/CodePage.hs b/src/GHC/Internal/IO/Encoding/CodePage.hs
--- a/src/GHC/Internal/IO/Encoding/CodePage.hs
+++ b/src/GHC/Internal/IO/Encoding/CodePage.hs
@@ -14,7 +14,10 @@
                             ) where
 
 #if !defined(mingw32_HOST_OS)
-import GHC.Internal.Base () -- Build ordering
+
+-- See W1 of Note [Tracking dependencies on primitives] in GHC.Internal.Base
+import GHC.Types ()
+
 #else
 import GHC.Internal.Base
 import GHC.Internal.Show
diff --git a/src/GHC/Internal/IO/Encoding/Iconv.hs b/src/GHC/Internal/IO/Encoding/Iconv.hs
--- a/src/GHC/Internal/IO/Encoding/Iconv.hs
+++ b/src/GHC/Internal/IO/Encoding/Iconv.hs
@@ -32,7 +32,10 @@
 #include "HsBaseConfig.h"
 
 #if defined(mingw32_HOST_OS)
-import GHC.Internal.Base () -- For build ordering
+
+-- See W1 of Note [Tracking dependencies on primitives] in GHC.Internal.Base
+import GHC.Types ()
+
 #else
 
 import GHC.Internal.Foreign.C.Types
diff --git a/src/GHC/Internal/IO/FD.hs b/src/GHC/Internal/IO/FD.hs
--- a/src/GHC/Internal/IO/FD.hs
+++ b/src/GHC/Internal/IO/FD.hs
@@ -57,6 +57,7 @@
 import GHC.Internal.Foreign.C.Types
 import GHC.Internal.Foreign.C.Error
 import GHC.Internal.Foreign.Marshal.Utils
+import GHC.Internal.Foreign.Marshal.Alloc (allocaBytes)
 
 import qualified GHC.Internal.System.Posix.Internals
 import GHC.Internal.System.Posix.Internals hiding (FD, setEcho, getEcho)
@@ -476,10 +477,15 @@
   -- O_NONBLOCK has no effect on regular files and block devices;
   -- utilities inspecting fdIsNonBlocking (such as readRawBufferPtr)
   -- should not be tricked to think otherwise.
-  is_nonblock <- if set then do
-    (fd_type, _, _) <- fdStat (fdFD fd)
-    pure $ fd_type /= RegularFile && fd_type /= RawDevice
-    else pure False
+  is_nonblock <-
+    if set
+      then do
+        allocaBytes sizeof_stat $ \ p_stat -> do
+          throwErrnoIfMinus1Retry_ "fileSize" $
+            c_fstat (fdFD fd) p_stat
+          fd_type <- statGetType_maybe p_stat
+          pure $ fd_type /= Just RegularFile && fd_type /= Just RawDevice
+      else pure False
   setNonBlockingFD (fdFD fd) is_nonblock
 #if defined(mingw32_HOST_OS)
   return fd
diff --git a/src/GHC/Internal/IO/Handle/Lock/Flock.hsc b/src/GHC/Internal/IO/Handle/Lock/Flock.hsc
--- a/src/GHC/Internal/IO/Handle/Lock/Flock.hsc
+++ b/src/GHC/Internal/IO/Handle/Lock/Flock.hsc
@@ -10,7 +10,8 @@
 #include "HsBaseConfig.h"
 
 #if !HAVE_FLOCK
-import GHC.Internal.Base () -- Make implicit dependency known to build system
+-- See W1 of Note [Tracking dependencies on primitives] in GHC.Internal.Base
+import GHC.Types ()
 #else
 
 #include <sys/file.h>
diff --git a/src/GHC/Internal/IO/Handle/Lock/LinuxOFD.hsc b/src/GHC/Internal/IO/Handle/Lock/LinuxOFD.hsc
--- a/src/GHC/Internal/IO/Handle/Lock/LinuxOFD.hsc
+++ b/src/GHC/Internal/IO/Handle/Lock/LinuxOFD.hsc
@@ -10,7 +10,8 @@
 #include "HsBaseConfig.h"
 
 #if !HAVE_OFD_LOCKING
-import GHC.Internal.Base () -- Make implicit dependency known to build system
+-- See W1 of Note [Tracking dependencies on primitives] in GHC.Internal.Base
+import GHC.Types ()
 #else
 
 -- Not only is this a good idea but it also works around #17950.
diff --git a/src/GHC/Internal/IO/Handle/Lock/Windows.hsc b/src/GHC/Internal/IO/Handle/Lock/Windows.hsc
--- a/src/GHC/Internal/IO/Handle/Lock/Windows.hsc
+++ b/src/GHC/Internal/IO/Handle/Lock/Windows.hsc
@@ -10,7 +10,8 @@
 #include "HsBaseConfig.h"
 
 #if !defined(mingw32_HOST_OS)
-import GHC.Internal.Base () -- Make implicit dependency known to build system
+-- See W1 of Note [Tracking dependencies on primitives] in GHC.Internal.Base
+import GHC.Types ()
 #else
 
 ##include <windows_cconv.h>
diff --git a/src/GHC/Internal/IO/Handle/Types.hs-boot b/src/GHC/Internal/IO/Handle/Types.hs-boot
--- a/src/GHC/Internal/IO/Handle/Types.hs-boot
+++ b/src/GHC/Internal/IO/Handle/Types.hs-boot
@@ -2,7 +2,7 @@
 
 module GHC.Internal.IO.Handle.Types ( Handle ) where
 
--- See Note [Depend on GHC.Num.Integer] in GHC.Internal.Base
+-- See W1 of Note [Tracking dependencies on primitives] in GHC.Internal.Base
 import GHC.Types ()
 
 data Handle
diff --git a/src/GHC/Internal/InfoProv/Types.hsc b/src/GHC/Internal/InfoProv/Types.hsc
--- a/src/GHC/Internal/InfoProv/Types.hsc
+++ b/src/GHC/Internal/InfoProv/Types.hsc
@@ -18,8 +18,9 @@
     ) where
 
 import GHC.Internal.Base
-import GHC.Internal.Data.Maybe
 import GHC.Internal.Enum
+import GHC.Internal.Real (fromIntegral)
+import GHC.Internal.Word (Word32)
 import GHC.Internal.Show (Show)
 import GHC.Internal.Ptr (Ptr(..), plusPtr)
 import GHC.Internal.Foreign.C.String.Encoding (CString, peekCString)
@@ -28,7 +29,6 @@
 import GHC.Internal.IO.Encoding (utf8)
 import GHC.Internal.Foreign.Storable (peekByteOff)
 import GHC.Internal.ClosureTypes
-import GHC.Internal.Text.Read
 import GHC.Prim (whereFrom##)
 
 data InfoProv = InfoProv {
@@ -70,9 +70,11 @@
 ipeProv :: Ptr InfoProvEnt -> Ptr InfoProv
 ipeProv p = (#ptr InfoProvEnt, prov) p
 
-peekIpName, peekIpDesc, peekIpLabel, peekIpUnitId, peekIpModule, peekIpSrcFile, peekIpSrcSpan, peekIpTyDesc :: Ptr InfoProv -> IO CString
-peekIpName p    =  (# peek InfoProv, table_name) p
+peekIpDesc :: Ptr InfoProv -> IO Word32
 peekIpDesc p    =  (# peek InfoProv, closure_desc) p
+
+peekIpName, peekIpLabel, peekIpUnitId, peekIpModule, peekIpSrcFile, peekIpSrcSpan, peekIpTyDesc :: Ptr InfoProv -> IO CString
+peekIpName p    =  (# peek InfoProv, table_name) p
 peekIpLabel p   =  (# peek InfoProv, label) p
 peekIpUnitId p  =  (# peek InfoProv, unit_id) p
 peekIpModule p  =  (# peek InfoProv, module) p
@@ -83,7 +85,7 @@
 peekInfoProv :: Ptr InfoProv -> IO InfoProv
 peekInfoProv infop = do
   name <- peekCString utf8 =<< peekIpName infop
-  desc <- peekCString utf8 =<< peekIpDesc infop
+  desc <- peekIpDesc infop
   tyDesc <- peekCString utf8 =<< peekIpTyDesc infop
   label <- peekCString utf8 =<< peekIpLabel infop
   unit_id <- peekCString utf8 =<< peekIpUnitId infop
@@ -94,7 +96,7 @@
       ipName = name,
       -- The INVALID_OBJECT case should be impossible as we
       -- control the C code generating these values.
-      ipDesc = maybe INVALID_OBJECT toEnum . readMaybe @Int $ desc,
+      ipDesc = toEnum $ fromIntegral desc,
       ipTyDesc = tyDesc,
       ipLabel = label,
       ipUnitId = unit_id,
diff --git a/src/GHC/Internal/JS/Prim/Internal/Build.hs b/src/GHC/Internal/JS/Prim/Internal/Build.hs
--- a/src/GHC/Internal/JS/Prim/Internal/Build.hs
+++ b/src/GHC/Internal/JS/Prim/Internal/Build.hs
@@ -4,7 +4,8 @@
 #if !defined(javascript_HOST_ARCH)
 module GHC.Internal.JS.Prim.Internal.Build () where
 
-import GHC.Internal.Base () -- for build ordering
+-- See W1 of Note [Tracking dependencies on primitives] in GHC.Internal.Base
+import GHC.Types ()
 
 #else
 {-# LANGUAGE ForeignFunctionInterface, JavaScriptFFI, GHCForeignImportPrim #-}
diff --git a/src/GHC/Internal/Maybe.hs b/src/GHC/Internal/Maybe.hs
--- a/src/GHC/Internal/Maybe.hs
+++ b/src/GHC/Internal/Maybe.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude, StandaloneDeriving #-}
 {-# OPTIONS_HADDOCK not-home #-}
 
 -- | Maybe type
@@ -7,7 +7,7 @@
    )
 where
 
-import GHC.Num.Integer () -- See Note [Depend on GHC.Num.Integer] in GHC.Internal.Base
+-- See W1 of Note [Tracking dependencies on primitives] in GHC.Internal.Base
 import GHC.Classes
 
 default ()
diff --git a/src/GHC/Internal/Num.hs-boot b/src/GHC/Internal/Num.hs-boot
--- a/src/GHC/Internal/Num.hs-boot
+++ b/src/GHC/Internal/Num.hs-boot
@@ -6,7 +6,6 @@
 -- See Note [Semigroup stimes cycle] in GHC.Internal.Base
 
 import GHC.Num.Integer (Integer)
-import GHC.Types ()
 
 infixl 7  *
 infixl 6  +, -
diff --git a/src/GHC/Internal/Read.hs b/src/GHC/Internal/Read.hs
--- a/src/GHC/Internal/Read.hs
+++ b/src/GHC/Internal/Read.hs
@@ -551,7 +551,7 @@
   readList     = readListDefault
 
 --------------------------------------------------------------
--- GHC.Internal.Numeric instances of Read
+-- Numeric instances of Read
 --------------------------------------------------------------
 
 readNumber :: Num a => (L.Lexeme -> ReadPrec a) -> ReadPrec a
diff --git a/src/GHC/Internal/Real.hs b/src/GHC/Internal/Real.hs
--- a/src/GHC/Internal/Real.hs
+++ b/src/GHC/Internal/Real.hs
@@ -360,7 +360,7 @@
 {-# INLINE numericEnumFrom #-}  -- See Note [Inline Enum method helpers] in GHC.Internal.Enum
 numericEnumFrom n       = go 0
   where
-    -- See Note [GHC.Internal.Numeric Stability of Enumerating Floating Numbers]
+    -- See Note [Numeric Stability of Enumerating Floating Numbers]
     go !k = let !n' = n + k
              in n' : go (k + 1)
 
@@ -369,7 +369,7 @@
 numericEnumFromThen n m = go 0
   where
     step = m - n
-    -- See Note [GHC.Internal.Numeric Stability of Enumerating Floating Numbers]
+    -- See Note [Numeric Stability of Enumerating Floating Numbers]
     go !k = let !n' = n + k * step
              in n' : go (k + 1)
 
@@ -386,7 +386,7 @@
                                  !predicate | e2 >= e1  = (<= e3 + mid)
                                             | otherwise = (>= e3 + mid)
 
-{- Note [GHC.Internal.Numeric Stability of Enumerating Floating Numbers]
+{- Note [Numeric Stability of Enumerating Floating Numbers]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 When enumerate floating numbers, we could add the increment to the last number
 at every run (as what we did previously):
diff --git a/src/GHC/Internal/Real.hs-boot b/src/GHC/Internal/Real.hs-boot
--- a/src/GHC/Internal/Real.hs-boot
+++ b/src/GHC/Internal/Real.hs-boot
@@ -7,7 +7,6 @@
 
 import GHC.Classes (Ord)
 import GHC.Num.Integer (Integer)
-import GHC.Types ()
 
 import {-# SOURCE #-} GHC.Internal.Num (Num)
 import {-# SOURCE #-} GHC.Internal.Enum (Enum)
diff --git a/src/GHC/Internal/Records.hs b/src/GHC/Internal/Records.hs
--- a/src/GHC/Internal/Records.hs
+++ b/src/GHC/Internal/Records.hs
@@ -25,9 +25,8 @@
        ( HasField(..)
        ) where
 
--- The import of GHC.Internal.Base is for build ordering; see Notes in GHC.Internal.Base for
--- more info.
-import GHC.Internal.Base ()
+-- See W1 of Note [Tracking dependencies on primitives] in GHC.Internal.Base
+import GHC.Types ()
 
 -- | Constraint representing the fact that the field @x@ belongs to
 -- the record type @r@ and has field type @a@.  This will be solved
diff --git a/src/GHC/Internal/Stack/Types.hs b/src/GHC/Internal/Stack/Types.hs
--- a/src/GHC/Internal/Stack/Types.hs
+++ b/src/GHC/Internal/Stack/Types.hs
@@ -54,9 +54,7 @@
 import GHC.Classes (Eq)
 import GHC.Types (Char, Int)
 
--- Make implicit dependency known to build system
-import GHC.Tuple ()       -- See Note [Depend on GHC.Tuple] in GHC.Internal.Base
-import GHC.Num.Integer () -- See Note [Depend on GHC.Num.Integer] in GHC.Internal.Base
+default ()
 
 -- $setup
 -- >>> import Prelude
diff --git a/src/GHC/Internal/System/Posix/Internals.hs b/src/GHC/Internal/System/Posix/Internals.hs
--- a/src/GHC/Internal/System/Posix/Internals.hs
+++ b/src/GHC/Internal/System/Posix/Internals.hs
@@ -140,17 +140,30 @@
 fdType :: FD -> IO IODeviceType
 fdType fd = do (ty,_,_) <- fdStat fd; return ty
 
+-- | Return a known device type or throw an exception if the device
+-- type is unknown.
 statGetType :: Ptr CStat -> IO IODeviceType
 statGetType p_stat = do
+   dev_ty_m <- statGetType_maybe p_stat
+   case dev_ty_m of
+      Nothing -> ioError ioe_unknownfiletype
+      Just dev_ty -> pure dev_ty
+
+-- | Unlike @statGetType@, @statGetType_maybe@ will not throw an exception
+-- if the CStat refers to a unknown device type.
+--
+-- @since base-4.20.1.0
+statGetType_maybe :: Ptr CStat -> IO (Maybe IODeviceType)
+statGetType_maybe p_stat = do
   c_mode <- st_mode p_stat :: IO CMode
   case () of
-      _ | s_isdir c_mode        -> return Directory
+      _ | s_isdir c_mode        -> return $ Just Directory
         | s_isfifo c_mode || s_issock c_mode || s_ischr  c_mode
-                                -> return Stream
-        | s_isreg c_mode        -> return RegularFile
+                                -> return $ Just Stream
+        | s_isreg c_mode        -> return $ Just RegularFile
          -- Q: map char devices to RawDevice too?
-        | s_isblk c_mode        -> return RawDevice
-        | otherwise             -> ioError ioe_unknownfiletype
+        | s_isblk c_mode        -> return $ Just RawDevice
+        | otherwise             -> return Nothing
 
 ioe_unknownfiletype :: IOException
 ioe_unknownfiletype = IOError Nothing UnsupportedOperation "fdType"
diff --git a/src/GHC/Internal/TypeError.hs b/src/GHC/Internal/TypeError.hs
--- a/src/GHC/Internal/TypeError.hs
+++ b/src/GHC/Internal/TypeError.hs
@@ -32,7 +32,6 @@
   ) where
 
 import GHC.Internal.Data.Bool
-import GHC.Num.Integer () -- See Note [Depend on GHC.Num.Integer] in GHC.Internal.Base
 import GHC.Types (TYPE, Constraint, Symbol)
 
 {- Note [Custom type errors]
diff --git a/src/GHC/Internal/Wasm/Prim/Conc/Internal.hs b/src/GHC/Internal/Wasm/Prim/Conc/Internal.hs
--- a/src/GHC/Internal/Wasm/Prim/Conc/Internal.hs
+++ b/src/GHC/Internal/Wasm/Prim/Conc/Internal.hs
@@ -6,6 +6,8 @@
 
 import GHC.Internal.Base
 import GHC.Internal.IO
+
+-- See W6 of Note [Tracking dependencies on primitives] in GHC.Internal.Base
 import GHC.Internal.Wasm.Prim.Imports ()
 
 foreign import javascript safe "new Promise(res => setTimeout(res, $1 / 1000))"
