diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 ## Changelog for Weeder
 
+### [`2.4.0`][v2.4.0] - *2022-05-22*
+
+- Weeder has been upgraded to support GHC 9.2 (only). As this changes the
+  format of `.hie` files accepted, this is a major version bump.
+
 ### [`2.3.1`][v2.3.1] - *2022-05-21*
 
 This is the last release of `weeder` compatible with GHC 9.0.
@@ -15,7 +20,7 @@
     a, b :: Int
     (a, b) = (xxx, 1)
     ```
-    
+
     ... `weeder` will determine that both `a` and `b` depend on `xxx`. While this is an over-approximation, it prevents weeder from reporting false positives. For more information, see [#92](https://github.com/ocharles/weeder/issues/92).
 
 - Corrected a typo in `--help` ([#96](https://github.com/ocharles/weeder/pull/96)).
diff --git a/src/Weeder.hs b/src/Weeder.hs
--- a/src/Weeder.hs
+++ b/src/Weeder.hs
@@ -48,8 +48,12 @@
 import Data.Generics.Labels ()
 
 -- ghc
-import GHC.Types.Avail ( AvailInfo( Avail, AvailTC ) )
-import GHC.Types.FieldLabel ( FieldLbl( FieldLabel, flSelector ) )
+import GHC.Data.FastString ( unpackFS )
+import GHC.Types.Avail
+  ( AvailInfo( Avail, AvailTC )
+  , GreName( NormalGreName, FieldGreName )
+  )
+import GHC.Types.FieldLabel ( FieldLabel( FieldLabel, flSelector ) )
 import GHC.Iface.Ext.Types
   ( BindType( RegularBind )
   , ContextInfo( Decl, ValBind, PatternBind, Use, TyDecl, ClassTyDecl )
@@ -58,6 +62,7 @@
   , HieASTs( HieASTs )
   , HieFile( HieFile, hie_asts, hie_exports, hie_module, hie_hs_file )
   , IdentifierDetails( IdentifierDetails, identInfo )
+  , NodeAnnotation( NodeAnnotation, nodeAnnotType )
   , NodeInfo( nodeIdentifiers, nodeAnnotations )
   , Scope( ModuleScope )
   , getSourcedNodeInfo
@@ -188,14 +193,22 @@
 
 analyseExport :: MonadState Analysis m => Module -> AvailInfo -> m ()
 analyseExport m = \case
-  Avail name ->
-    for_ ( nameToDeclaration name ) addExport
+  Avail (NormalGreName name) ->
+    traverse_ addExport $ nameToDeclaration name
 
-  AvailTC name pieces fields -> do
+  Avail (FieldGreName (FieldLabel{ flSelector })) ->
+    traverse_ addExport $ nameToDeclaration flSelector
+
+  AvailTC name pieces -> do
     for_ ( nameToDeclaration name ) addExport
-    for_ pieces ( traverse_ addExport . nameToDeclaration )
-    for_ fields \FieldLabel{ flSelector } -> for_ ( nameToDeclaration flSelector ) addExport
 
+    for_ pieces \case
+      NormalGreName name ->
+        traverse_ addExport $ nameToDeclaration name
+
+      FieldGreName (FieldLabel{ flSelector }) ->
+        traverse_ addExport $ nameToDeclaration flSelector
+
   where
 
     addExport :: MonadState Analysis m => Declaration -> m ()
@@ -265,7 +278,7 @@
 analyseBinding :: ( Alternative m, MonadState Analysis m ) => HieAST a -> m ()
 analyseBinding n@Node{ nodeSpan, sourcedNodeInfo } = do
   let bindAnns = Set.fromList [("FunBind", "HsBindLR"), ("PatBind", "HsBindLR")]
-  guard $ any (not . Set.disjoint bindAnns . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
+  guard $ any (not . Set.disjoint bindAnns . Set.map unNodeAnnotation . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
 
   for_ ( findDeclarations n ) \d -> do
     define d nodeSpan
@@ -275,21 +288,21 @@
 
 analyseRewriteRule :: ( Alternative m, MonadState Analysis m ) => HieAST a -> m ()
 analyseRewriteRule n@Node{ sourcedNodeInfo } = do
-  guard $ any (Set.member ("HsRule", "RuleDecl") . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
+  guard $ any (Set.member ("HsRule", "RuleDecl") . Set.map unNodeAnnotation . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
 
   for_ ( uses n ) addImplicitRoot
 
 
 analyseInstanceDeclaration :: ( Alternative m, MonadState Analysis m ) => HieAST a -> m ()
 analyseInstanceDeclaration n@Node{ sourcedNodeInfo } = do
-  guard $ any (Set.member ("ClsInstD", "InstDecl") . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
+  guard $ any (Set.member ("ClsInstD", "InstDecl") . Set.map unNodeAnnotation . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
 
   traverse_ addImplicitRoot ( uses n )
 
 
 analyseClassDeclaration :: ( Alternative m, MonadState Analysis m ) => HieAST a -> m ()
 analyseClassDeclaration n@Node{ sourcedNodeInfo } = do
-  guard $ any (Set.member ("ClassDecl", "TyClDecl") . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
+  guard $ any (Set.member ("ClassDecl", "TyClDecl") . Set.map unNodeAnnotation . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
 
   for_ ( findIdentifiers isClassDeclaration n ) $
     for_ ( findIdentifiers ( const True ) n ) . addDependency
@@ -307,7 +320,7 @@
 
 analyseDataDeclaration :: ( Alternative m, MonadState Analysis m ) => HieAST a -> m ()
 analyseDataDeclaration n@Node{ sourcedNodeInfo } = do
-  guard $ any (Set.member ("DataDecl", "TyClDecl") . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
+  guard $ any (Set.member ("DataDecl", "TyClDecl") . Set.map unNodeAnnotation . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
 
   for_
     ( foldMap
@@ -334,7 +347,7 @@
 
 constructors :: HieAST a -> Seq ( HieAST a )
 constructors n@Node{ nodeChildren, sourcedNodeInfo } =
-  if any (any (\( _, t) -> t == "ConDecl" ) . nodeAnnotations) (getSourcedNodeInfo sourcedNodeInfo) then
+  if any (any ( ("ConDecl" ==) . unpackFS . nodeAnnotType) . nodeAnnotations) (getSourcedNodeInfo sourcedNodeInfo) then
     pure n
 
   else
@@ -342,7 +355,7 @@
 
 analysePatternSynonyms :: ( Alternative m, MonadState Analysis m ) => HieAST a -> m ()
 analysePatternSynonyms n@Node{ sourcedNodeInfo } = do
-  guard $ any (Set.member ("PatSynBind", "HsBindLR") . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
+  guard $ any (Set.member ("PatSynBind", "HsBindLR") . Set.map unNodeAnnotation . nodeAnnotations) $ getSourcedNodeInfo sourcedNodeInfo
 
   for_ ( findDeclarations n ) $ for_ ( uses n ) . addDependency
 
@@ -395,3 +408,7 @@
 nameToDeclaration name = do
   m <- nameModule_maybe name
   return Declaration { declModule = m, declOccName = nameOccName name }
+
+
+unNodeAnnotation :: NodeAnnotation -> (String, String)
+unNodeAnnotation (NodeAnnotation x y) = (unpackFS x, unpackFS y)
diff --git a/src/Weeder/Main.hs b/src/Weeder/Main.hs
--- a/src/Weeder/Main.hs
+++ b/src/Weeder/Main.hs
@@ -9,11 +9,16 @@
 
 module Weeder.Main ( main, mainWithConfig ) where
 
+-- algebraic-graphs
+import Algebra.Graph.Export.Dot ( export, defaultStyleViaShow )
+
 -- base
+import Control.Exception ( evaluate )
 import Control.Monad ( guard, unless, when )
 import Control.Monad.IO.Class ( liftIO )
 import Data.Bool
 import Data.Foldable
+import Data.IORef ( atomicModifyIORef, newIORef, readIORef )
 import Data.List ( isSuffixOf )
 import Data.Version ( showVersion )
 import System.Exit ( exitFailure )
@@ -119,14 +124,13 @@
       then getFilesIn ".hs" "./."
       else pure []
 
-  nameCache <- do
-    uniqSupply <- mkSplitUniqSupply 'z'
-    return ( initNameCache uniqSupply [] )
+  nameCacheUpdater <-
+    mkNameCacheUpdater
 
   analysis <-
     flip execStateT emptyAnalysis do
       for_ hieFilePaths \hieFilePath -> do
-        hieFileResult <- liftIO ( readCompatibleHieFileOrExit nameCache hieFilePath )
+        hieFileResult <- liftIO ( readCompatibleHieFileOrExit nameCacheUpdater hieFilePath )
         let hsFileExists = any ( hie_hs_file hieFileResult `isSuffixOf` ) hsFilePaths
         when (requireHsFiles ==> hsFileExists) do
           analyseHieFile hieFileResult
@@ -216,9 +220,9 @@
 
 
 -- | Read a .hie file, exiting if it's an incompatible version.
-readCompatibleHieFileOrExit :: NameCache -> FilePath -> IO HieFile
-readCompatibleHieFileOrExit nameCache path = do
-  res <- readHieFileWithVersion (\(v, _) -> v == hieVersion) (NCU (\f -> return $ snd $ f nameCache)) path
+readCompatibleHieFileOrExit :: NameCacheUpdater -> FilePath -> IO HieFile
+readCompatibleHieFileOrExit nameCacheUpdater path = do
+  res <- readHieFileWithVersion (\(v, _) -> v == hieVersion) nameCacheUpdater path
   case res of
     Right HieFileResult{ hie_file_result } ->
       return hie_file_result
@@ -232,6 +236,19 @@
                <> " as the project it is used on"
       exitFailure
 
+
+mkNameCacheUpdater :: IO NameCacheUpdater
+mkNameCacheUpdater = do
+  nameCache <- do
+    uniqSupply <- mkSplitUniqSupply 'z'
+    return ( initNameCache uniqSupply [] )
+
+  nameCacheRef <- newIORef nameCache
+
+  let update_nc f = do r <- atomicModifyIORef nameCacheRef f
+                       _ <- evaluate =<< readIORef nameCacheRef
+                       return r
+  return (NCU update_nc)
 
 
 infixr 5 ==>
diff --git a/weeder.cabal b/weeder.cabal
--- a/weeder.cabal
+++ b/weeder.cabal
@@ -5,7 +5,7 @@
 author:        Ollie Charles <ollie@ocharles.org.uk>
 maintainer:    Ollie Charles <ollie@ocharles.org.uk>
 build-type:    Simple
-version:       2.3.1
+version:       2.4.0
 copyright:     Neil Mitchell 2017-2020, Oliver Charles 2020
 synopsis:      Detect dead code
 description:   Find declarations.
@@ -18,16 +18,16 @@
 
 library
   build-depends:
-    , algebraic-graphs     ^>= 0.4 || ^>= 0.5 || ^>= 0.6
-    , base                 ^>= 4.15.0.0
+    , algebraic-graphs     ^>= 0.4 || ^>= 0.5  || ^>= 0.6
+    , base                 ^>= 4.16.0.0
     , bytestring           ^>= 0.10.9.0 || ^>= 0.11.0.0
     , containers           ^>= 0.6.2.1
     , dhall                ^>= 1.30.0 || ^>= 1.31.0 || ^>= 1.32.0 || ^>= 1.33.0 || ^>= 1.34.0 || ^>= 1.35.0 || ^>= 1.36.0 || ^>= 1.37.0 || ^>= 1.40.0 || ^>= 1.41
     , directory            ^>= 1.3.3.2
     , filepath             ^>= 1.4.2.1
     , generic-lens         ^>= 2.2.0.0
-    , ghc                  ^>= 9.0
-    , lens                 ^>= 4.18.1 || ^>= 4.19 || ^>= 5.0.1 || ^>= 5.1
+    , ghc                  ^>= 9.2
+    , lens                 ^>= 5.1
     , mtl                  ^>= 2.2.2
     , optparse-applicative ^>= 0.14.3.0 || ^>= 0.15.1.0 || ^>= 0.16.0.0 || ^>=  0.17
     , regex-tdfa           ^>= 1.2.0.0 || ^>= 1.3.1.0
