    {-# LANGUAGE CPP #-}
    #ifdef TRUSTWORTHY
    # if MIN_VERSION_template_haskell(2,12,0)
    {-# LANGUAGE Safe #-}
    # else
    {-# LANGUAGE Trustworthy #-}
    # endif
    #endif

    #ifndef MIN_VERSION_template_haskell
    #define MIN_VERSION_template_haskell(x,y,z) (defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 706)
    #endif

    #ifndef MIN_VERSION_containers
    #define MIN_VERSION_containers(x,y,z) 1
    #endif

    #ifndef MIN_VERSION_base
    #define MIN_VERSION_base(x,y,z) 1
    #endif
    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Control.Lens.Internal.TH
    -- Copyright   :  (C) 2013-2016 Edward Kmett and Eric Mertens
    -- License     :  BSD-style (see the file LICENSE)
    -- Maintainer  :  Edward Kmett <ekmett@gmail.com>
    -- Stability   :  experimental
    -- Portability :  non-portable
    --
    ----------------------------------------------------------------------------
    module Control.Lens.Internal.TH where

    import Data.Functor.Contravariant
    import Language.Haskell.TH
    import Language.Haskell.TH.Syntax
    import qualified Data.Map as Map
    import qualified Data.Set as Set
    #ifndef CURRENT_PACKAGE_KEY
    import Data.Version (showVersion)
    import Paths_lens (version)
    #endif

    -- | Apply arguments to a type constructor
    appsT :: TypeQ -> [TypeQ] -> TypeQ
    appsT :: TypeQ -> [TypeQ] -> TypeQ
    appsT = (TypeQ -> TypeQ -> TypeQ) -> TypeQ -> [TypeQ] -> TypeQ
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl TypeQ -> TypeQ -> TypeQ
    appT

    -- | Apply arguments to a function
    appsE1 :: ExpQ -> [ExpQ] -> ExpQ
    appsE1 :: ExpQ -> [ExpQ] -> ExpQ
    appsE1 = (ExpQ -> ExpQ -> ExpQ) -> ExpQ -> [ExpQ] -> ExpQ
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl ExpQ -> ExpQ -> ExpQ
    appE

    -- | Construct a tuple type given a list of types.
    toTupleT :: [TypeQ] -> TypeQ
    toTupleT :: [TypeQ] -> TypeQ
    toTupleT [x :: TypeQ
    x] = TypeQ
    x
    toTupleT xs :: [TypeQ]
    xs = TypeQ -> [TypeQ] -> TypeQ
    appsT (Int -> TypeQ
    tupleT ([TypeQ] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [TypeQ]
    xs)) [TypeQ]
    xs

    -- | Construct a tuple value given a list of expressions.
    toTupleE :: [ExpQ] -> ExpQ
    toTupleE :: [ExpQ] -> ExpQ
    toTupleE [x :: ExpQ
    x] = ExpQ
    x
    toTupleE xs :: [ExpQ]
    xs = [ExpQ] -> ExpQ
    tupE [ExpQ]
    xs

    -- | Construct a tuple pattern given a list of patterns.
    toTupleP :: [PatQ] -> PatQ
    toTupleP :: [PatQ] -> PatQ
    toTupleP [x :: PatQ
    x] = PatQ
    x
    toTupleP xs :: [PatQ]
    xs = [PatQ] -> PatQ
    tupP [PatQ]
    xs

    -- | Apply arguments to a type constructor.
    conAppsT :: Name -> [Type] -> Type
    conAppsT :: Name -> [Type] -> Type
    conAppsT conName :: Name
    conName = (Type -> Type -> Type) -> Type -> [Type] -> Type
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl Type -> Type -> Type
    AppT (Name -> Type
    ConT Name
    conName)

    -- | Return 'Name' contained in a 'TyVarBndr'.
    bndrName :: TyVarBndr -> Name
    bndrName :: TyVarBndr -> Name
    bndrName (PlainTV  n :: Name
    n  ) = Name
    n
    bndrName (KindedTV n :: Name
    n _) = Name
    n

    fromSet :: (k -> v) -> Set.Set k -> Map.Map k v
    #if MIN_VERSION_containers(0,5,0)
    fromSet :: (k -> v) -> Set k -> Map k v
    fromSet = (k -> v) -> Set k -> Map k v
    forall k a. (k -> a) -> Set k -> Map k a
    Map.fromSet
    #else
    fromSet f x = Map.fromDistinctAscList [ (k,f k) | k <- Set.toAscList x ]
    #endif

    -- | Generate many new names from a given base name.
    newNames :: String {- ^ base name -} -> Int {- ^ count -} -> Q [Name]
    newNames :: String -> Int -> Q [Name]
    newNames base :: String
    base n :: Int
    n = [Q Name] -> Q [Name]
    forall (t :: * -> *) (m :: * -> *) a.
    (Traversable t, Monad m) =>
    t (m a) -> m (t a)
    sequence [ String -> Q Name
    newName (String
    baseString -> String -> String
    forall a. [a] -> [a] -> [a]
    ++Int -> String
    forall a. Show a => a -> String
    show Int
    i) | Int
    i <- [1..Int
    n] ]

    -- | Decompose an applied type into its individual components. For example, this:
    --
    -- @
    -- Either Int Char
    -- @
    --
    -- would be unfolded to this:
    --
    -- @
    -- ('ConT' ''Either, ['ConT' ''Int, 'ConT' ''Char])
    -- @
    --
    -- This function ignores explicit parentheses and visible kind applications.
    unfoldType :: Type -> (Type, [Type])
    unfoldType :: Type -> (Type, [Type])
    unfoldType = [Type] -> Type -> (Type, [Type])
    go []
      where
        go :: [Type] -> Type -> (Type, [Type])
        go :: [Type] -> Type -> (Type, [Type])
    go acc :: [Type]
    acc (ForallT _ _ ty :: Type
    ty) = [Type] -> Type -> (Type, [Type])
    go [Type]
    acc Type
    ty
        go acc :: [Type]
    acc (AppT ty1 :: Type
    ty1 ty2 :: Type
    ty2)   = [Type] -> Type -> (Type, [Type])
    go (Type
    ty2Type -> [Type] -> [Type]
    forall a. a -> [a] -> [a]
    :[Type]
    acc) Type
    ty1
        go acc :: [Type]
    acc (SigT ty :: Type
    ty _)      = [Type] -> Type -> (Type, [Type])
    go [Type]
    acc Type
    ty
    #if MIN_VERSION_template_haskell(2,11,0)
        go acc :: [Type]
    acc (ParensT ty :: Type
    ty)     = [Type] -> Type -> (Type, [Type])
    go [Type]
    acc Type
    ty
    #endif
    #if MIN_VERSION_template_haskell(2,15,0)
        go acc :: [Type]
    acc (AppKindT ty :: Type
    ty _)  = [Type] -> Type -> (Type, [Type])
    go [Type]
    acc Type
    ty
    #endif
        go acc :: [Type]
    acc ty :: Type
    ty               = (Type
    ty, [Type]
    acc)

    ------------------------------------------------------------------------
    -- Manually quoted names
    ------------------------------------------------------------------------
    -- By manually generating these names we avoid needing to use the
    -- TemplateHaskell language extension when compiling the lens library.
    -- This allows the library to be used in stage1 cross-compilers.

    lensPackageKey         :: String
    #ifdef CURRENT_PACKAGE_KEY
    lensPackageKey :: String
    lensPackageKey          = CURRENT_PACKAGE_KEY
    #else
    lensPackageKey          = "lens-" ++ showVersion version
    #endif

    mkLensName_tc          :: String -> String -> Name
    mkLensName_tc :: String -> String -> Name
    mkLensName_tc           = String -> String -> String -> Name
    mkNameG_tc String
    lensPackageKey

    mkLensName_v           :: String -> String -> Name
    mkLensName_v :: String -> String -> Name
    mkLensName_v            = String -> String -> String -> Name
    mkNameG_v String
    lensPackageKey

    traversalTypeName      :: Name
    traversalTypeName :: Name
    traversalTypeName       = String -> String -> Name
    mkLensName_tc "Control.Lens.Type" "Traversal"

    traversal'TypeName     :: Name
    traversal'TypeName :: Name
    traversal'TypeName      = String -> String -> Name
    mkLensName_tc "Control.Lens.Type" "Traversal'"

    lensTypeName           :: Name
    lensTypeName :: Name
    lensTypeName            = String -> String -> Name
    mkLensName_tc "Control.Lens.Type" "Lens"

    lens'TypeName          :: Name
    lens'TypeName :: Name
    lens'TypeName           = String -> String -> Name
    mkLensName_tc "Control.Lens.Type" "Lens'"

    isoTypeName            :: Name
    isoTypeName :: Name
    isoTypeName             = String -> String -> Name
    mkLensName_tc "Control.Lens.Type" "Iso"

    iso'TypeName           :: Name
    iso'TypeName :: Name
    iso'TypeName            = String -> String -> Name
    mkLensName_tc "Control.Lens.Type" "Iso'"

    getterTypeName         :: Name
    getterTypeName :: Name
    getterTypeName          = String -> String -> Name
    mkLensName_tc "Control.Lens.Type" "Getter"

    foldTypeName           :: Name
    foldTypeName :: Name
    foldTypeName            = String -> String -> Name
    mkLensName_tc "Control.Lens.Type" "Fold"

    prismTypeName          :: Name
    prismTypeName :: Name
    prismTypeName           = String -> String -> Name
    mkLensName_tc "Control.Lens.Type" "Prism"

    prism'TypeName         :: Name
    prism'TypeName :: Name
    prism'TypeName          = String -> String -> Name
    mkLensName_tc "Control.Lens.Type" "Prism'"

    reviewTypeName          :: Name
    reviewTypeName :: Name
    reviewTypeName           = String -> String -> Name
    mkLensName_tc "Control.Lens.Type" "Review"

    wrappedTypeName         :: Name
    wrappedTypeName :: Name
    wrappedTypeName          = String -> String -> Name
    mkLensName_tc "Control.Lens.Wrapped" "Wrapped"

    unwrappedTypeName       :: Name
    unwrappedTypeName :: Name
    unwrappedTypeName        = String -> String -> Name
    mkLensName_tc "Control.Lens.Wrapped" "Unwrapped"

    rewrappedTypeName       :: Name
    rewrappedTypeName :: Name
    rewrappedTypeName        = String -> String -> Name
    mkLensName_tc "Control.Lens.Wrapped" "Rewrapped"

    _wrapped'ValName        :: Name
    _wrapped'ValName :: Name
    _wrapped'ValName         = String -> String -> Name
    mkLensName_v "Control.Lens.Wrapped" "_Wrapped'"

    isoValName              :: Name
    isoValName :: Name
    isoValName               = String -> String -> Name
    mkLensName_v "Control.Lens.Iso" "iso"

    prismValName            :: Name
    prismValName :: Name
    prismValName             = String -> String -> Name
    mkLensName_v "Control.Lens.Prism" "prism"

    untoValName             :: Name
    untoValName :: Name
    untoValName              = String -> String -> Name
    mkLensName_v "Control.Lens.Review" "unto"

    phantomValName          :: Name
    phantomValName :: Name
    phantomValName           = String -> String -> Name
    mkLensName_v "Control.Lens.Internal.TH" "phantom2"

    phantom2 :: (Functor f, Contravariant f) => f a -> f b
    phantom2 :: f a -> f b
    phantom2 = f a -> f b
    forall (f :: * -> *) a b.
    (Functor f, Contravariant f) =>
    f a -> f b
    phantom
    {-# INLINE phantom2 #-}

    composeValName          :: Name
    composeValName :: Name
    composeValName           = String -> String -> String -> Name
    mkNameG_v "base" "GHC.Base" "."

    idValName               :: Name
    idValName :: Name
    idValName                = String -> String -> String -> Name
    mkNameG_v "base" "GHC.Base" "id"

    fmapValName             :: Name
    fmapValName :: Name
    fmapValName              = String -> String -> String -> Name
    mkNameG_v "base" "GHC.Base" "fmap"

    #if MIN_VERSION_base(4,8,0)
    pureValName             :: Name
    pureValName :: Name
    pureValName              = String -> String -> String -> Name
    mkNameG_v "base" "GHC.Base" "pure"

    apValName               :: Name
    apValName :: Name
    apValName                = String -> String -> String -> Name
    mkNameG_v "base" "GHC.Base" "<*>"
    #else
    pureValName             :: Name
    pureValName              = mkNameG_v "base" "Control.Applicative" "pure"

    apValName               :: Name
    apValName                = mkNameG_v "base" "Control.Applicative" "<*>"
    #endif

    rightDataName           :: Name
    rightDataName :: Name
    rightDataName            = String -> String -> String -> Name
    mkNameG_d "base" "Data.Either" "Right"

    leftDataName            :: Name
    leftDataName :: Name
    leftDataName             = String -> String -> String -> Name
    mkNameG_d "base" "Data.Either" "Left"

    ------------------------------------------------------------------------
    -- Support for generating inline pragmas
    ------------------------------------------------------------------------

    inlinePragma :: Name -> [DecQ]

    #ifdef INLINING

    #if MIN_VERSION_template_haskell(2,8,0)

    # ifdef OLD_INLINE_PRAGMAS
    -- 7.6rc1?
    inlinePragma methodName = [pragInlD methodName (inlineSpecNoPhase Inline False)]
    # else
    -- 7.7.20120830
    inlinePragma :: Name -> [DecQ]
    inlinePragma methodName :: Name
    methodName = [Name -> Inline -> RuleMatch -> Phases -> DecQ
    pragInlD Name
    methodName Inline
    Inline RuleMatch
    FunLike Phases
    AllPhases]
    # endif

    #else
    -- GHC <7.6, TH <2.8.0
    inlinePragma methodName = [pragInlD methodName (inlineSpecNoPhase True False)]
    #endif

    #else

    inlinePragma _ = []

    #endif