diff --git a/CHANGES.txt b/CHANGES.txt
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,10 @@
 Changelog for HLint (* = breaking change)
 
+2.2.6, released 2020-01-09
+    #813, remove any/all with const predicates
+    Allow haskell-src-exts-1.23
+    #814, suggest find instead of listToMaybe/filter
+    Allow ghc-lib-parser-8.8.*
 2.2.5, released 2019-12-06
     #803, allow newer ghc-lib-8.8.1
     #792, note that reverse/sort changes sort stability
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright Neil Mitchell 2006-2019.
+Copyright Neil Mitchell 2006-2020.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -88,6 +88,7 @@
 * [Restyled](https://restyled.io) includes an HLint Restyler to automatically run `hlint --refactor` on files changed in GitHub Pull Requests.
 * [lpaste](http://lpaste.net/) integrates with HLint - suggestions are shown at the bottom.
 * [hlint-test](https://hackage.haskell.org/package/hlint-test) helps you write a small test runner with HLint.
+* [hint-man](https://github.com/apps/hint-man) automatically submits reviews to opened pull requests in your repositories with inline hints.
 
 ### Automatically Applying Hints
 
@@ -215,6 +216,10 @@
 ```
 
 See discussion in [issue #372](https://github.com/ndmitchell/hlint/issues/372).
+
+### Why do I get a parse error?
+
+HLint enables/disables a set of extensions designed to allow as many files to parse as possible, but sometimes you'll need to enable an additional extension (e.g. Arrows), or disable some (e.g. MagicHash) to enable your code to parse. In addition, sometimes the underlying parser library ([haskell-src-exts](https://github.com/haskell-suite/haskell-src-exts)) has a bug which causes a parse error.
 
 ## Customizing the hints
 
diff --git a/data/Test.hs b/data/Test.hs
--- a/data/Test.hs
+++ b/data/Test.hs
@@ -46,7 +46,7 @@
 warn "noop" = a ? 0 ==> a
 
 {-
-<TEST>
+<--! TEST (temporarily disabled see issue https://github.com/ndmitchell/hlint/issues/809) !-->
 main = readFile "foo" >>= putStr            \
   -- bad
 
diff --git a/data/hlint.yaml b/data/hlint.yaml
--- a/data/hlint.yaml
+++ b/data/hlint.yaml
@@ -164,6 +164,8 @@
     - hint: {lhs: 0 >= length x, rhs: null x, note: IncreasesLaziness}
     - hint: {lhs: "x == []", rhs: null x}
     - hint: {lhs: "[] == x", rhs: null x}
+    - hint: {lhs: all (const False), rhs: "null"}
+    - hint: {lhs: any (const True) x, rhs: not (null x), name: Use null}
     - hint: {lhs: length x /= 0, rhs: not (null x), note: IncreasesLaziness, name: Use null}
     - hint: {lhs: 0 /= length x, rhs: not (null x), note: IncreasesLaziness, name: Use null}
     - hint: {lhs: "\\x -> [x]", rhs: "(:[])", name: "Use :"}
@@ -210,6 +212,7 @@
     - warn: {lhs: iterate id, rhs: repeat}
     - warn: {lhs: zipWith f (repeat x), rhs: map (f x)}
     - warn: {lhs: zipWith f y (repeat z), rhs: map (\x -> f x z) y}
+    - warn: {lhs: listToMaybe (filter p x), rhs: find p x}
 
     # MONOIDS
 
@@ -675,6 +678,8 @@
     - warn: {lhs: "concat []", rhs: "[]", name: Evaluate}
     - warn: {lhs: "zip [] []", rhs: "[]", name: Evaluate}
     - warn: {lhs: const x y, rhs: x, name: Evaluate}
+    - warn: {lhs: any (const False), rhs: const False, note: IncreasesLaziness, name: Evaluate}
+    - warn: {lhs: all (const True), rhs: const True, note: IncreasesLaziness, name: Evaluate}
 
     # FOLDABLE + TUPLES
 
diff --git a/hlint.cabal b/hlint.cabal
--- a/hlint.cabal
+++ b/hlint.cabal
@@ -1,13 +1,13 @@
 cabal-version:      >= 1.18
 build-type:         Simple
 name:               hlint
-version:            2.2.5
+version:            2.2.6
 license:            BSD3
 license-file:       LICENSE
 category:           Development
 author:             Neil Mitchell <ndmitchell@gmail.com>
 maintainer:         Neil Mitchell <ndmitchell@gmail.com>
-copyright:          Neil Mitchell 2006-2019
+copyright:          Neil Mitchell 2006-2020
 synopsis:           Source code suggestions
 description:
     HLint gives suggestions on how to improve your source code.
@@ -58,7 +58,7 @@
         cpphs >= 1.20.1,
         cmdargs >= 0.10,
         yaml >= 0.5.0,
-        haskell-src-exts >= 1.21 && < 1.23,
+        haskell-src-exts >= 1.21 && < 1.24,
         haskell-src-exts-util >= 0.2.5,
         uniplate >= 1.5,
         ansi-terminal >= 0.6.2,
@@ -74,7 +74,7 @@
           ghc-boot-th
     else
         build-depends:
-          ghc-lib-parser == 8.8.1.*
+          ghc-lib-parser == 8.8.*
 
     if flag(gpl)
         build-depends: hscolour >= 1.21
@@ -130,10 +130,8 @@
 
         HSE.All
         HSE.Match
-        HSE.Reduce
         HSE.Scope
         HSE.Type
-        HSE.Unify
         HSE.Util
         Hint.All
         Hint.Bracket
diff --git a/src/CmdLine.hs b/src/CmdLine.hs
--- a/src/CmdLine.hs
+++ b/src/CmdLine.hs
@@ -206,7 +206,7 @@
     ,CmdHSE
         {} &= explicit &= name "hse"
     ] &= program "hlint" &= verbosity
-    &=  summary ("HLint v" ++ showVersion version ++ ", (C) Neil Mitchell 2006-2019")
+    &=  summary ("HLint v" ++ showVersion version ++ ", (C) Neil Mitchell 2006-2020")
     where
         nam xs = nam_ xs &= name [head xs]
         nam_ xs = def &= explicit &= name xs
diff --git a/src/GHC/Util/HsDecl.hs b/src/GHC/Util/HsDecl.hs
--- a/src/GHC/Util/HsDecl.hs
+++ b/src/GHC/Util/HsDecl.hs
@@ -1,13 +1,19 @@
 {-# LANGUAGE NamedFieldPuns #-}
 
-module GHC.Util.HsDecl (declName,isForD') where
+module GHC.Util.HsDecl (declName,isForD',isNewType',isDerivD',isClsDefSig')
+where
 
 import HsSyn
 import OccName
 import SrcLoc
 
-isForD' :: LHsDecl GhcPs -> Bool
+isNewType' :: NewOrData -> Bool
+isNewType' NewType = True
+isNewType' DataType = False
+
+isForD', isDerivD' :: LHsDecl GhcPs -> Bool
 isForD' (LL _ ForD{}) = True; isForD' _ = False
+isDerivD' (LL _ DerivD{}) = True; isDerivD' _ = False
 
 -- | @declName x@ returns the \"new name\" that is created (for
 -- example a function declaration) by @x@.  If @x@ isn't a declaration
@@ -31,3 +37,6 @@
     ForD _ ForeignExport{fd_name} -> Just $ unLoc fd_name
     _ -> Nothing
 declName _ = Nothing {- COMPLETE LL-}
+
+isClsDefSig' :: Sig GhcPs -> Bool
+isClsDefSig' (ClassOpSig _ True _ _) = True; isClsDefSig' _ = False
diff --git a/src/GHC/Util/HsExpr.hs b/src/GHC/Util/HsExpr.hs
--- a/src/GHC/Util/HsExpr.hs
+++ b/src/GHC/Util/HsExpr.hs
@@ -18,6 +18,7 @@
   , replaceBranches'
   , needBracketOld', transformBracketOld', descendBracketOld', reduce', reduce1', fromParen1'
   , hasFieldsDotDot', isFieldPun'
+  , isParComp', isMDo', isRecStmt', isLCase', isTupleSection', isString', isPrimLiteral', isSpliceDecl', isFieldWildcard', isUnboxed'
 ) where
 
 import HsSyn
@@ -332,3 +333,48 @@
 fromParen1' :: LHsExpr GhcPs -> LHsExpr GhcPs
 fromParen1' (LL _ (HsPar _ x)) = x
 fromParen1' x = x
+
+--
+
+isMDo' :: HsStmtContext Name -> Bool
+isMDo' MDoExpr = True; isMDo' _ = False
+
+isRecStmt' :: StmtLR GhcPs GhcPs (LHsExpr GhcPs) -> Bool
+isRecStmt' RecStmt{} = True; isRecStmt' _ = False
+
+isParComp' :: StmtLR GhcPs GhcPs (LHsExpr GhcPs) -> Bool
+isParComp' ParStmt{} = True; isParComp' _ = False
+
+
+isLCase' :: LHsExpr GhcPs -> Bool
+isLCase' (LL _ HsLamCase{}) = True; isLCase' _ = False
+
+isTupleSection' :: HsTupArg GhcPs -> Bool
+isTupleSection' Missing{} = True; isTupleSection' _ = False
+
+isString' :: HsLit GhcPs -> Bool
+isString' HsString{} = True; isString' _ = False
+
+isPrimLiteral' :: HsLit GhcPs -> Bool
+isPrimLiteral' HsCharPrim{} = True;
+isPrimLiteral' HsStringPrim{} = True;
+isPrimLiteral' HsIntPrim{} = True;
+isPrimLiteral' HsWordPrim{} = True;
+isPrimLiteral' HsInt64Prim{} = True;
+isPrimLiteral' HsWord64Prim{} = True;
+isPrimLiteral' HsFloatPrim{} = True;
+isPrimLiteral' HsDoublePrim{} = True;
+isPrimLiteral' _ = False
+
+isSpliceDecl' :: HsExpr GhcPs -> Bool
+isSpliceDecl' HsSpliceE{} = True; isSpliceDecl' _ = False
+
+-- Field has a '_' as in '{foo=_} or is punned e.g. '{foo}'.
+isFieldWildcard' :: LHsRecField GhcPs (LHsExpr GhcPs) -> Bool
+isFieldWildcard' (LL _ HsRecField {hsRecFieldArg=(LL _ (EWildPat _))}) = True
+isFieldWildcard' (LL _ HsRecField {hsRecPun=True}) = True
+isFieldWildcard' (LL _ HsRecField {}) = False
+isFieldWildcard' _ = False -- {-# COMPLETE LL #-}
+
+isUnboxed' :: Boxity -> Bool
+isUnboxed' Unboxed = True; isUnboxed' _ = False
diff --git a/src/GHC/Util/HsType.hs b/src/GHC/Util/HsType.hs
--- a/src/GHC/Util/HsType.hs
+++ b/src/GHC/Util/HsType.hs
@@ -2,6 +2,8 @@
 module GHC.Util.HsType (
     Brackets'(..)
   , fromTyParen'
+  , isTyQuasiQuote'
+  , isUnboxedTuple'
   ) where
 
 import HsSyn
@@ -12,3 +14,10 @@
 fromTyParen' :: LHsType GhcPs -> LHsType GhcPs
 fromTyParen' (LL _ (HsParTy _ x)) = x
 fromTyParen' x = x
+
+isTyQuasiQuote' :: LHsType GhcPs -> Bool
+isTyQuasiQuote' (LL _ (HsSpliceTy _ HsQuasiQuote{})) = True; isTyQuasiQuote' _ = False
+
+isUnboxedTuple' :: HsTupleSort -> Bool
+isUnboxedTuple' HsUnboxedTuple = True
+isUnboxedTuple' _ = False
diff --git a/src/GHC/Util/Pat.hs b/src/GHC/Util/Pat.hs
--- a/src/GHC/Util/Pat.hs
+++ b/src/GHC/Util/Pat.hs
@@ -4,6 +4,7 @@
     strToPat', patToStr'
   , Brackets'(..)
   , fromPChar', isPFieldWildcard', hasPFieldsDotDot', isPWildCard'
+  , isPFieldPun', isPatTypeSig', isPBangPat', isPViewPat'
   ) where
 
 import HsSyn
@@ -46,3 +47,12 @@
 isPWildCard' :: Pat GhcPs -> Bool
 isPWildCard' (LL _ (WildPat _)) = True
 isPWildCard' _ = False
+
+isPFieldPun' :: LHsRecField GhcPs (Pat GhcPs) -> Bool
+isPFieldPun' (LL _ HsRecField {hsRecPun=True}) = True
+isPFieldPun' _ = False
+
+isPatTypeSig', isPBangPat', isPViewPat' :: Pat GhcPs -> Bool
+isPatTypeSig' (LL _ SigPat{}) = True; isPatTypeSig' _ = False
+isPBangPat' (LL _ BangPat{}) = True; isPBangPat' _ = False
+isPViewPat' (LL _ ViewPat{}) = True; isPViewPat' _ = False
diff --git a/src/HSE/All.hs b/src/HSE/All.hs
--- a/src/HSE/All.hs
+++ b/src/HSE/All.hs
@@ -16,7 +16,6 @@
 import Language.Haskell.Exts.Util hiding (freeVars, Vars(..))
 import qualified Language.Haskell.Exts.Util as X
 import HSE.Util as X
-import HSE.Reduce as X
 import HSE.Type as X
 import HSE.Match as X
 import HSE.Scope as X
diff --git a/src/HSE/Reduce.hs b/src/HSE/Reduce.hs
deleted file mode 100644
--- a/src/HSE/Reduce.hs
+++ /dev/null
@@ -1,28 +0,0 @@
-{-# LANGUAGE ViewPatterns #-}
-
--- Evaluate/reduce a HSE Exp as much as possible
-module HSE.Reduce(reduce) where
-
-import HSE.Match
-import HSE.Util
-import HSE.Type
-import Language.Haskell.Exts.Util
-
-
-reduce :: Exp_ -> Exp_
-reduce = fromParen . transform reduce1
-
-
-reduce1 :: Exp_ -> Exp_
-reduce1 (App s len (Lit _ (String _ xs _))) | len ~= "length" = Lit s $ Int s n (show n)
-    where n = fromIntegral $ length xs
-reduce1 (App s len (List _ xs)) | len ~= "length" = Lit s $ Int s n (show n)
-    where n = fromIntegral $ length xs
-reduce1 (view -> App2 op (Lit _ x) (Lit _ y)) | op ~= "==" = toNamed $ show $ x =~= y
-reduce1 (view -> App2 op (Lit _ (Int _ x _)) (Lit _ (Int _ y _)))
-    | op ~= ">=" = toNamed $ show $ x >= y
-reduce1 (view -> App2 op x y)
-    | op ~= "&&" && x ~= "True"  = y
-    | op ~= "&&" && x ~= "False" = x
-reduce1 (Paren _ x) | isAtom x = x
-reduce1 x = x
diff --git a/src/HSE/Scope.hs b/src/HSE/Scope.hs
--- a/src/HSE/Scope.hs
+++ b/src/HSE/Scope.hs
@@ -1,8 +1,7 @@
-{-# LANGUAGE ViewPatterns, GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
 
 module HSE.Scope(
-    Scope, scopeCreate, scopeImports,
-    scopeMatch, scopeMove
+    Scope, scopeCreate, scopeImports
     ) where
 
 import Data.Semigroup
@@ -47,58 +46,3 @@
 
 scopeImports :: Scope -> [ImportDecl S]
 scopeImports (Scope x) = x
-
-
-
--- | Given a two names in scopes, could they possibly refer to the same thing.
---   This property is reflexive.
-scopeMatch :: (Scope, QName S) -> (Scope, QName S) -> Bool
-scopeMatch (a, x@Special{}) (b, y@Special{}) = x =~= y
-scopeMatch (a, x) (b, y) | isSpecial x || isSpecial y = False
-scopeMatch (a, x) (b, y) = unqual x =~= unqual y && not (null $ possModules a x `intersect` possModules b y)
-
-
--- | Given a name in a scope, and a new scope, create a name for the new scope that will refer
---   to the same thing. If the resulting name is ambiguous, it picks a plausible candidate.
-scopeMove :: (Scope, QName S) -> Scope -> QName S
-scopeMove (a, x@(fromQual -> Just name)) (Scope b)
-    | null imps = head $ real ++ [x]
-    | any (not . importQualified) imps = unqual x
-    | otherwise = Qual an (head $ mapMaybe importAs imps ++ map importModule imps) name
-    where
-        real = [Qual an (ModuleName an m) name | m <- possModules a x]
-        imps = [i | r <- real, i <- b, possImport i r]
-scopeMove (_, x) _ = x
-
-
--- which modules could a name possibly lie in
--- if it's qualified but not matching any import, assume the user
--- just lacks an import
-possModules :: Scope -> QName S -> [String]
-possModules (Scope is) x = f x
-    where
-        res = [fromModuleName $ importModule i | i <- is, possImport i x]
-
-        f Special{} = [""]
-        f x@(Qual _ mod _) = [fromModuleName mod | null res] ++ res
-        f _ = res
-
-
-possImport :: ImportDecl S -> QName S -> Bool
-possImport i Special{} = False
-possImport i (Qual _ mod x) = fromModuleName mod `elem` map fromModuleName ms && possImport i{importQualified=False} (UnQual an x)
-    where ms = importModule i : maybeToList (importAs i)
-possImport i (UnQual _ x) = not (importQualified i) && maybe True f (importSpecs i)
-    where
-        f (ImportSpecList _ hide xs) = if hide then Just True `notElem` ms else Nothing `elem` ms || Just True `elem` ms
-            where ms = map g xs
-
-        g :: ImportSpec S -> Maybe Bool -- does this import cover the name x
-        g (IVar _ y) = Just $ x =~= y
-        g (IAbs _ _ y) = Just $ x =~= y
-        g (IThingAll _ y) = if x =~= y then Just True else Nothing
-        g (IThingWith _ y ys) = Just $ x `elem_` (y : map fromCName ys)
-
-        fromCName :: CName S -> Name S
-        fromCName (VarName _ x) = x
-        fromCName (ConName _ x) = x
diff --git a/src/HSE/Type.hs b/src/HSE/Type.hs
--- a/src/HSE/Type.hs
+++ b/src/HSE/Type.hs
@@ -1,7 +1,7 @@
 
 module HSE.Type(
     S,
-    Module_, Decl_, Exp_, Pat_, Type_,
+    Module_, Decl_, Exp_, Pat_,
     module HSE,
     module Uniplate
     ) where
@@ -16,4 +16,3 @@
 type Decl_ = Decl S
 type Exp_ = Exp S
 type Pat_ = Pat S
-type Type_ = Type S
diff --git a/src/HSE/Unify.hs b/src/HSE/Unify.hs
deleted file mode 100644
--- a/src/HSE/Unify.hs
+++ /dev/null
@@ -1,157 +0,0 @@
-{-# LANGUAGE PatternGuards, ViewPatterns, FlexibleContexts, ScopedTypeVariables #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-
-module HSE.Unify(
-    Subst, fromSubst,
-    validSubst, substitute,
-    unifyExp,
-    ) where
-
-import Control.Applicative
-import Data.List.Extra
-import Data.Maybe
-import Data.Data
-import Data.Semigroup
-import Config.Type
-import Hint.Type
-import Control.Monad
-import Data.Tuple.Extra
-import Util
-import Prelude
-
----------------------------------------------------------------------
--- SUBSTITUTION DATA TYPE
-
--- | A list of substitutions. A key may be duplicated, you need to call 'check'
---   to ensure the substitution is valid.
-newtype Subst a = Subst [(String, a)]
-    deriving (Semigroup, Monoid)
-
--- | Unpack the substitution
-fromSubst :: Subst a -> [(String, a)]
-fromSubst (Subst xs) = xs
-
-instance Functor Subst where
-    fmap f (Subst xs) = Subst $ map (second f) xs
-
-instance Pretty a => Show (Subst a) where
-    show (Subst xs) = unlines [a ++ " = " ++ prettyPrint b | (a,b) <- xs]
-
-
--- check the unification is valid and simplify it
-validSubst :: (a -> a -> Bool) -> Subst a -> Maybe (Subst a)
-validSubst eq = fmap Subst . mapM f . groupSort . fromSubst
-    where f (x,y:ys) | all (eq y) ys = Just (x,y)
-          f _ = Nothing
-
-
--- | Perform a substitution
-substitute :: Subst Exp_ -> Exp_ -> Exp_
-substitute (Subst bind) = transformBracketOld exp . transformBi pat . transformBi typ
-    where
-        exp (Var _ (fromNamed -> x)) = lookup x bind
-        exp (InfixApp s lhs (fromNamed -> x) rhs) =
-            (\op -> InfixApp s lhs op rhs) <$> lookupOp x
-        exp (LeftSection s exp (fromNamed -> x)) =
-            LeftSection s exp <$> lookupOp x
-        exp (RightSection s (fromNamed -> x) exp) =
-            (\op -> RightSection s op exp) <$> lookupOp x
-        exp _ = Nothing
-
-        -- Substition for operator must be an operator name
-        lookupOp x = toNamed . fromNamed <$> lookup x bind
-
-        pat (PVar _ (fromNamed -> x)) | Just y <- lookup x bind = toNamed $ fromNamed y
-        pat x = x :: Pat_
-
-        typ (TyVar _ (fromNamed -> x)) | Just (TypeApp _ y) <- lookup x bind = y
-        typ x = x :: Type_
-
----------------------------------------------------------------------
--- UNIFICATION
-
-type NameMatch = QName S -> QName S -> Bool
-
-nmOp :: NameMatch -> QOp S -> QOp S -> Bool
-nmOp nm (QVarOp _ x) (QVarOp _ y) = nm x y
-nmOp nm (QConOp _ x) (QConOp _ y) = nm x y
-nmOp nm  _ _ = False
-
-
--- | Unification, obeys the property that if @unify a b = s@, then @substitute s a = b@.
-unify :: Data a => NameMatch -> Bool -> a -> a -> Maybe (Subst Exp_)
-unify nm root x y
-    | Just (x,y) <- cast (x,y) = unifyExp nm root x y
-    | Just (x,y) <- cast (x,y) = unifyPat nm x y
-    | Just (x,y) <- cast (x,y) = unifyType nm x y
-    | Just (x :: S) <- cast x = Just mempty
-    | otherwise = unifyDef nm x y
-
-
-unifyDef :: Data a => NameMatch -> a -> a -> Maybe (Subst Exp_)
-unifyDef nm x y = fmap mconcat . sequence =<< gzip (unify nm False) x y
-
-
--- App/InfixApp are analysed specially for performance reasons
--- root = True, this is the outside of the expr
--- do not expand out a dot at the root, since otherwise you get two matches because of readRule (Bug #570)
-unifyExp :: NameMatch -> Bool -> Exp_ -> Exp_ -> Maybe (Subst Exp_)
-
--- brackets are not added when expanding $ in the users code, so tolerate them
--- in the match even if they aren't in the users code
-unifyExp nm root x y | not root, isParen x, not $ isParen y = unifyExp nm root (fromParen x) y
-
--- don't subsitute for type apps, since no one writes rules imaginging they exist
-unifyExp nm root (Var _ (fromNamed -> v)) y | isUnifyVar v, not $ isTypeApp y = Just $ Subst [(v,y)]
-unifyExp nm root (Var _ x) (Var _ y) | nm x y = Just mempty
-
--- Match wildcard operators
-unifyExp nm root (InfixApp _ lhs1 (fromNamed -> v) rhs1) (InfixApp _ lhs2 (fromNamed -> op2) rhs2)
-    | isUnifyVar v =
-        (Subst [(v, toNamed op2)] <>) <$>
-        liftM2 (<>) (unifyExp nm False lhs1 lhs2) (unifyExp nm False rhs1 rhs2)
-unifyExp nm root (LeftSection _ exp1 (fromNamed -> v)) (LeftSection _ exp2 (fromNamed -> op2))
-    | isUnifyVar v =
-        (Subst [(v, toNamed op2)] <>) <$> unifyExp nm False exp1 exp2
-unifyExp nm root (RightSection _ (fromNamed -> v) exp1) (RightSection _ (fromNamed -> op2) exp2)
-    | isUnifyVar v =
-        (Subst [(v, toNamed op2)] <>) <$> unifyExp nm False exp1 exp2
-
--- Options: match directly, and expand through .
-unifyExp nm root x@(App _ x1 x2) (App _ y1 y2) =
-    liftM2 (<>) (unifyExp nm False x1 y1) (unifyExp nm False x2 y2) `mplus`
-    (do guard $ not root
-            -- don't expand . if at the root, otherwise you can get duplicate matches
-            -- because the matching engine auto-generates hints in dot-form
-        InfixApp _ y11 dot y12 <- return $ fromParen y1
-        guard $ isDot dot
-        unifyExp nm root x (App an y11 (App an y12 y2))
-    )
-
--- Options: match directly, then expand through $, then desugar infix
-unifyExp nm root x (InfixApp _ lhs2 op2 rhs2)
-    | InfixApp _ lhs1 op1 rhs1 <- x = guard (nmOp nm op1 op2) >> liftM2 (<>) (unifyExp nm False lhs1 lhs2) (unifyExp nm False rhs1 rhs2)
-    | isDol op2 = unifyExp nm root x $ App an lhs2 rhs2
-    | otherwise = unifyExp nm root x $ App an (App an (opExp op2) lhs2) rhs2
-
-unifyExp nm root x y | isOther x, isOther y = unifyDef nm x y
-    where
-        -- types that are not already handled in unify
-        {-# INLINE isOther #-}
-        isOther Var{} = False
-        isOther App{} = False
-        isOther InfixApp{} = False
-        isOther _ = True
-
-unifyExp nm root _ _ = Nothing
-
-
-unifyPat :: NameMatch -> Pat_ -> Pat_ -> Maybe (Subst Exp_)
-unifyPat nm (PVar _ x) (PVar _ y) = Just $ Subst [(fromNamed x, toNamed $ fromNamed y)]
-unifyPat nm (PVar _ x) PWildCard{} = Just $ Subst [(fromNamed x, toNamed $ "_" ++ fromNamed x)]
-unifyPat nm x y = unifyDef nm x y
-
-
-unifyType :: NameMatch -> Type_ -> Type_ -> Maybe (Subst Exp_)
-unifyType nm (TyVar a x) y = Just $ Subst [(fromNamed x, TypeApp a y)]
-unifyType nm x y = unifyDef nm x y
diff --git a/src/Hint/All.hs b/src/Hint/All.hs
--- a/src/Hint/All.hs
+++ b/src/Hint/All.hs
@@ -45,7 +45,6 @@
 builtin :: HintBuiltin -> Hint
 builtin x = case x of
     -- Hse.
-    HintExtensions -> modu extensionsHint
     HintLambda     -> decl lambdaHint
 
     -- Ghc.
@@ -64,6 +63,7 @@
     HintSmell      -> mempty{hintDecl'=smellHint,hintModule=smellModuleHint}
     HintPattern    -> decl' patternHint
     HintMonad      -> decl' monadHint
+    HintExtensions -> modu extensionsHint
     where
         wrap = timed "Hint" (drop 4 $ show x) . forceList
         decl f = mempty{hintDecl=const $ \a b c -> wrap $ f a b c}
@@ -78,12 +78,7 @@
 -- | Transform a list of 'HintBuiltin' or 'HintRule' into a 'Hint'.
 resolveHints :: [Either HintBuiltin HintRule] -> Hint
 resolveHints xs =
-  if False then
-      -- GHC
-    mconcat $ mempty{hintDecl'=const $ readMatch' rights} : map builtin (nubOrd lefts)
-  else
-      -- HSE
-    mconcat $ mempty{ hintDecl=const $  readMatch rights} : map builtin (nubOrd lefts)
+  mconcat $ mempty{hintDecl'=const $ readMatch' rights} : map builtin (nubOrd lefts)
   where (lefts,rights) = partitionEithers xs
 
 -- | Transform a list of 'HintRule' into a 'Hint'.
diff --git a/src/Hint/Bracket.hs b/src/Hint/Bracket.hs
--- a/src/Hint/Bracket.hs
+++ b/src/Hint/Bracket.hs
@@ -125,10 +125,11 @@
 
 -- Dirty, should add to Brackets type class I think
 tyConToRtype :: String -> RType
-tyConToRtype "Exp"  = Expr
-tyConToRtype "Type" = Type
-tyConToRtype "Pat"  = Pattern
-tyConToRtype _      = Expr
+tyConToRtype "Exp"    = Expr
+tyConToRtype "Type"   = Type
+tyConToRtype "HsType" = Type
+tyConToRtype "Pat"    = Pattern
+tyConToRtype _        = Expr
 
 findType :: (Data a) => a -> RType
 findType = tyConToRtype . dataTypeName . dataTypeOf
diff --git a/src/Hint/Extensions.hs b/src/Hint/Extensions.hs
--- a/src/Hint/Extensions.hs
+++ b/src/Hint/Extensions.hs
@@ -70,6 +70,8 @@
 f :: Int -> (# Int, Int #)
 {-# LANGUAGE UnboxedTuples #-} \
 f :: x -> (x, x); f x = (x, x) --
+{-# LANGUAGE UnboxedTuples #-} \
+f x = case x of (# a, b #) -> a
 {-# LANGUAGE DefaultSignatures #-} \
 class Val a where; val :: a --
 {-# LANGUAGE DefaultSignatures #-} \
@@ -133,72 +135,87 @@
 
 module Hint.Extensions(extensionsHint) where
 
-import Hint.Type
+import Hint.Type(ModuHint, rawIdea',Severity(Warning),Note(..),toSS',ghcAnnotations,ghcModule,extensionImpliedBy,extensionImplies)
+import Language.Haskell.Exts.Extension
+
+import Data.Generics.Uniplate.Operations
 import Control.Monad.Extra
-import Data.Maybe
 import Data.List.Extra
 import Data.Ratio
 import Data.Data
 import Refact.Types
-import Data.Semigroup
 import qualified Data.Set as Set
 import qualified Data.Map as Map
-import Prelude
 
+import SrcLoc
+import HsSyn
+import BasicTypes
+import Class
+import RdrName
+import OccName
+import ForeignCall
+import GHC.Util
 
 extensionsHint :: ModuHint
 extensionsHint _ x =
-    [ rawIdea Warning "Unused LANGUAGE pragma"
-        (srcInfoSpan sl)
-        (prettyPrint o)
+    [ rawIdea' Hint.Type.Warning "Unused LANGUAGE pragma"
+        sl
+        (comment (mkLangExts sl exts))
         (Just newPragma)
         ( [RequiresExtension $ prettyExtension gone | x <- before \\ after, gone <- Map.findWithDefault [] x disappear] ++
             [ Note $ "Extension " ++ prettyExtension x ++ " is " ++ reason x
             | x <- explainedRemovals])
-        [ModifyComment (toSS o) newPragma]
-    | o@(LanguagePragma sl exts) <- modulePragmas (hseModule x)
-    , let before = map (parseExtension . prettyPrint) exts
+        [ModifyComment (toSS' (mkLangExts sl exts)) newPragma]
+    | (LL sl _,  exts) <- langExts $ pragmas (ghcAnnotations x)
+    , let before = map parseExtension exts
     , let after = filter (`Set.member` keep) before
     , before /= after
     , let explainedRemovals
             | null after && not (any (`Map.member` implied) before) = []
             | otherwise = before \\ after
-    , let newPragma = if null after then "" else prettyPrint $ LanguagePragma sl $ map (toNamed . prettyExtension) after
+    , let newPragma =
+            if null after then "" else comment (mkLangExts sl $ map prettyExtension after)
     ]
-    where
-        usedTH = used TemplateHaskell (hseModule x) || used QuasiQuotes (hseModule x)
-            -- if TH or QuasiQuotes is on, can use all other extensions programmatically
-
-        -- all the extensions defined to be used
-        extensions = Set.fromList [parseExtension $ fromNamed e | LanguagePragma _ exts <- modulePragmas (hseModule x), e <- exts]
-
-        -- those extensions we detect to be useful
-        useful = if usedTH then extensions  else Set.filter (`usedExt` hseModule x) extensions
-
-        -- those extensions which are useful, but implied by other useful extensions
-        implied = Map.fromList
-            [ (e, a)
-            | e <- Set.toList useful
-            , a:_ <- [filter (`Set.member` useful) $ extensionImpliedBy e]]
-
-        -- those we should keep
-        keep =  useful `Set.difference` Map.keysSet implied
-
-        -- (a,b) means a used to imply b, but has gone, so suggest enabling b
-        disappear =
-            Map.fromListWith (++) $
-            nubOrdOn snd -- only keep one instance for each of a
-            [ (e, [a])
-            | e <- Set.toList $ extensions `Set.difference` keep
-            , a <- extensionImplies e
-            , a `Set.notMember` useful
-            , usedTH || usedExt a (hseModule x)
-            ]
+  where
+    usedTH :: Bool
+    usedTH = used TemplateHaskell (ghcModule x) || used QuasiQuotes (ghcModule x)
+      -- If TH or QuasiQuotes is on, can use all other extensions
+      -- programmatically.
 
-        reason x =
-            case Map.lookup x implied of
-            Just a -> "implied by " ++ prettyExtension a
-            Nothing -> "not used"
+    -- All the extensions defined to be used.
+    extensions :: Set.Set Extension
+    extensions = Set.fromList [ parseExtension e
+                              | let exts = concatMap snd $ langExts (pragmas (ghcAnnotations x))
+                              , e <- exts ]
+    -- Those extensions we detect to be useful.
+    useful :: Set.Set Extension
+    useful = if usedTH then extensions else Set.filter (`usedExt` ghcModule x) extensions
+    -- Those extensions which are useful, but implied by other useful
+    -- extensions.
+    implied :: Map.Map Extension Extension
+    implied = Map.fromList
+        [ (e, a)
+        | e <- Set.toList useful
+        , a:_ <- [filter (`Set.member` useful) $ extensionImpliedBy e]]
+    -- Those we should keep.
+    keep :: Set.Set Extension
+    keep =  useful `Set.difference` Map.keysSet implied
+    -- The meaning of (a,b) is a used to imply b, but has gone, so
+    -- suggest enabling b.
+    disappear =
+        Map.fromListWith (++) $
+        nubOrdOn snd -- Only keep one instance for each of a.
+        [ (e, [a])
+        | e <- Set.toList $ extensions `Set.difference` keep
+        , a <- extensionImplies e
+        , a `Set.notMember` useful
+        , usedTH || usedExt a (ghcModule x)
+        ]
+    reason :: Extension -> String
+    reason x =
+      case Map.lookup x implied of
+        Just a -> "implied by " ++ prettyExtension a
+        Nothing -> "not used"
 
 deriveHaskell = ["Eq","Ord","Enum","Ix","Bounded","Read","Show"]
 deriveGenerics = ["Data","Typeable","Generic","Generic1","Lift"]
@@ -210,150 +227,159 @@
     deriveGenerics -- Generics stuff can't newtype derive since it has the ctor in it
 
 -- | Classes that can appear as stock, and can't appear as anyclass
+deriveStock :: [String]
 deriveStock = deriveHaskell ++ deriveGenerics ++ deriveCategory
 
-
-usedExt :: Extension -> Module_ -> Bool
+usedExt :: Extension -> Located (HsModule GhcPs) -> Bool
 usedExt (EnableExtension x) = used x
 usedExt (UnknownExtension "NumDecimals") = hasS isWholeFrac
 usedExt (UnknownExtension "DeriveLift") = hasDerive ["Lift"]
 usedExt (UnknownExtension "DeriveAnyClass") = not . null . derivesAnyclass . derives
 usedExt _ = const True
 
-
-used :: KnownExtension -> Module_ -> Bool
-used RecursiveDo = hasS isMDo ||^ hasS isRecStmt
-used ParallelListComp = hasS isParComp
-used FunctionalDependencies = hasT (un :: FunDep S)
-used ImplicitParams = hasT (un :: IPName S)
-used TypeApplications = hasS isTypeApp
+used :: KnownExtension -> Located (HsModule GhcPs) -> Bool
+used RecursiveDo = hasS isMDo' ||^ hasS isRecStmt'
+used ParallelListComp = hasS isParComp'
+used FunctionalDependencies = hasT (un :: FunDep (Located RdrName))
+used ImplicitParams = hasT (un :: HsIPName)
+used TypeApplications = hasS isTypeApp'
 used EmptyDataDecls = hasS f
-    where f (DataDecl _ _ _ _ [] _) = True
-          f (GDataDecl _ _ _ _ _ [] _) = True
-          f _ = False
+  where
+    f :: HsDataDefn GhcPs -> Bool
+    f (HsDataDefn _ _ _ _ _ [] _) = True
+    f _ = False
 used EmptyCase = hasS f
-    where f (Case _ _ []) = True
-          f (LCase _ []) = True
-          f (_ :: Exp_) = False
-used KindSignatures = hasT (un :: Kind S)
-used BangPatterns = hasS isPBangPat
-used TemplateHaskell = hasT2 (un :: (Bracket S, Splice S)) ||^ hasS f ||^ hasS isSpliceDecl
-    where f VarQuote{} = True
-          f TypQuote{} = True
-          f _ = False
-used ForeignFunctionInterface = hasT (un :: CallConv S)
+  where
+    f :: HsExpr GhcPs -> Bool
+    f (HsCase _ _ (MG _ (LL _ []) _)) = True
+    f (HsLamCase _ (MG _ (LL _ []) _)) = True
+    f _ = False
+used KindSignatures = hasT (un :: HsKind GhcPs)
+used BangPatterns = hasS isPBangPat'
+used TemplateHaskell = hasT2' (un :: (HsBracket GhcPs, HsSplice GhcPs)) ||^ hasS f ||^ hasS isSpliceDecl'
+    where
+      f :: HsBracket GhcPs -> Bool
+      f VarBr{} = True
+      f TypBr{} = True
+      f _ = False
+used ForeignFunctionInterface = hasT (un :: CCallConv)
 used PatternGuards = hasS f
-    where f (GuardedRhs _ xs _) = g xs
-          g [] = False
-          g [Qualifier{}] = False
-          g _ = True
-used StandaloneDeriving = hasS isDerivDecl
-used PatternSignatures = hasS isPatTypeSig
-used RecordWildCards = hasS isPFieldWildcard ||^ hasS isFieldWildcard
-used RecordPuns = hasS isPFieldPun ||^ hasS isFieldPun
-used NamedFieldPuns = hasS isPFieldPun ||^ hasS isFieldPun
-used UnboxedTuples = has (not . isBoxed)
-used QuasiQuotes = hasS isQuasiQuote ||^ hasS isTyQuasiQuote
-used ViewPatterns = hasS isPViewPat
-used DefaultSignatures = hasS isClsDefSig
+  where
+    f :: GRHS GhcPs (LHsExpr GhcPs) -> Bool
+    f (GRHS _ xs _) = g xs
+    f _ = False -- new ctor
+    g :: [GuardLStmt GhcPs] -> Bool
+    g [] = False
+    g [LL _ BodyStmt{}] = False
+    g _ = True
+used StandaloneDeriving = hasS isDerivD'
+used PatternSignatures = hasS isPatTypeSig'
+used RecordWildCards = hasS hasFieldsDotDot' ||^ hasS hasPFieldsDotDot'
+used RecordPuns = hasS isPFieldPun' ||^ hasS isFieldPun'
+used NamedFieldPuns = hasS isPFieldPun' ||^ hasS isFieldPun'
+used UnboxedTuples = has isUnboxedTuple' ||^ has (== Unboxed)
+used QuasiQuotes = hasS isQuasiQuote' ||^ hasS isTyQuasiQuote'
+used ViewPatterns = hasS isPViewPat'
+used DefaultSignatures = hasS isClsDefSig'
 used DeriveDataTypeable = hasDerive ["Data","Typeable"]
 used DeriveFunctor = hasDerive ["Functor"]
 used DeriveFoldable = hasDerive ["Foldable"]
 used DeriveTraversable = hasDerive ["Traversable","Foldable","Functor"]
 used DeriveGeneric = hasDerive ["Generic","Generic1"]
-used GeneralizedNewtypeDeriving = not . null . derivesNewtype . derives
-used LambdaCase = hasS isLCase
-used TupleSections = hasS isTupleSection
-used OverloadedStrings = hasS isString
+used GeneralizedNewtypeDeriving = not . null . derivesNewtype' . derives
+used LambdaCase = hasS isLCase'
+used TupleSections = hasS isTupleSection'
+used OverloadedStrings = hasS isString'
 used Arrows = hasS f
-    where f Proc{} = True
-          f LeftArrApp{} = True
-          f RightArrApp{} = True
-          f LeftArrHighApp{} = True
-          f RightArrHighApp{} = True
-          f _ = False
+  where
+    f :: HsExpr GhcPs -> Bool
+    f HsProc{} = True
+    f HsArrApp{} = True
+    f _ = False
 used TransformListComp = hasS f
-    where f QualStmt{} = False
-          f _ = True
-used MagicHash = hasS f ||^ hasS isPrimLiteral
-    where f (Ident _ s) = "#" `isSuffixOf` s
-          f _ = False
-
--- for forwards compatibility, if things ever get added to the extension enumeration
+    where
+      f :: StmtLR GhcPs GhcPs (LHsExpr GhcPs) -> Bool
+      f TransStmt{} = True
+      f _ = False
+used MagicHash = hasS f ||^ hasS isPrimLiteral'
+    where
+      f :: RdrName -> Bool
+      f s = "#" `isSuffixOf` (occNameString . rdrNameOcc) s
+-- For forwards compatibility, if things ever get added to the
+-- extension enumeration.
 used x = usedExt $ UnknownExtension $ show x
 
-
-hasDerive :: [String] -> Module_ -> Bool
-hasDerive want = any (`elem` want) . derivesStock . derives
-
+hasDerive :: [String] -> Located (HsModule GhcPs) -> Bool
+hasDerive want = any (`elem` want) . derivesStock' . derives
 
 -- Derivations can be implemented using any one of 3 strategies, so for each derivation
 -- add it to all the strategies that might plausibly implement it
 data Derives = Derives
-    {derivesStock :: [String]
+    {derivesStock' :: [String]
     ,derivesAnyclass :: [String]
-    ,derivesNewtype :: [String]
+    ,derivesNewtype' :: [String]
     }
 instance Semigroup Derives where
     Derives x1 x2 x3 <> Derives y1 y2 y3 =
-        Derives (x1++y1) (x2++y2) (x3++y3)
+        Derives (x1 ++ y1) (x2 ++ y2) (x3 ++ y3)
 instance Monoid Derives where
     mempty = Derives [] [] []
     mappend = (<>)
 
-addDerives :: Maybe (DataOrNew S) -> Maybe (DerivStrategy S) -> [String] -> Derives
+addDerives :: Maybe NewOrData -> Maybe (DerivStrategy GhcPs) -> [String] -> Derives
 addDerives _ (Just s) xs = case s of
-    DerivStock{} -> mempty{derivesStock = xs}
-    DerivAnyclass{} -> mempty{derivesAnyclass = xs}
-    DerivNewtype{} -> mempty{derivesNewtype = xs}
-    DerivVia{} -> mempty
+    StockStrategy -> mempty{derivesStock' = xs}
+    AnyclassStrategy -> mempty{derivesAnyclass = xs}
+    NewtypeStrategy -> mempty{derivesNewtype' = xs}
+    ViaStrategy{} -> mempty
 addDerives nt _ xs = mempty
-    {derivesStock = stock
+    {derivesStock' = stock
     ,derivesAnyclass = other
-    ,derivesNewtype = if maybe True isNewType nt then filter (`notElem` noDeriveNewtype) xs else []}
+    ,derivesNewtype' = if maybe True isNewType' nt then filter (`notElem` noDeriveNewtype) xs else []}
     where (stock, other) = partition (`elem` deriveStock) xs
 
-
--- | What is derived on newtype, and on data type
---   'deriving' declarations may be on either, so we approximate as both newtype and data
-derives :: Module_ -> Derives
-derives m = mconcat $ map decl (childrenBi m) ++ map idecl (childrenBi m)
-    where
-        idecl :: InstDecl S -> Derives
-        idecl (InsData _ dn _ _ ds) = g dn ds
-        idecl (InsGData _ dn _ _ _ ds) = g dn ds
-        idecl _ = mempty
+derives :: Located (HsModule GhcPs) -> Derives
+derives (LL _ m) =  mconcat $ map decl (childrenBi m) ++ map idecl (childrenBi m)
+  where
+    idecl :: Located (DataFamInstDecl GhcPs) -> Derives
+    idecl (LL _ (DataFamInstDecl (HsIB _ FamEqn {feqn_rhs=HsDataDefn {dd_ND=dn, dd_derivs=(LL _ ds)}}))) = g dn ds
+    idecl _ = mempty
 
-        decl :: Decl_ -> Derives
-        decl (DataDecl _ dn _ _ _ ds) = g dn ds
-        decl (GDataDecl _ dn _ _ _ _ ds) = g dn ds
-        decl (DataInsDecl _ dn _ _ ds) = g dn ds
-        decl (GDataInsDecl _ dn _ _ _ ds) = g dn ds
-        decl (DerivDecl _ strategy _ hd) = addDerives Nothing strategy [ir hd]
-        decl _ = mempty
+    decl :: LHsDecl GhcPs -> Derives
+    decl (LL _ (TyClD _ (DataDecl _ _ _ _ HsDataDefn {dd_ND=dn, dd_derivs=(LL _ ds)}))) = g dn ds -- Data declaration.
+    decl (LL _ (DerivD _ (DerivDecl _ (HsWC _ sig) strategy _))) = addDerives Nothing (fmap unLoc strategy) [derivedToStr sig] -- A deriving declaration.
+    decl _ = mempty
 
-        g dn ds = mconcat [addDerives (Just dn) strategy $ map ir rules | Deriving _ strategy rules <- ds]
+    g :: NewOrData -> [LHsDerivingClause GhcPs] -> Derives
+    g dn ds = mconcat [addDerives (Just dn) (fmap unLoc strategy) $ map derivedToStr tys | LL _ (HsDerivingClause _ strategy (LL _ tys)) <- ds]
 
-        ir (IRule _ _ _ x) = ih x
-        ir (IParen _ x) = ir x
+    derivedToStr :: LHsSigType GhcPs -> String
+    derivedToStr (HsIB _ t) = ih t
+      where
+        ih :: LHsType GhcPs -> String
+        ih (LL _ (HsQualTy _ _ a)) = ih a
+        ih (LL _ (HsParTy _ a)) = ih a
+        ih (LL _ (HsAppTy _ a _)) = ih a
+        ih (LL _ (HsTyVar _ _ a)) = unsafePrettyPrint $ unqual' a
+        ih (LL _ a) = unsafePrettyPrint a -- I don't anticipate this case is called.
+        ih _ = "" -- {-# COMPLETE LL #-}
+    derivedToStr _ = "" -- new ctor
 
-        ih (IHCon _ a) = prettyPrint $ unqual a
-        ih (IHInfix _ _ a) = prettyPrint $ unqual a
-        ih (IHParen _ a) = ih a
-        ih (IHApp _ a _) = ih a
+derives _ = mempty -- {-# COMPLETE LL #-}
 
 un = undefined
 
 hasT t x = not $ null (universeBi x `asTypeOf` [t])
-hasT2 ~(t1,t2) = hasT t1 ||^ hasT t2
+hasT2' ~(t1,t2) = hasT t1 ||^ hasT t2
 
-hasS :: (Data x, Data (f S)) => (f S -> Bool) -> x -> Bool
+hasS :: (Data x, Data a) => (a -> Bool) -> x -> Bool
 hasS test = any test . universeBi
 
 has f = any f . universeBi
 
 -- Only whole number fractions are permitted by NumDecimals extension.
 -- Anything not-whole raises an error.
-isWholeFrac :: Literal S -> Bool
-isWholeFrac (Frac _ v _) = denominator v == 1
+isWholeFrac :: HsExpr GhcPs -> Bool
+isWholeFrac (HsLit _ (HsRat _ (FL _ _ v) _)) = denominator v == 1
+isWholeFrac (HsOverLit _ (OverLit _ (HsFractional (FL _ _ v)) _)) = denominator v == 1
 isWholeFrac _ = False
diff --git a/src/Hint/Match.hs b/src/Hint/Match.hs
--- a/src/Hint/Match.hs
+++ b/src/Hint/Match.hs
@@ -1,8 +1,5 @@
 {-# LANGUAGE PatternGuards, ViewPatterns, RecordWildCards, FlexibleContexts, ScopedTypeVariables #-}
 
--- Keep until 'checkSide', 'checkDefine', ... are used.
-{-# OPTIONS_GHC -Wno-unused-top-binds #-}
-
 {-
 The matching does a fairly simple unification between the two terms, treating
 any single letter variable on the left as a free variable. After the matching
@@ -40,65 +37,31 @@
 not . not . x ==> x
 -}
 
-module Hint.Match(readMatch,readMatch') where
+module Hint.Match(readMatch') where
 
-import Control.Applicative
-import Data.List.Extra
-import Data.Maybe
-import Config.Type
-import Hint.Type
-import Control.Monad
-import Data.Tuple.Extra
-import HSE.Unify
+import Hint.Type (ModuleEx,Idea,idea',ideaNote,toSS')
 import Util
 import Timing
 import qualified Data.Set as Set
-import Prelude
 import qualified Refact.Types as R
 
-import qualified HsSyn as GHC
-import qualified SrcLoc as GHC
-import qualified BasicTypes as GHC
+import Control.Monad
+import Data.Tuple.Extra
+import Data.Maybe
+import Config.Type
+import Data.Generics.Uniplate.Operations
+
+import HsSyn
+import SrcLoc
+import BasicTypes
 import RdrName
 import OccName
 import Data.Data
 import GHC.Util
 
-fmapAn :: Exp b -> Exp SrcSpanInfo
-fmapAn = fmap (const an)
-
-
----------------------------------------------------------------------
--- READ THE RULE
-
--- old
-
-readMatch :: [HintRule] -> DeclHint
-readMatch settings = findIdeas (concatMap readRule settings)
-
--- new
-
-readMatch' :: [HintRule] -> Scope' -> ModuleEx -> GHC.LHsDecl GHC.GhcPs -> [Idea]
+readMatch' :: [HintRule] -> Scope' -> ModuleEx -> LHsDecl GhcPs -> [Idea]
 readMatch' settings = findIdeas' (concatMap readRule' settings)
 
--- old
-
-readRule :: HintRule -> [HintRule]
-readRule m@HintRule{hintRuleLHS=(fmapAn -> hintRuleLHS), hintRuleRHS=(fmapAn -> hintRuleRHS), hintRuleSide=(fmap fmapAn -> hintRuleSide)} =
-    (:) m{hintRuleLHS=hintRuleLHS,hintRuleSide=hintRuleSide,hintRuleRHS=hintRuleRHS} $ do
-        (l,v1) <- dotVersion hintRuleLHS
-        (r,v2) <- dotVersion hintRuleRHS
-        guard $ v1 == v2 && l /= [] && (length l > 1 || length r > 1) && Set.notMember v1 (freeVars $ maybeToList hintRuleSide ++ l ++ r)
-        if r /= [] then
-            [m{hintRuleLHS=dotApps l, hintRuleRHS=dotApps r, hintRuleSide=hintRuleSide}
-            ,m{hintRuleLHS=dotApps (l++[toNamed v1]), hintRuleRHS=dotApps (r++[toNamed v1]), hintRuleSide=hintRuleSide}]
-         else if length l > 1 then
-            [m{hintRuleLHS=dotApps l, hintRuleRHS=toNamed "id", hintRuleSide=hintRuleSide}
-            ,m{hintRuleLHS=dotApps (l++[toNamed v1]), hintRuleRHS=toNamed v1, hintRuleSide=hintRuleSide}]
-         else []
-
--- new
-
 readRule' :: HintRule -> [HintRule]
 readRule' m@HintRule{ hintRuleGhcLHS=(stripLocs' . unwrap -> hintRuleGhcLHS)
                     , hintRuleGhcRHS=(stripLocs' . unwrap -> hintRuleGhcRHS)
@@ -109,6 +72,7 @@
         , hintRuleGhcSide=wrap <$> hintRuleGhcSide } $ do
     (l, v1) <- dotVersion' hintRuleGhcLHS
     (r, v2) <- dotVersion' hintRuleGhcRHS
+
     guard $ v1 == v2 && not (null l) && (length l > 1 || length r > 1) && Set.notMember v1 (Set.map occNameString (freeVars' $ maybeToList hintRuleGhcSide ++ l ++ r))
     if not (null r) then
       [ m{ hintRuleGhcLHS=wrap (dotApps' l), hintRuleGhcRHS=wrap (dotApps' r), hintRuleGhcSide=wrap <$> hintRuleGhcSide }
@@ -118,43 +82,27 @@
             , m{ hintRuleGhcLHS=wrap (dotApps' (l++[strToVar' v1])), hintRuleGhcRHS=wrap (strToVar' v1), hintRuleGhcSide=wrap <$> hintRuleGhcSide}]
       else []
 
--- old
-
--- find a dot version of this rule, return the sequence of app prefixes, and the var
-dotVersion :: Exp_ -> [([Exp_], String)]
-dotVersion (view -> Var_ v) | isUnifyVar v = [([], v)]
-dotVersion (App l ls rs) = first (ls :) <$> dotVersion (fromParen rs)
-dotVersion (InfixApp l x op y) = (first (LeftSection l x op :) <$> dotVersion y) ++
-                                 (first (RightSection l op y:) <$> dotVersion x)
-dotVersion _ = []
-
--- new
-
 -- Find a dot version of this rule, return the sequence of app
 -- prefixes, and the var.
-dotVersion' :: GHC.LHsExpr GHC.GhcPs -> [([GHC.LHsExpr GHC.GhcPs], String)]
+dotVersion' :: LHsExpr GhcPs -> [([LHsExpr GhcPs], String)]
 dotVersion' (view' -> Var_' v) | isUnifyVar v = [([], v)]
-dotVersion' (GHC.LL _ (GHC.HsApp _ ls rs)) = first (ls :) <$> dotVersion' (fromParen' rs)
-dotVersion' (GHC.LL l (GHC.OpApp _ x op y)) =(first (GHC.cL l (GHC.SectionL GHC.noExt x op) :) <$> dotVersion' y) ++
-                                             (first (GHC.cL l (GHC.SectionR GHC.noExt op y) :) <$> dotVersion' x)
+dotVersion' (LL _ (HsApp _ ls rs)) = first (ls :) <$> dotVersion' (fromParen' rs)
+dotVersion' (LL l (OpApp _ x op y)) =
+  -- In a GHC parse tree, raw sections aren't valid application terms.
+  -- To be suitable as application terms, they must be enclosed in
+  -- parentheses.
+
+  --   If a == b then
+  --   x is 'a', op is '==' and y is 'b' and,
+  let lSec = addParen' (cL l (SectionL noExt x op)) -- (a == )
+      rSec = addParen' (cL l (SectionR noExt op y)) -- ( == b)
+  in (first (lSec :) <$> dotVersion' y) ++ (first (rSec :) <$> dotVersion' x) -- [([(a ==)], b), ([(b == )], a])].
 dotVersion' _ = []
 
 ---------------------------------------------------------------------
 -- PERFORM THE MATCHING
 
--- old
-
-findIdeas :: [HintRule] -> Scope -> ModuleEx -> Decl_ -> [Idea]
-findIdeas matches s _ decl = timed "Hint" "Match apply" $ forceList
-    [ (idea (hintRuleSeverity m) (hintRuleName m) x y [r]){ideaNote=notes}
-    | decl <- findDecls decl
-    , (parent,x) <- universeParentExp decl
-    , m <- matches, Just (y,notes, subst) <- [matchIdea s decl m parent x]
-    , let r = R.Replace R.Expr (toSS x) subst (prettyPrint $ hintRuleRHS m) ]
-
--- new
-
-findIdeas' :: [HintRule] -> Scope' -> ModuleEx -> GHC.LHsDecl GHC.GhcPs -> [Idea]
+findIdeas' :: [HintRule] -> Scope' -> ModuleEx -> LHsDecl GhcPs -> [Idea]
 findIdeas' matches s _ decl = timed "Hint" "Match apply" $ forceList
     [ (idea' (hintRuleSeverity m) (hintRuleName m) x y [r]){ideaNote=notes}
     | decl <- findDecls' decl
@@ -163,52 +111,17 @@
     , let r = R.Replace R.Expr (toSS' x) subst (unsafePrettyPrint $ unwrap (hintRuleGhcRHS m))
     ]
 
--- old
-
-findDecls :: Decl_ -> [Decl_]
-findDecls x@InstDecl{} = children x
-findDecls RulePragmaDecl{} = []  -- often rules contain things that HLint would rewrite
-findDecls x = [x]
-
--- new
-
-findDecls' :: GHC.LHsDecl GHC.GhcPs -> [GHC.LHsDecl GHC.GhcPs]
-findDecls' x@(GHC.LL _ GHC.InstD{}) = children x
-findDecls' (GHC.LL _ GHC.RuleD{}) = [] -- Often rules contain things that HLint would rewrite.
+findDecls' :: LHsDecl GhcPs -> [LHsDecl GhcPs]
+findDecls' x@(LL _ InstD{}) = children x
+findDecls' (LL _ RuleD{}) = [] -- Often rules contain things that HLint would rewrite.
 findDecls' x = [x]
 
--- old
-
-matchIdea :: Scope -> Decl_ -> HintRule -> Maybe (Int, Exp_) -> Exp_ -> Maybe (Exp_, [Note], [(String, R.SrcSpan)])
-matchIdea s decl HintRule{..} parent x = do
-    let nm a b = scopeMatch (hintRuleScope,a) (s,b)
-    u <- unifyExp nm True hintRuleLHS x
-    u <- validSubst (=~=) u
-    -- need to check free vars before unqualification, but after subst (with e)
-    -- need to unqualify before substitution (with res)
-    let e = substitute u hintRuleRHS
-        res = addBracket parent $ performSpecial $ substitute u $ unqualify hintRuleScope s hintRuleRHS
-    guard $ (freeVars e Set.\\ Set.filter (not . isUnifyVar) (freeVars hintRuleRHS))
-            `Set.isSubsetOf` freeVars x
-        -- check no unexpected new free variables
-
-    -- check it isn't going to get broken by QuasiQuotes as per #483
-    -- if we have lambdas we might be moving, and QuasiQuotes, we might inadvertantly break free vars
-    -- because quasi quotes don't show what free vars they make use of
-    guard $ not (any isLambda $ universe hintRuleLHS) || not (any isQuasiQuote $ universe x)
-
-    guard $ checkSide hintRuleSide $ ("original",x) : ("result",res) : fromSubst u
-    guard $ checkDefine decl parent res
-    return (res, hintRuleNotes, [(s, toSS pos) | (s, pos) <- fromSubst u, ann pos /= an])
-
--- new
-
 matchIdea' :: Scope'
-           -> GHC.LHsDecl GHC.GhcPs
+           -> LHsDecl GhcPs
            -> HintRule
-           -> Maybe (Int, GHC.LHsExpr GHC.GhcPs)
-           -> GHC.LHsExpr GHC.GhcPs
-           -> Maybe (GHC.LHsExpr GHC.GhcPs, [Note], [(String, R.SrcSpan)])
+           -> Maybe (Int, LHsExpr GhcPs)
+           -> LHsExpr GhcPs
+           -> Maybe (LHsExpr GhcPs, [Note], [(String, R.SrcSpan)])
 matchIdea' sb decl HintRule{..} parent x = do
   let lhs = unwrap hintRuleGhcLHS
       rhs = unwrap hintRuleGhcRHS
@@ -220,7 +133,7 @@
   -- Need to check free vars before unqualification, but after subst
   -- (with 'e') need to unqualify before substitution (with 'res').
   let e = substitute' u rhs
-      res = addBracket' parent $ performSpecial' $ substitute' u $ unqualify' sa sb rhs
+      res = addBracketTy' (addBracket' parent $ performSpecial' $ substitute' u $ unqualify' sa sb rhs)
   guard $ (freeVars' e Set.\\ Set.filter (not . isUnifyVar . occNameString) (freeVars' rhs)) `Set.isSubsetOf` freeVars' x
       -- Check no unexpected new free variables.
 
@@ -233,92 +146,33 @@
   guard $ checkSide' (unwrap <$> hintRuleGhcSide) $ ("original", x) : ("result", res) : fromSubst' u
   guard $ checkDefine' decl parent res
 
-  return (res, hintRuleNotes, [(s, toSS' pos) | (s, pos) <- fromSubst' u, GHC.getLoc pos /= GHC.noSrcSpan])
+  return (res, hintRuleNotes, [(s, toSS' pos) | (s, pos) <- fromSubst' u, getLoc pos /= noSrcSpan])
 
 ---------------------------------------------------------------------
 -- SIDE CONDITIONS
 
--- old
-
-checkSide :: Maybe Exp_ -> [(String, Exp_)] -> Bool
-checkSide x bind = maybe True bool x
-    where
-        bool :: Exp_ -> Bool
-        bool (InfixApp _ x op y)
-            | opExp op ~= "&&" = bool x && bool y
-            | opExp op ~= "||" = bool x || bool y
-            | opExp op ~= "==" = expr (fromParen1 x) =~= expr (fromParen1 y)
-        bool (App _ x y) | x ~= "not" = not $ bool y
-        bool (Paren _ x) = bool x
-
-        bool (App _ cond (sub -> y))
-            | 'i':'s':typ <- fromNamed cond = isType typ y
-        bool (App _ (App _ cond (sub -> x)) (sub -> y))
-            | cond ~= "notIn" = and [x `notElem` universe y | x <- list x, y <- list y]
-            | cond ~= "notEq" = x /=~= y
-        bool x | x ~= "noTypeCheck" = True
-        bool x | x ~= "noQuickCheck" = True
-        bool x = error $ "Hint.Match.checkSide, unknown side condition: " ++ prettyPrint x
-
-        expr :: Exp_ -> Exp_
-        expr (App _ (fromNamed -> "subst") x) = sub $ fromParen1 x
-        expr x = x
-
-        isType "Compare" x = True -- just a hint for proof stuff
-        isType "Atom" x = isAtom x
-        isType "WHNF" x = isWHNF x
-        isType "Wildcard" x = any isFieldWildcard $ universeS x
-        isType "Nat" (asInt -> Just x) | x >= 0 = True
-        isType "Pos" (asInt -> Just x) | x >  0 = True
-        isType "Neg" (asInt -> Just x) | x <  0 = True
-        isType "NegZero" (asInt -> Just x) | x <= 0 = True
-        isType ('L':'i':'t':typ@(_:_)) (Lit _ x) =
-           -- This case only comes up in the tests with 'LitInt'.
-          let top = head (words $ show x) in
-          typ == top
-        isType typ x =
-          let top = head (words $ show x) in
-          typ == top
-
-        asInt :: Exp_ -> Maybe Integer
-        asInt (Paren _ x) = asInt x
-        asInt (NegApp _ x) = negate <$> asInt x
-        asInt (Lit _ (Int _ x _)) = Just x
-        asInt _ = Nothing
-
-        list :: Exp_ -> [Exp_]
-        list (List _ xs) = xs
-        list x = [x]
-
-        sub :: Exp_ -> Exp_
-        sub = transform f
-            where f (view -> Var_ x) | Just y <- lookup x bind = y
-                  f x = x
-
--- new
-
-checkSide' :: Maybe (GHC.LHsExpr GHC.GhcPs) -> [(String, GHC.LHsExpr GHC.GhcPs)] -> Bool
+checkSide' :: Maybe (LHsExpr GhcPs) -> [(String, LHsExpr GhcPs)] -> Bool
 checkSide' x bind = maybe True bool x
     where
-      bool :: GHC.LHsExpr GHC.GhcPs -> Bool
-      bool (GHC.LL _ (GHC.OpApp _ x op y))
+      bool :: LHsExpr GhcPs -> Bool
+      bool (LL _ (OpApp _ x op y))
         | varToStr' op == "&&" = bool x && bool y
         | varToStr' op == "||" = bool x || bool y
         | varToStr' op == "==" = expr (fromParen1' x) `eqNoLoc'` expr (fromParen1' y)
-      bool (GHC.LL _ (GHC.HsApp _ x y)) | varToStr' x == "not" = not $ bool y
-      bool (GHC.LL _ (GHC.HsPar _ x)) = bool x
+      bool (LL _ (HsApp _ x y)) | varToStr' x == "not" = not $ bool y
+      bool (LL _ (HsPar _ x)) = bool x
 
-      bool (GHC.LL _ (GHC.HsApp _ cond (sub -> y)))
+      bool (LL _ (HsApp _ cond (sub -> y)))
         | 'i' : 's' : typ <- varToStr' cond = isType typ y
-      bool (GHC.LL _ (GHC.HsApp _ (GHC.LL _ (GHC.HsApp _ cond (sub -> x))) (sub -> y)))
+      bool (LL _ (HsApp _ (LL _ (HsApp _ cond (sub -> x))) (sub -> y)))
           | varToStr' cond == "notIn" = and [wrap (stripLocs' x) `notElem` map (wrap . stripLocs') (universe y) | x <- list x, y <- list y]
           | varToStr' cond == "notEq" = not (x `eqNoLoc'` y)
       bool x | varToStr' x == "noTypeCheck" = True
       bool x | varToStr' x == "noQuickCheck" = True
       bool x = error $ "Hint.Match.checkSide', unknown side condition: " ++ unsafePrettyPrint x
 
-      expr :: GHC.LHsExpr GHC.GhcPs -> GHC.LHsExpr GHC.GhcPs
-      expr (GHC.LL _ (GHC.HsApp _ (varToStr' -> "subst") x)) = sub $ fromParen1' x
+      expr :: LHsExpr GhcPs -> LHsExpr GhcPs
+      expr (LL _ (HsApp _ (varToStr' -> "subst") x)) = sub $ fromParen1' x
       expr x = x
 
       isType "Compare" x = True -- Just a hint for proof stuff
@@ -329,103 +183,72 @@
       isType "Pos" (asInt -> Just x) | x >  0 = True
       isType "Neg" (asInt -> Just x) | x <  0 = True
       isType "NegZero" (asInt -> Just x) | x <= 0 = True
-      isType "LitInt" (GHC.LL _ (GHC.HsLit _ GHC.HsInt{})) = True
-      isType "LitInt" (GHC.LL _ (GHC.HsOverLit _ (GHC.OverLit _ GHC.HsIntegral{} _))) = True
-      isType "Var" (GHC.LL _ GHC.HsVar{}) = True
-      isType "App" (GHC.LL _ GHC.HsApp{}) = True
-      isType "InfixApp" (GHC.LL _ x@GHC.OpApp{}) = True
-      isType "Paren" (GHC.LL _ x@GHC.HsPar{}) = True
-      isType "Tuple" (GHC.LL _ GHC.ExplicitTuple{}) = True
+      isType "LitInt" (LL _ (HsLit _ HsInt{})) = True
+      isType "LitInt" (LL _ (HsOverLit _ (OverLit _ HsIntegral{} _))) = True
+      isType "Var" (LL _ HsVar{}) = True
+      isType "App" (LL _ HsApp{}) = True
+      isType "InfixApp" (LL _ x@OpApp{}) = True
+      isType "Paren" (LL _ x@HsPar{}) = True
+      isType "Tuple" (LL _ ExplicitTuple{}) = True
 
-      isType typ (GHC.LL _ x) =
+      isType typ (LL _ x) =
         let top = showConstr (toConstr x) in
         typ == top
       isType _ _ = False -- {-# COMPLETE LL#-}
 
-      asInt :: GHC.LHsExpr GHC.GhcPs -> Maybe Integer
-      asInt (GHC.LL _ (GHC.HsPar _ x)) = asInt x
-      asInt (GHC.LL _ (GHC.NegApp _ x _)) = negate <$> asInt x
-      asInt (GHC.LL _ (GHC.HsLit _ (GHC.HsInt _ (GHC.IL _ neg x)) )) = Just $ if neg then -x else x
-      asInt (GHC.LL _ (GHC.HsOverLit _ (GHC.OverLit _ (GHC.HsIntegral (GHC.IL _ neg x)) _))) = Just $ if neg then -x else x
+      asInt :: LHsExpr GhcPs -> Maybe Integer
+      asInt (LL _ (HsPar _ x)) = asInt x
+      asInt (LL _ (NegApp _ x _)) = negate <$> asInt x
+      asInt (LL _ (HsLit _ (HsInt _ (IL _ neg x)) )) = Just $ if neg then -x else x
+      asInt (LL _ (HsOverLit _ (OverLit _ (HsIntegral (IL _ neg x)) _))) = Just $ if neg then -x else x
       asInt _ = Nothing
 
-      list :: GHC.LHsExpr GHC.GhcPs -> [GHC.LHsExpr GHC.GhcPs]
-      list (GHC.LL _ (GHC.ExplicitList _ _ xs)) = xs
+      list :: LHsExpr GhcPs -> [LHsExpr GhcPs]
+      list (LL _ (ExplicitList _ _ xs)) = xs
       list x = [x]
 
-      sub :: GHC.LHsExpr GHC.GhcPs -> GHC.LHsExpr GHC.GhcPs
+      sub :: LHsExpr GhcPs -> LHsExpr GhcPs
       sub = transform f
         where f (view' -> Var_' x) | Just y <- lookup x bind = y
               f x = x
 
--- old
-
--- does the result look very much like the declaration
-checkDefine :: Decl_ -> Maybe (Int, Exp_) -> Exp_ -> Bool
-checkDefine x Nothing y = fromNamed x /= fromNamed (transformBi unqual $ head $ fromApps y)
-checkDefine _ _ _ = True
-
--- new
-
 -- Does the result look very much like the declaration?
-checkDefine' :: GHC.LHsDecl GHC.GhcPs -> Maybe (Int, GHC.LHsExpr GHC.GhcPs) -> GHC.LHsExpr GHC.GhcPs -> Bool
+checkDefine' :: LHsDecl GhcPs -> Maybe (Int, LHsExpr GhcPs) -> LHsExpr GhcPs -> Bool
 checkDefine' x Nothing y = declName x /= Just (varToStr' (transformBi unqual' $ head $ fromApps' y))
 checkDefine' _ _ _ = True
 
 ---------------------------------------------------------------------
 -- TRANSFORMATION
 
--- old
-
--- if it has _eval_ do evaluation on it
-performSpecial :: Exp_ -> Exp_
-performSpecial = transform fNoParen . fEval
-    where
-        fEval (App _ e x) | e ~= "_eval_" = reduce x
-        fEval x = x
-
-        fNoParen (App _ e x) | e ~= "_noParen_" = fromParen x
-        fNoParen x = x
-
--- new
-
 -- If it has '_eval_' do evaluation on it.
-performSpecial' :: GHC.LHsExpr GHC.GhcPs -> GHC.LHsExpr GHC.GhcPs
+performSpecial' :: LHsExpr GhcPs -> LHsExpr GhcPs
 performSpecial' = transform fNoParen . fEval
   where
-    fEval, fNoParen :: GHC.LHsExpr GHC.GhcPs -> GHC.LHsExpr GHC.GhcPs
-    fEval (GHC.LL _ (GHC.HsApp _ e x)) | varToStr' e == "_eval_" = reduce' x
+    fEval, fNoParen :: LHsExpr GhcPs -> LHsExpr GhcPs
+    fEval (LL _ (HsApp _ e x)) | varToStr' e == "_eval_" = reduce' x
     fEval x = x
-    fNoParen (GHC.LL _ (GHC.HsApp _ e x)) | varToStr' e == "_noParen_" = fromParen' x
+    fNoParen (LL _ (HsApp _ e x)) | varToStr' e == "_noParen_" = fromParen' x
     fNoParen x = x
 
--- old
-
--- contract Data.List.foo ==> foo, if Data.List is loaded
-unqualify :: Scope -> Scope -> Exp_ -> Exp_
-unqualify from to = transformBi f
-    where
-        f x@(UnQual _ (Ident _ s)) | isUnifyVar s = x
-        f x = scopeMove (from,x) to
-
--- new
-
 -- Contract : 'Data.List.foo' => 'foo' if 'Data.List' is loaded.
-unqualify' :: Scope' -> Scope' -> GHC.LHsExpr GHC.GhcPs -> GHC.LHsExpr GHC.GhcPs
+unqualify' :: Scope' -> Scope' -> LHsExpr GhcPs -> LHsExpr GhcPs
 unqualify' from to = transformBi f
   where
-    f :: GHC.Located RdrName -> GHC.Located RdrName
-    f x@(GHC.L _ (Unqual s)) | isUnifyVar (occNameString s) = x
+    f :: Located RdrName -> Located RdrName
+    f x@(L _ (Unqual s)) | isUnifyVar (occNameString s) = x
     f x = scopeMove' (from, x) to
 
--- old
-
-addBracket :: Maybe (Int,Exp_) -> Exp_ -> Exp_
-addBracket (Just (i,p)) c | needBracketOld i p c = Paren an c
-addBracket _ x = x
-
--- new
-
-addBracket' :: Maybe (Int, GHC.LHsExpr GHC.GhcPs) -> GHC.LHsExpr GHC.GhcPs -> GHC.LHsExpr GHC.GhcPs
-addBracket' (Just (i, p)) c | needBracketOld' i p c = GHC.noLoc $ GHC.HsPar GHC.noExt c
+addBracket' :: Maybe (Int, LHsExpr GhcPs) -> LHsExpr GhcPs -> LHsExpr GhcPs
+addBracket' (Just (i, p)) c | needBracketOld' i p c = noLoc $ HsPar noExt c
 addBracket' _ x = x
+
+-- Type substitution e.g. 'Foo Int' for 'a' in 'Proxy a' can lead to a
+-- need to bracket type applications in  This doesn't come up in HSE
+-- because the pretty printer inserts them.
+addBracketTy' :: LHsExpr GhcPs -> LHsExpr GhcPs
+addBracketTy'= transformBi f
+  where
+    f :: LHsType GhcPs -> LHsType GhcPs
+    f (LL _ (HsAppTy _ t x@(LL _ HsAppTy{}))) =
+      noLoc (HsAppTy noExt t (noLoc (HsParTy noExt x)))
+    f x = x
