diff --git a/compiler/GHC/Hs/Binds.hs b/compiler/GHC/Hs/Binds.hs
index 2d67d7de27580f604f68c690009393ecb17a3ced..41977c86886e0a2a71ad9b0ce335a10d70dc25e3 100644
--- a/compiler/GHC/Hs/Binds.hs
+++ b/compiler/GHC/Hs/Binds.hs
@@ -85,7 +85,7 @@ data NHsValBindsLR idL
       [(RecFlag, LHsBinds idL)]
       [LSig GhcRn]
 
-type instance XValBinds    (GhcPass pL) (GhcPass pR) = AnnSortKey
+type instance XValBinds    (GhcPass pL) (GhcPass pR) = AnnSortKey BindTag
 type instance XXValBindsLR (GhcPass pL) pR
             = NHsValBindsLR (GhcPass pL)
 
diff --git a/compiler/GHC/Hs/Decls.hs b/compiler/GHC/Hs/Decls.hs
index 5aa28c240f105c41055ee2838214a88b929837f9..9185f785f2ca8b527acdcd977088bae6bb1b60e7 100644
--- a/compiler/GHC/Hs/Decls.hs
+++ b/compiler/GHC/Hs/Decls.hs
@@ -351,7 +351,7 @@ data DataDeclRn = DataDeclRn
              , tcdFVs      :: NameSet }
   deriving Data
 
-type instance XClassDecl    GhcPs = (EpAnn [AddEpAnn], AnnSortKey)
+type instance XClassDecl    GhcPs = (EpAnn [AddEpAnn], AnnSortKey DeclTag)
 
   -- TODO:AZ:tidy up AnnSortKey above
 type instance XClassDecl    GhcRn = NameSet -- FVs
@@ -803,7 +803,7 @@ type instance XCClsInstDecl    GhcPs = ( Maybe (LWarningTxt GhcPs)
                                              -- See Note [Implementation of deprecated instances]
                                              -- in GHC.Tc.Solver.Dict
                                        , EpAnn [AddEpAnn]
-                                       , AnnSortKey) -- For sorting the additional annotations
+                                       , AnnSortKey DeclTag) -- For sorting the additional annotations
                                         -- TODO:AZ:tidy up
 type instance XCClsInstDecl    GhcRn = Maybe (LWarningTxt GhcRn)
                                            -- The warning of the deprecated instance
diff --git a/compiler/GHC/Parser/Annotation.hs b/compiler/GHC/Parser/Annotation.hs
index 1cd22a9190311fc3a2cc5bc912a72315cbe5896a..d14a6a2070cf4c6c5ef056e7a36a9910d5c9c3bd 100644
--- a/compiler/GHC/Parser/Annotation.hs
+++ b/compiler/GHC/Parser/Annotation.hs
@@ -41,7 +41,7 @@ module GHC.Parser.Annotation (
   AnnContext(..),
   NameAnn(..), NameAdornment(..),
   NoEpAnns(..),
-  AnnSortKey(..),
+  AnnSortKey(..), DeclTag(..), BindTag(..),
 
   -- ** Trailing annotations in lists
   TrailingAnn(..), trailingAnnToAddEpAnn,
@@ -798,18 +798,119 @@ data AnnPragma
       } deriving (Data,Eq)
 
 -- ---------------------------------------------------------------------
--- | Captures the sort order of sub elements. This is needed when the
--- sub-elements have been split (as in a HsLocalBind which holds separate
--- binds and sigs) or for infix patterns where the order has been
--- re-arranged. It is captured explicitly so that after the Delta phase a
--- SrcSpan is used purely as an index into the annotations, allowing
--- transformations of the AST including the introduction of new Located
--- items or re-arranging existing ones.
-data AnnSortKey
+
+-- | Captures the sort order of sub elements for `ValBinds`,
+-- `ClassDecl`, `ClsInstDecl`
+data AnnSortKey tag
+  -- See Note [AnnSortKey] below
   = NoAnnSortKey
-  | AnnSortKey [RealSrcSpan]
+  | AnnSortKey [tag]
   deriving (Data, Eq)
 
+-- | Used to track of interleaving of binds and signatures for ValBind
+data BindTag
+  -- See Note [AnnSortKey] below
+  = BindTag
+  | SigDTag
+  deriving (Eq,Data,Ord,Show)
+
+-- | Used to track interleaving of class methods, class signatures,
+-- associated types and associate type defaults in `ClassDecl` and
+-- `ClsInstDecl`.
+data DeclTag
+  -- See Note [AnnSortKey] below
+  = ClsMethodTag
+  | ClsSigTag
+  | ClsAtTag
+  | ClsAtdTag
+  deriving (Eq,Data,Ord,Show)
+
+{-
+Note [AnnSortKey]
+~~~~~~~~~~~~~~~~~
+
+For some constructs in the ParsedSource we have mixed lists of items
+that can be freely intermingled.
+
+An example is the binds in a where clause, captured in
+
+    ValBinds
+        (XValBinds idL idR)
+        (LHsBindsLR idL idR) [LSig idR]
+
+This keeps separate ordered collections of LHsBind GhcPs and LSig GhcPs.
+
+But there is no constraint on the original source code as to how these
+should appear, so they can have all the signatures first, then their
+binds, or grouped with a signature preceding each bind.
+
+   fa :: Int
+   fa = 1
+
+   fb :: Char
+   fb = 'c'
+
+Or
+
+   fa :: Int
+   fb :: Char
+
+   fb = 'c'
+   fa = 1
+
+When exact printing these, we need to restore the original order. As
+initially parsed we have the SrcSpan, and can sort on those. But if we
+have modified the AST prior to printing, we cannot rely on the
+SrcSpans for order any more.
+
+The bag of LHsBind GhcPs is physically ordered, as is the list of LSig
+GhcPs. So in effect we have a list of binds in the order we care
+about, and a list of sigs in the order we care about. The only problem
+is to know how to merge the lists.
+
+This is where AnnSortKey comes in, which we store in the TTG extension
+point for ValBinds.
+
+    data AnnSortKey tag
+      = NoAnnSortKey
+      | AnnSortKey [tag]
+
+When originally parsed, with SrcSpans we can rely on, we do not need
+any extra information, so we tag it with NoAnnSortKey.
+
+If the binds and signatures are updated in any way, such that we can
+no longer rely on their SrcSpans (e.g. they are copied from elsewhere,
+parsed from scratch for insertion, have a fake SrcSpan), we use
+`AnnSortKey [BindTag]` to keep track.
+
+    data BindTag
+      = BindTag
+      | SigDTag
+
+We use it as a merge selector, and have one entry for each bind and
+signature.
+
+So for the first example we have
+
+  binds: fa = 1 , fb = 'c'
+  sigs:  fa :: Int, fb :: Char
+  tags: SigTag, BindTag, SigTag, BindTag
+
+so we draw first from the signatures, then the binds, and same again.
+
+For the second example we have
+
+  binds: fb = 'c', fa = 1
+  sigs:  fa :: Int, fb :: Char
+  tags: SigTag, SigTag, BindTag, BindTag
+
+so we draw two signatures, then two binds.
+
+We do similar for ClassDecl and ClsInstDecl, but we have four
+different lists we must manage. For this we use DeclTag.
+
+-}
+
 -- ---------------------------------------------------------------------
 
 -- | Convert a 'TrailingAnn' to an 'AddEpAnn'
@@ -1249,12 +1350,12 @@ instance Monoid NameAnn where
   mempty = NameAnnTrailing []
 
 
-instance Semigroup AnnSortKey where
+instance Semigroup (AnnSortKey tag) where
   NoAnnSortKey <> x = x
   x <> NoAnnSortKey = x
   AnnSortKey ls1 <> AnnSortKey ls2 = AnnSortKey (ls1 <> ls2)
 
-instance Monoid AnnSortKey where
+instance Monoid (AnnSortKey tag) where
   mempty = NoAnnSortKey
 
 instance (Outputable a) => Outputable (EpAnn a) where
@@ -1288,7 +1389,13 @@ instance (NamedThing (Located a)) => NamedThing (LocatedAn an a) where
 instance Outputable AnnContext where
   ppr (AnnContext a o c) = text "AnnContext" <+> ppr a <+> ppr o <+> ppr c
 
-instance Outputable AnnSortKey where
+instance Outputable BindTag where
+  ppr tag = text $ show tag
+
+instance Outputable DeclTag where
+  ppr tag = text $ show tag
+
+instance Outputable tag => Outputable (AnnSortKey tag) where
   ppr NoAnnSortKey    = text "NoAnnSortKey"
   ppr (AnnSortKey ls) = text "AnnSortKey" <+> ppr ls
 
diff --git a/testsuite/tests/ghc-api/exactprint/AddClassMethod.expected.hs b/testsuite/tests/ghc-api/exactprint/AddClassMethod.expected.hs
new file mode 100644
index 0000000000000000000000000000000000000000..1943008778caed2ef78ad1af83fc626370e42cef
--- /dev/null
+++ b/testsuite/tests/ghc-api/exactprint/AddClassMethod.expected.hs
@@ -0,0 +1,10 @@
+module AddClassMethod where
+
+class Foo where
+  f1 :: Int
+
+  nn :: Int
+  nn = 2
+
+  f2 :: Int
+  f2 = 1
diff --git a/testsuite/tests/ghc-api/exactprint/AddClassMethod.hs b/testsuite/tests/ghc-api/exactprint/AddClassMethod.hs
new file mode 100644
index 0000000000000000000000000000000000000000..09fde257abc1439d3482fbbb02827e16dfb62f6f
--- /dev/null
+++ b/testsuite/tests/ghc-api/exactprint/AddClassMethod.hs
@@ -0,0 +1,7 @@
+module AddClassMethod where
+
+class Foo where
+  f1 :: Int
+
+  f2 :: Int
+  f2 = 1
diff --git a/testsuite/tests/ghc-api/exactprint/Makefile b/testsuite/tests/ghc-api/exactprint/Makefile
index 8d3b71ac9bf2991a437a8a6392140c94d8edc26b..05f9b098971d5a11a61cd7819bbf7fd3ba89f43f 100644
--- a/testsuite/tests/ghc-api/exactprint/Makefile
+++ b/testsuite/tests/ghc-api/exactprint/Makefile
@@ -158,3 +158,7 @@ AddHiding1:
 .PHONY: AddHiding2
 AddHiding2:
 	$(CHECK_EXACT) $(LIBDIR) AddHiding2.hs addHiding2
+
+.PHONY: AddClassMethod
+AddClassMethod:
+	$(CHECK_EXACT) $(LIBDIR) AddClassMethod.hs addClassMethod
diff --git a/testsuite/tests/ghc-api/exactprint/all.T b/testsuite/tests/ghc-api/exactprint/all.T
index 6bbb5807c21cc7135b8f9fb4969d691123f3844a..8ba046ce42388e3386f85000a87c82d46730bf5b 100644
--- a/testsuite/tests/ghc-api/exactprint/all.T
+++ b/testsuite/tests/ghc-api/exactprint/all.T
@@ -36,6 +36,7 @@ test('RmTypeSig1',    ignore_stderr, makefile_test, ['RmTypeSig1'])
 test('RmTypeSig2',    ignore_stderr, makefile_test, ['RmTypeSig2'])
 test('AddHiding1',    ignore_stderr, makefile_test, ['AddHiding1'])
 test('AddHiding2',    ignore_stderr, makefile_test, ['AddHiding2'])
+test('AddClassMethod',ignore_stderr, makefile_test, ['AddClassMethod'])
 test('Test20239',  normal, compile_fail, ['-dsuppress-uniques -ddump-parsed-ast -dkeep-comments'])
 test('ZeroWidthSemi',  normal, compile, ['-dsuppress-uniques -ddump-parsed-ast -dkeep-comments'])
 test('T22919',  normal, compile, ['-dsuppress-uniques -ddump-parsed-ast -dkeep-comments'])
diff --git a/utils/check-exact/ExactPrint.hs b/utils/check-exact/ExactPrint.hs
index 215a19dd2492173e5dc2527a991cfd792a0b9943..ff0671611c66af0c2c0199599614f3249a0bf6b8 100644
--- a/utils/check-exact/ExactPrint.hs
+++ b/utils/check-exact/ExactPrint.hs
@@ -63,6 +63,7 @@ import Data.Functor.Const
 import qualified Data.Set as Set
 import Data.Typeable
 import Data.List ( partition, sort, sortBy)
+import qualified Data.Map.Strict as Map
 import Data.Maybe ( isJust, mapMaybe )
 import Data.Void
 
@@ -2009,11 +2010,11 @@ instance ExactPrint (ClsInstDecl GhcPs) where
           an1 <- markEpAnnL an0 lidl AnnOpenC
           an2 <- markEpAnnAllL an1 lid AnnSemi
           ds <- withSortKey sortKey
-                               (prepareListAnnotationA ats
-                             ++ prepareListAnnotationF an adts
-                             ++ prepareListAnnotationA (bagToList binds)
-                             ++ prepareListAnnotationA sigs
-                               )
+                               [(ClsAtdTag, prepareListAnnotationA ats),
+                                (ClsAtdTag, prepareListAnnotationF an adts),
+                                (ClsMethodTag, prepareListAnnotationA (bagToList binds)),
+                                (ClsSigTag, prepareListAnnotationA sigs)
+                               ]
           an3 <- markEpAnnL an2 lidl AnnCloseC -- '}'
           let
             ats'   = undynamic ds
@@ -2320,13 +2321,10 @@ instance ExactPrint (HsValBindsLR GhcPs GhcPs) where
   setAnnotationAnchor a _ _ = a
 
   exact (ValBinds sortKey binds sigs) = do
-    ds <- setLayoutBoth $ withSortKey sortKey
-       (prepareListAnnotationA (bagToList binds)
-     ++ prepareListAnnotationA sigs
-       )
+    decls <- setLayoutBoth $ mapM markAnnotated $ hsDeclsValBinds (ValBinds sortKey binds sigs)
     let
-      binds' = listToBag $ undynamic ds
-      sigs'  = undynamic ds
+      binds' = listToBag $ concatMap decl2Bind decls
+      sigs'  =             concatMap decl2Sig decls
     return (ValBinds sortKey binds' sigs')
   exact (XValBindsLR _) = panic "XValBindsLR"
 
@@ -2381,20 +2379,14 @@ prepareListAnnotationA ls = map (\b -> (realSrcSpan $ getLocA b,go b)) ls
       b' <- markAnnotated b
       return (toDyn b')
 
-withSortKey :: (Monad m, Monoid w) => AnnSortKey -> [(RealSrcSpan, EP w m Dynamic)] -> EP w m [Dynamic]
+withSortKey :: (Monad m, Monoid w)
+  => AnnSortKey DeclTag -> [(DeclTag, [(RealSrcSpan, EP w m Dynamic)])] -> EP w m [Dynamic]
 withSortKey annSortKey xs = do
   debugM $ "withSortKey:annSortKey=" ++ showAst annSortKey
   let ordered = case annSortKey of
-                  NoAnnSortKey -> sortBy orderByFst xs
-                  -- Just keys -> error $ "withSortKey: keys" ++ show keys
-                  AnnSortKey keys -> orderByKey xs keys
-                                -- `debug` ("withSortKey:" ++
-                                --          showPprUnsafe (map fst (sortBy (comparing (flip elemIndex keys . fst)) xs),
-                                --                  map fst xs,
-                                --                  keys)
-                                --          )
+                  NoAnnSortKey -> sortBy orderByFst $ concatMap snd xs
+                  AnnSortKey _keys -> orderedDecls annSortKey (Map.fromList xs)
   mapM snd ordered
-
 orderByFst :: Ord a => (a, b1) -> (a, b2) -> Ordering
 orderByFst (a,_) (b,_) = compare a b
 
@@ -3497,12 +3489,12 @@ instance ExactPrint (TyClDecl GhcPs) where
           an1 <- markEpAnnL    an0 lidl AnnOpenC
           an2 <- markEpAnnAllL an1 lidl AnnSemi
           ds <- withSortKey sortKey
-                               (prepareListAnnotationA sigs
-                             ++ prepareListAnnotationA (bagToList methods)
-                             ++ prepareListAnnotationA ats
-                             ++ prepareListAnnotationA at_defs
+                               [(ClsSigTag, prepareListAnnotationA sigs),
+                                (ClsMethodTag, prepareListAnnotationA (bagToList methods)),
+                                (ClsAtTag, prepareListAnnotationA ats),
+                                (ClsAtdTag, prepareListAnnotationA at_defs)
                              -- ++ prepareListAnnotation docs
-                               )
+                               ]
           an3 <- markEpAnnL an2 lidl AnnCloseC
           let
             sigs'    = undynamic ds
diff --git a/utils/check-exact/Main.hs b/utils/check-exact/Main.hs
index b498f6cc48af03c50fa8a25e2a1bb06d54a11f26..e1a5a2f7cc39100fc852eed16013e170fe9a55a2 100644
--- a/utils/check-exact/Main.hs
+++ b/utils/check-exact/Main.hs
@@ -251,6 +251,7 @@ changers =
   ,("rmTypeSig2",        rmTypeSig2)
   ,("addHiding1",        addHiding1)
   ,("addHiding2",        addHiding2)
+  ,("addClassMethod",    addClassMethod)
    ]
 
 -- ---------------------------------------------------------------------
@@ -520,7 +521,7 @@ changeLocalDecls libdir (L l p) = do
         let oldBinds     = concatMap decl2Bind oldDecls'
             (os:oldSigs) = concatMap decl2Sig  oldDecls'
             os' = setEntryDP os (DifferentLine 2 0)
-        let sortKey = captureOrder decls
+        let sortKey = captureOrderBinds decls
         let (EpAnn anc (AnnList (Just (Anchor anc2 _)) a b c dd) cs) = van
         let van' = (EpAnn anc (AnnList (Just (Anchor anc2 (MovedAnchor (DifferentLine 1 4)))) a b c dd) cs)
         let binds' = (HsValBinds van'
@@ -553,7 +554,7 @@ changeLocalDecls2 libdir (L l p) = do
                                  [AddEpAnn AnnWhere (EpaDelta (SameLine 0) [])] [])
                         emptyComments
         let decls = [s,d]
-        let sortKey = captureOrder decls
+        let sortKey = captureOrderBinds decls
         let binds = (HsValBinds an (ValBinds sortKey (listToBag $ [decl'])
                                     [sig']))
         return (L lm (Match ma mln pats (GRHSs emptyComments rhs binds)))
@@ -798,7 +799,7 @@ rmDecl5 _libdir lp = do
         let
           go :: HsExpr GhcPs -> Transform (HsExpr GhcPs)
           go (HsLet a tkLet lb tkIn expr) = do
-            decs <- hsDeclsValBinds lb
+            let decs = hsDeclsLocalBinds lb
             let hdecs : _ = decs
             let dec = last decs
             _ <- transferEntryDP hdecs dec
@@ -945,6 +946,24 @@ addHiding2 _libdir top = do
   debugM $ "log:[\n" ++ intercalate "\n" _w ++ "]log end\n"
   return lp'
 
+-- ---------------------------------------------------------------------
+
+addClassMethod :: Changer
+addClassMethod libdir lp = do
+  Right sig  <- withDynFlags libdir (\df -> parseDecl df "sig"  "nn :: Int")
+  Right decl <- withDynFlags libdir (\df -> parseDecl df "decl" "nn = 2")
+  let decl' = setEntryDP decl (DifferentLine 1 2)
+  let  sig' = setEntryDP sig  (DifferentLine 2 2)
+  let doAddMethod = do
+        [cd] <- hsDecls lp
+        (f1:f2s:f2d:_) <- hsDecls cd
+        let  f2s' = setEntryDP f2s  (DifferentLine 2 2)
+        cd' <- replaceDecls cd [f1, sig', decl', f2s', f2d]
+        replaceDecls lp [cd']
+
+  (lp',_,w) <- runTransformT doAddMethod
+  debugM $ "addClassMethod:" ++ intercalate "\n" w
+  return lp'
 
 -- ---------------------------------------------------------------------
 -- From SYB
diff --git a/utils/check-exact/Transform.hs b/utils/check-exact/Transform.hs
index 45f3612a768c1be507a3fdc6ed28bb331fd9c018..340fa43cfafa2ec7c84231ef440d9cd6e2579cd7 100644
--- a/utils/check-exact/Transform.hs
+++ b/utils/check-exact/Transform.hs
@@ -68,7 +68,7 @@ module Transform
         , anchorEof
 
         -- ** Managing lists, pure functions
-        , captureOrder
+        , captureOrderBinds
         , captureLineSpacing
         , captureMatchLineSpacing
         , captureTypeSigSpacing
@@ -97,7 +97,6 @@ import GHC.Data.Bag
 import GHC.Data.FastString
 
 import Data.Data
-import Data.List ( sortBy )
 import Data.Maybe
 
 import Data.Functor.Identity
@@ -175,10 +174,12 @@ srcSpanStartLine' _ = 0
 
 -- ---------------------------------------------------------------------
 
--- |If a list has been re-ordered or had items added, capture the new order in
--- the appropriate 'AnnSortKey' attached to the 'Annotation' for the list.
-captureOrder :: [LocatedA b] -> AnnSortKey
-captureOrder ls = AnnSortKey $ map (rs . getLocA) ls
+captureOrderBinds :: [LHsDecl GhcPs] -> AnnSortKey BindTag
+captureOrderBinds ls = AnnSortKey $ map go ls
+  where
+    go (L _ (ValD _ _))       = BindTag
+    go (L _ (SigD _ _))       = SigDTag
+    go d      = error $ "captureOrderBinds:" ++ showGhc d
 
 -- ---------------------------------------------------------------------
 
@@ -239,34 +240,6 @@ captureTypeSigSpacing s = s
 
 -- ---------------------------------------------------------------------
 
--- |Pure function to convert a 'LHsDecl' to a 'LHsBind'. This does
--- nothing to any annotations that may be attached to either of the elements.
--- It is used as a utility function in 'replaceDecls'
-decl2Bind :: LHsDecl GhcPs -> [LHsBind GhcPs]
-decl2Bind (L l (ValD _ s)) = [L l s]
-decl2Bind _                      = []
-
--- |Pure function to convert a 'LSig' to a 'LHsBind'. This does
--- nothing to any annotations that may be attached to either of the elements.
--- It is used as a utility function in 'replaceDecls'
-decl2Sig :: LHsDecl GhcPs -> [LSig GhcPs]
-decl2Sig (L l (SigD _ s)) = [L l s]
-decl2Sig _                = []
-
--- ---------------------------------------------------------------------
-
--- |Convert a 'LSig' into a 'LHsDecl'
-wrapSig :: LSig GhcPs -> LHsDecl GhcPs
-wrapSig (L l s) = L l (SigD NoExtField s)
-
--- ---------------------------------------------------------------------
-
--- |Convert a 'LHsBind' into a 'LHsDecl'
-wrapDecl :: LHsBind GhcPs -> LHsDecl GhcPs
-wrapDecl (L l s) = L l (ValD NoExtField s)
-
--- ---------------------------------------------------------------------
-
 setEntryDPDecl :: LHsDecl GhcPs -> DeltaPos -> LHsDecl GhcPs
 setEntryDPDecl decl@(L _  (ValD x (FunBind a b (MG c (L d ms ))))) dp
                    = L l' (ValD x (FunBind a b (MG c (L d ms'))))
@@ -520,7 +493,7 @@ pushTrailingComments _ _cs (HsIPBinds _ _) = error "TODO: pushTrailingComments:H
 pushTrailingComments w cs lb@(HsValBinds an _)
   = (True, HsValBinds an' vb)
   where
-    (decls, _, _ws1) = runTransform (hsDeclsValBinds lb)
+    decls = hsDeclsLocalBinds lb
     (an', decls') = case reverse decls of
       [] -> (addCommentsToEpAnn (spanHsLocaLBinds lb) an cs, decls)
       (L la d:ds) -> (an, L (addCommentsToSrcAnn la cs) d:ds)
@@ -888,13 +861,24 @@ instance HasDecls ParsedSource where
   replaceDecls (L l (HsModule (XModulePs a lo deps haddocks) mname exps imps _decls)) decls
     = do
         logTr "replaceDecls LHsModule"
-        -- modifyAnnsT (captureOrder m decls)
         return (L l (HsModule (XModulePs a lo deps haddocks) mname exps imps decls))
 
 -- ---------------------------------------------------------------------
 
+instance HasDecls (LocatedA (HsDecl GhcPs)) where
+  hsDecls (L _ (TyClD _ c@ClassDecl{}))  = return $ hsDeclsClassDecl c
+  hsDecls decl = do
+    error $ "hsDecls:decl=" ++ showAst decl
+  replaceDecls (L l (TyClD e dec@ClassDecl{})) decls = do
+    let decl' = replaceDeclsClassDecl dec decls
+    return (L l (TyClD e decl'))
+  replaceDecls decl _decls = do
+    error $ "replaceDecls:decl=" ++ showAst decl
+
+-- ---------------------------------------------------------------------
+
 instance HasDecls (LocatedA (Match GhcPs (LocatedA (HsExpr GhcPs)))) where
-  hsDecls (L _ (Match _ _ _ (GRHSs _ _ lb))) = hsDeclsValBinds lb
+  hsDecls (L _ (Match _ _ _ (GRHSs _ _ lb))) = return $ hsDeclsLocalBinds lb
 
   replaceDecls (L l (Match xm c p (GRHSs xr rhs binds))) []
     = do
@@ -923,7 +907,7 @@ instance HasDecls (LocatedA (Match GhcPs (LocatedA (HsExpr GhcPs)))) where
 -- ---------------------------------------------------------------------
 
 instance HasDecls (LocatedA (HsExpr GhcPs)) where
-  hsDecls (L _ (HsLet _ _ decls _ _ex)) = hsDeclsValBinds decls
+  hsDecls (L _ (HsLet _ _ decls _ _ex)) = return $ hsDeclsLocalBinds decls
   hsDecls _                             = return []
 
   replaceDecls (L ll (HsLet x tkLet binds tkIn ex)) newDecls
@@ -965,7 +949,7 @@ instance HasDecls (LocatedA (HsExpr GhcPs)) where
 -- cannot be a member of 'HasDecls' because a 'FunBind' is not idempotent
 -- for 'hsDecls' \/ 'replaceDecls'. 'hsDeclsPatBindD' \/ 'replaceDeclsPatBindD' is
 -- idempotent.
-hsDeclsPatBindD :: (Monad m) => LHsDecl GhcPs -> TransformT m [LHsDecl GhcPs]
+hsDeclsPatBindD :: LHsDecl GhcPs -> [LHsDecl GhcPs]
 hsDeclsPatBindD (L l (ValD _ d)) = hsDeclsPatBind (L l d)
 hsDeclsPatBindD x = error $ "hsDeclsPatBindD called for:" ++ showGhc x
 
@@ -973,8 +957,8 @@ hsDeclsPatBindD x = error $ "hsDeclsPatBindD called for:" ++ showGhc x
 -- cannot be a member of 'HasDecls' because a 'FunBind' is not idempotent
 -- for 'hsDecls' \/ 'replaceDecls'. 'hsDeclsPatBind' \/ 'replaceDeclsPatBind' is
 -- idempotent.
-hsDeclsPatBind :: (Monad m) => LHsBind GhcPs -> TransformT m [LHsDecl GhcPs]
-hsDeclsPatBind (L _ (PatBind _ _ (GRHSs _ _grhs lb))) = hsDeclsValBinds lb
+hsDeclsPatBind :: LHsBind GhcPs -> [LHsDecl GhcPs]
+hsDeclsPatBind (L _ (PatBind _ _ (GRHSs _ _grhs lb))) = hsDeclsLocalBinds lb
 hsDeclsPatBind x = error $ "hsDeclsPatBind called for:" ++ showGhc x
 
 -- -------------------------------------
@@ -1006,7 +990,7 @@ replaceDeclsPatBind x _ = error $ "replaceDeclsPatBind called for:" ++ showGhc x
 -- ---------------------------------------------------------------------
 
 instance HasDecls (LocatedA (Stmt GhcPs (LocatedA (HsExpr GhcPs)))) where
-  hsDecls (L _ (LetStmt _ lb))      = hsDeclsValBinds lb
+  hsDecls (L _ (LetStmt _ lb))      = return $ hsDeclsLocalBinds lb
   hsDecls (L _ (LastStmt _ e _ _))  = hsDecls e
   hsDecls (L _ (BindStmt _ _pat e)) = hsDecls e
   hsDecls (L _ (BodyStmt _ e _ _))  = hsDecls e
@@ -1035,35 +1019,6 @@ instance HasDecls (LocatedA (Stmt GhcPs (LocatedA (HsExpr GhcPs)))) where
 -- end of HasDecls instances
 -- =====================================================================
 
--- ---------------------------------------------------------------------
-
--- |Look up the annotated order and sort the decls accordingly
--- TODO:AZ: this should be pure
-orderedDecls :: (Monad m)
-             => AnnSortKey -> [LHsDecl GhcPs] -> TransformT m [LHsDecl GhcPs]
-orderedDecls sortKey decls = do
-  case sortKey of
-    NoAnnSortKey -> do
-      -- return decls
-      return $ sortBy (\a b -> compare (realSrcSpan $ getLocA a) (realSrcSpan $ getLocA b)) decls
-    AnnSortKey keys -> do
-      let ds = map (\s -> (rs $ getLocA s,s)) decls
-          ordered = map snd $ orderByKey ds keys
-      return ordered
-
--- ---------------------------------------------------------------------
-
-hsDeclsValBinds :: (Monad m) => HsLocalBinds GhcPs -> TransformT m [LHsDecl GhcPs]
-hsDeclsValBinds lb = case lb of
-    HsValBinds _ (ValBinds sortKey bs sigs) -> do
-      let
-        bds = map wrapDecl (bagToList bs)
-        sds = map wrapSig sigs
-      orderedDecls sortKey (bds ++ sds)
-    HsValBinds _ (XValBindsLR _) -> error $ "hsDecls.XValBindsLR not valid"
-    HsIPBinds {}       -> return []
-    EmptyLocalBinds {} -> return []
-
 data WithWhere = WithWhere
                | WithoutWhere
                deriving (Eq,Show)
@@ -1085,7 +1040,7 @@ replaceDeclsValbinds w b@(HsValBinds a _) new
         an <- oldWhereAnnotation a w (realSrcSpan oldSpan)
         let decs = listToBag $ concatMap decl2Bind new
         let sigs = concatMap decl2Sig new
-        let sortKey = captureOrder new
+        let sortKey = captureOrderBinds new
         return (HsValBinds an (ValBinds sortKey decs sigs))
 replaceDeclsValbinds _ (HsIPBinds {}) _new    = error "undefined replaceDecls HsIPBinds"
 replaceDeclsValbinds w (EmptyLocalBinds _) new
@@ -1096,7 +1051,7 @@ replaceDeclsValbinds w (EmptyLocalBinds _) new
             newSigs  = concatMap decl2Sig  new
         let decs = listToBag $ newBinds
         let sigs = newSigs
-        let sortKey = captureOrder new
+        let sortKey = captureOrderBinds new
         return (HsValBinds an (ValBinds sortKey decs sigs))
 
 oldWhereAnnotation :: (Monad m)
@@ -1160,7 +1115,7 @@ modifyValD :: forall m t. (HasTransform m)
 modifyValD p pb@(L ss (ValD _ (PatBind {} ))) f =
   if (locA ss) == p
      then do
-       ds <- liftT $ hsDeclsPatBindD pb
+       let ds = hsDeclsPatBindD pb
        (ds',r) <- f (error "modifyValD.PatBind should not touch Match") ds
        pb' <- liftT $ replaceDeclsPatBindD pb ds'
        return (pb',r)
diff --git a/utils/check-exact/Utils.hs b/utils/check-exact/Utils.hs
index 14a05a23378682d7dcc83c81dfd752aad79855cf..59353df8245ae04811a1e51e65be378ea65cb93d 100644
--- a/utils/check-exact/Utils.hs
+++ b/utils/check-exact/Utils.hs
@@ -31,6 +31,7 @@ import qualified Orphans as Orphans
 
 import GHC hiding (EpaComment)
 import qualified GHC
+import GHC.Data.Bag
 import GHC.Types.Name
 import GHC.Types.Name.Reader
 import GHC.Types.SrcLoc
@@ -40,6 +41,7 @@ import qualified GHC.Data.Strict as Strict
 
 import Data.Data hiding ( Fixity )
 import Data.List (sortBy, elemIndex)
+import qualified Data.Map.Strict as Map
 
 import Debug.Trace
 import Types
@@ -193,7 +195,7 @@ tweakDelta (DifferentLine l d) = DifferentLine l (d-1)
 
 -- |Given a list of items and a list of keys, returns a list of items
 -- ordered by their position in the list of keys.
-orderByKey :: [(RealSrcSpan,a)] -> [RealSrcSpan] -> [(RealSrcSpan,a)]
+orderByKey :: [(DeclTag,a)] -> [DeclTag] -> [(DeclTag,a)]
 orderByKey keys order
     -- AZ:TODO: if performance becomes a problem, consider a Map of the order
     -- SrcSpan to an index, and do a lookup instead of elemIndex.
@@ -439,12 +441,162 @@ hackAnchorToSrcSpan (Anchor r (MovedAnchor dp))
     s = - (getDeltaLine dp)
     e = - (deltaColumn dp)
 
- -- ---------------------------------------------------------------------
+-- ---------------------------------------------------------------------
+
+type DeclsByTag a = Map.Map DeclTag [(RealSrcSpan, a)]
+
+orderedDecls
+  :: AnnSortKey DeclTag
+  -> DeclsByTag a
+  -> [(RealSrcSpan, a)]
+orderedDecls sortKey declGroup  =
+  case sortKey of
+    NoAnnSortKey ->
+      sortBy (\a b -> compare (fst a) (fst b)) (concat $ Map.elems declGroup)
+    AnnSortKey keys ->
+      let
+        go :: [DeclTag] -> DeclsByTag a -> [(RealSrcSpan, a)]
+        go [] _                      = []
+        go (tag:ks) dbt = d : go ks dbt'
+          where
+            dbt' = Map.adjust (\ds -> drop 1 ds) tag dbt
+            d = case Map.lookup tag dbt of
+              Just (d':_) -> d'
+              _           -> error $ "orderedDecls: could not look up "
+                                       ++ show tag ++ " in " ++ show (Map.keys dbt)
+      in
+        go keys declGroup
+
+hsDeclsClassDecl :: TyClDecl GhcPs -> [LHsDecl GhcPs]
+hsDeclsClassDecl dec = case dec of
+  ClassDecl { tcdCExt = (_an2, sortKey),
+              tcdSigs = sigs,tcdMeths = methods,
+              tcdATs = ats, tcdATDefs = at_defs
+            } -> map snd decls
+    where
+      srs :: SrcAnn a -> RealSrcSpan
+      srs a = realSrcSpan $ locA a
+      decls
+          = orderedDecls sortKey $ Map.fromList
+              [(ClsSigTag,    map (\(L l s) -> (srs l, L l (SigD noExtField s))) sigs),
+               (ClsMethodTag, map (\(L l s) -> (srs l, L l (ValD noExtField s))) (bagToList methods)),
+               (ClsAtTag,     map (\(L l s) -> (srs l, L l (TyClD noExtField $ FamDecl noExtField s))) ats),
+               (ClsAtdTag,    map (\(L l s) -> (srs l, L l (InstD noExtField $ TyFamInstD noExtField s))) at_defs)
+              ]
+  _ -> error $ "hsDeclsClassDecl:dec=" ++ showAst dec
+
+replaceDeclsClassDecl :: TyClDecl GhcPs -> [LHsDecl GhcPs] -> TyClDecl GhcPs
+replaceDeclsClassDecl decl decls = case decl of
+  ClassDecl { tcdCExt = (an2, _) } -> decl'
+    where
+      (tags, methods', sigs', ats', at_defs', _, _docs) = partitionWithSortKey decls
+      decl' = decl { tcdCExt = (an2, AnnSortKey tags),
+                     tcdSigs = sigs',tcdMeths = methods',
+                     tcdATs = ats', tcdATDefs = at_defs'
+                   }
+
+  _ -> error $ "replaceDeclsClassDecl:decl=" ++ showAst decl
+
+partitionWithSortKey
+  :: [LHsDecl GhcPs]
+  -> ([DeclTag], LHsBinds GhcPs, [LSig GhcPs], [LFamilyDecl GhcPs],
+      [LTyFamInstDecl GhcPs], [LDataFamInstDecl GhcPs], [LDocDecl GhcPs])
+partitionWithSortKey = go
+  where
+    go [] = ([], emptyBag, [], [], [], [], [])
+    go ((L l decl) : ds) =
+      let (tags, bs, ss, ts, tfis, dfis, docs) = go ds in
+      case decl of
+        ValD _ b
+          -> (ClsMethodTag:tags, L l b `consBag` bs, ss, ts, tfis, dfis, docs)
+        SigD _ s
+          -> (ClsSigTag:tags, bs, L l s : ss, ts, tfis, dfis, docs)
+        TyClD _ (FamDecl _ t)
+          -> (ClsAtTag:tags, bs, ss, L l t : ts, tfis, dfis, docs)
+        InstD _ (TyFamInstD { tfid_inst = tfi })
+          -> (ClsAtdTag:tags, bs, ss, ts, L l tfi : tfis, dfis, docs)
+        InstD _ (DataFamInstD { dfid_inst = dfi })
+          -> (tags, bs, ss, ts, tfis, L l dfi : dfis, docs)
+        DocD _ d
+          -> (tags, bs, ss, ts, tfis, dfis, L l d : docs)
+        _ -> error $ "partitionBindsAndSigs" ++ (showAst decl)
+
+
+-- ---------------------------------------------------------------------
+
+orderedDeclsBinds
+  :: AnnSortKey BindTag
+  -> [LHsDecl GhcPs] -> [LHsDecl GhcPs]
+  -> [LHsDecl GhcPs]
+orderedDeclsBinds sortKey binds sigs =
+  case sortKey of
+    NoAnnSortKey ->
+      sortBy (\a b -> compare (realSrcSpan $ getLocA a)
+                              (realSrcSpan $ getLocA b)) (binds ++ sigs)
+    AnnSortKey keys ->
+      let
+        go [] _ _                      = []
+        go (BindTag:ks) (b:bs) ss = b : go ks bs ss
+        go (SigDTag:ks) bs (s:ss) = s : go ks bs ss
+        go (_:ks) bs ss           =     go ks bs ss
+      in
+        go keys binds sigs
+
+hsDeclsLocalBinds :: HsLocalBinds GhcPs -> [LHsDecl GhcPs]
+hsDeclsLocalBinds lb = case lb of
+    HsValBinds _ (ValBinds sortKey bs sigs) ->
+      let
+        bds = map wrapDecl (bagToList bs)
+        sds = map wrapSig sigs
+      in
+        orderedDeclsBinds sortKey bds sds
+    HsValBinds _ (XValBindsLR _) -> error $ "hsDecls.XValBindsLR not valid"
+    HsIPBinds {}       -> []
+    EmptyLocalBinds {} -> []
+
+hsDeclsValBinds :: (HsValBindsLR GhcPs GhcPs) -> [LHsDecl GhcPs]
+hsDeclsValBinds (ValBinds sortKey bs sigs) =
+      let
+        bds = map wrapDecl (bagToList bs)
+        sds = map wrapSig sigs
+      in
+        orderedDeclsBinds sortKey bds sds
+hsDeclsValBinds XValBindsLR{} = error "hsDeclsValBinds"
+
+-- ---------------------------------------------------------------------
+
+-- |Pure function to convert a 'LHsDecl' to a 'LHsBind'. This does
+-- nothing to any annotations that may be attached to either of the elements.
+-- It is used as a utility function in 'replaceDecls'
+decl2Bind :: LHsDecl GhcPs -> [LHsBind GhcPs]
+decl2Bind (L l (ValD _ s)) = [L l s]
+decl2Bind _                      = []
+
+-- |Pure function to convert a 'LSig' to a 'LHsBind'. This does
+-- nothing to any annotations that may be attached to either of the elements.
+-- It is used as a utility function in 'replaceDecls'
+decl2Sig :: LHsDecl GhcPs -> [LSig GhcPs]
+decl2Sig (L l (SigD _ s)) = [L l s]
+decl2Sig _                = []
+
+-- ---------------------------------------------------------------------
+
+-- |Convert a 'LSig' into a 'LHsDecl'
+wrapSig :: LSig GhcPs -> LHsDecl GhcPs
+wrapSig (L l s) = L l (SigD NoExtField s)
+
+-- ---------------------------------------------------------------------
+
+-- |Convert a 'LHsBind' into a 'LHsDecl'
+wrapDecl :: LHsBind GhcPs -> LHsDecl GhcPs
+wrapDecl (L l s) = L l (ValD NoExtField s)
+
+-- ---------------------------------------------------------------------
 
 showAst :: (Data a) => a -> String
 showAst ast
   = showSDocUnsafe
-    $ showAstData NoBlankSrcSpan NoBlankEpAnnotations ast
+    $ showAstData BlankSrcSpanFile NoBlankEpAnnotations ast
 
 -- ---------------------------------------------------------------------
 -- Putting these here for the time being, to avoid import loops