HORIZON HASKELLDocslts/ghc-10.0.xfc4e5982026-10-11Search names, modules, packages, or :: a typeCtrl K

GHC 10.0.0.20260917 · lts/ghc-10.0.x · fc4e598 · 2026-10-11

Moduleth-desugar-1.19Haskell2010

Language.Haskell.TH.Desugar

Desugars full Template Haskell syntax into a smaller core syntax for further processing.

  • 57 types
  • 2 classes
  • 118 values
  • Packageth-desugar-1.19
  • Exports180
  • LanguageHaskell2010
  • LicenceBSD-3-Clause
  • SourceDesugar.hs

Desugared data types

47 declarations
datadata DExp
#

Corresponds to TH's Exp type. Note that DLamE takes names, not patterns.

Constructors

Instances7Eq, Data, Show, Generic, Lift, Desugar, …
patternpattern DLamE :: [Name] -> DExp -> DExp
#

Deprecated. Use dLamE or DLamCasesE instead.

A DLamCasesE value with exactly one DClause where all DPats are DVarPs. This pattern synonym is provided for backwards compatibility with older versions of th-desugar in which DLamE was a data constructor of DExp. This pattern synonym is deprecated and will be removed in a future release of th-desugar.

patternpattern DCaseE :: DExp -> [DMatch] -> DExp
#

Deprecated. Use dCaseE or DLamCasesE instead.

An application of a DLamCasesE to some argument, where each DClause in the DLamCasesE value has exactly one DPat. This pattern synonym is provided for backwards compatibility with older versions of th-desugar in which DCaseE was a data constructor of DExp. This pattern synonym is deprecated and will be removed in a future release of th-desugar.

datadata DLetDec
#

Declarations as used in a let statement.

Instances6Eq, Data, Show, Generic, Lift, Rep
datadata NamespaceSpecifier
#

A way to specify a namespace to look in when GHC needs to find a name's source

Constructors

  • NoNamespaceSpecifier

    Name may be everything; If there are two names in different namespaces, then consider both

  • TypeNamespaceSpecifier

    Name should be a type-level entity, such as a data type, type alias, type family, type class, or type variable

  • DataNamespaceSpecifier

    Name should be a term-level entity, such as a function, data constructor, or pattern synonym

Instances7Eq, Data, Ord, Show, Generic, Lift, …
datadata DPat
#
Instances6Eq, Data, Show, Generic, Lift, Rep
datadata DType
#
Instances8Eq, Data, Show, Generic, Lift, Desugar, …
datadata DForallTelescope
#

The type variable binders in a forall.

Constructors

Instances6Eq, Data, Show, Generic, Lift, Rep
typetype DKind = DType
#

Kinds are types. Corresponds to TH's Kind

typetype DCxt = [DPred]
#

Corresponds to TH's Cxt

typetype DPred = DType
#

Predicates are types. Corresponds to TH's Pred

datadata DTyVarBndr flag
#

Corresponds to TH's TyVarBndr

Constructors

Instances10Functor, Foldable, Traversable, Lift, Eq, Data, …
datadata Specificity
#

The specificity of a type variable in a forall ....

Instances9Eq, Data, Ord, Show, Generic, PprFlag, …
datadata BndrVis
#

Visibility of a type variable. See Inferred vs. specified type variables.

Constructors

Instances9Eq, Data, Ord, Show, Generic, PprFlag, …
datadata DMatch
#

Corresponds to TH's Match type.

Note that while Match appears in the TH AST, DMatch does not appear directly in the th-desugar AST. This is because TH's Match is used in lambda (LamE) and case (CaseE) expressions, but th-desugar does not have counterparts to LamE and CaseE in the DExp data type. Instead, DExp only has a \cases (DLamCasesE) construct, which uses DClause instead of DMatch.

As such, DMatch only plays a "vestigial" role in th-desugar for constructing DLamCasesE values that look like lambda or case expressions. For example, DMatch appears in the type signatures for dLamE and dCaseE, which convert the supplied DMatches to DClauses under the hood.

Constructors

Instances6Eq, Data, Show, Generic, Lift, Rep
datadata DClause
#

Corresponds to TH's Clause type.

Constructors

Instances6Eq, Data, Show, Generic, Lift, Rep
datadata DDec
#

Corresponds to TH's Dec type.

Constructors

Instances7Eq, Data, Show, Generic, Lift, Desugar, …
datadata DDerivClause
#

Corresponds to TH's DerivClause type.

Instances6Eq, Data, Show, Generic, Lift, Rep
datadata DDerivStrategy
#

Corresponds to TH's DerivStrategy type.

Constructors

Instances6Eq, Data, Show, Generic, Lift, Rep
datadata DPatSynDir
#

Corresponds to TH's PatSynDir type

Constructors

Instances6Eq, Data, Show, Generic, Lift, Rep
datadata Overlap
#

Varieties of allowed instance overlap.

Constructors

Instances7Eq, Data, Ord, Show, Generic, Lift, …
datadata PatSynArgs
#

A pattern synonym's argument type.

Constructors

Instances8Eq, Data, Ord, Show, Generic, Ppr, …
datadata DataFlavor
#

Is a data type or data instance declaration a newtype declaration, a data declaration, or a type data declaration?

Constructors

Instances6Eq, Data, Show, Generic, Lift, Rep
datadata DTypeFamilyHead
#
Instances6Eq, Data, Show, Generic, Lift, Rep
datadata DFamilyResultSig
#

Corresponds to TH's FamilyResultSig type

Instances6Eq, Data, Show, Generic, Lift, Rep
datadata InjectivityAnn
#

Injectivity annotation as in an injective type family

Constructors

Instances8Eq, Data, Ord, Show, Generic, Ppr, …
datadata DCon
#

Corresponds to TH's Con type. Unlike Con, all DCons reflect GADT syntax. This is beneficial for th-desugar's since it means that all data type declarations can support explicit return kinds, so one does not need to represent them with something like Maybe DKind, since Haskell98-style data declaration syntax isn't used. Accordingly, there are some differences between DCon and Con to keep in mind:

  • Unlike ForallC, where the meaning of the TyVarBndrs changes depending on whether it's followed by GadtC/RecGadtC or not, the meaning of the DTyVarBndrs in a DCon is always the same: it is the list of universally and existentially quantified type variables. Note that it is not guaranteed that one set of type variables will appear before the other.

  • A DCon always has an explicit return type.

Constructors

Instances6Eq, Data, Show, Generic, Lift, Rep
datadata DConFields
#

A list of fields either for a standard data constructor or a record data constructor.

Instances6Eq, Data, Show, Generic, Lift, Rep
typetype DDeclaredInfix = Bool
#

True if a constructor is declared infix. For normal ADTs, this means that is was written in infix style. For example, both of the constructors below are declared infix.

data Infix = Int Infix Int | Int :*: Int

Whereas neither of these constructors are declared infix:

data Prefix = Prefix Int Int | (:+:) Int Int

For GADTs, detecting whether a constructor is declared infix is a bit trickier, as one cannot write a GADT constructor "infix-style" like one can for normal ADT constructors. GHC considers a GADT constructor to be declared infix if it meets the following three criteria:

  1. Its name uses operator syntax (e.g., (:*:)).

  2. It has exactly two fields (without record syntax).

  3. It has a programmer-specified fixity declaration.

For example, in the following GADT:

infixl 5 :**:, :&&:, :^^:, ActuallyPrefix
data InfixGADT a where
  (:**:) :: Int -> b -> InfixGADT (Maybe b) -- Only this one is infix
  ActuallyPrefix :: Char -> Bool -> InfixGADT Double
  (:&&:) :: { infixGADT1 :: b, infixGADT2 :: Int } -> InfixGADT b :: Int -> Int -> Int -> InfixGADT Int
  (:!!:) :: Char -> Char -> InfixGADT Char

Only the (:**:) constructor is declared infix. The other constructors are not declared infix, because:

  • ActuallyPrefix does not use operator syntax (criterion 1).

  • (:&&:) uses record syntax (criterion 2).

  • (:^^:) does not have exactly two fields (criterion 2).

  • (:!!:) does not have a programmer-specified fixity declaration (criterion 3).

datadata Bang
#

Strictness information in a data constructor's argument.

Constructors

Instances8Eq, Data, Ord, Show, Generic, Ppr, …
datadata SourceUnpackedness
#

SourceUnpackedness corresponds to unpack annotations found in the source code.

This may not agree with the annotations returned by reifyConStrictness. See reifyConStrictness for more information.

Constructors

Instances8Eq, Data, Ord, Show, Generic, Ppr, …
datadata SourceStrictness
#

SourceStrictness corresponds to strictness annotations found in the source code.

This may not agree with the annotations returned by reifyConStrictness. See reifyConStrictness for more information.

Constructors

Instances8Eq, Data, Ord, Show, Generic, Ppr, …
datadata DForeign
#

Corresponds to TH's Foreign type.

Instances6Eq, Data, Show, Generic, Lift, Rep
datadata DPragma
#
Instances6Eq, Data, Show, Generic, Lift, Rep
datadata DRuleBndr
#

Corresponds to TH's RuleBndr type.

Instances6Eq, Data, Show, Generic, Lift, Rep
datadata DTySynEqn
#

Corresponds to TH's TySynEqn type (to store type family equations).

Instances6Eq, Data, Show, Generic, Lift, Rep
datadata DInfo
#

Corresponds to TH's Info type.

Constructors

Instances6Eq, Data, Show, Generic, Lift, Rep
datadata Role
#

Role annotations

Constructors

Instances8Eq, Data, Ord, Show, Generic, Ppr, …
datadata AnnTarget
#

The target of an ANN pragma

Constructors

Instances7Eq, Data, Ord, Show, Generic, Lift, …

The Desugar class

1 declaration
classclass Desugar th ds | ds -> th where
#

This class relates a TH type with its th-desugar type and allows conversions back and forth. The functional dependency goes only one way because we define the following instances on old versions of GHC:

instance Desugar TyVarBndrSpec DTyVarBndrSpec
instance Desugar TyVarBndrUnit DTyVarBndrUnit

Prior to GHC 9.0, TyVarBndrSpec and TyVarBndrUnit are simply type synonyms for TyVarBndr, so making the functional dependencies bidirectional would cause these instances to be rejected.

Methods

Instances6Desugar

Main desugaring functions

17 declarations
valuedsPatOverExp :: DsMonad q => Pat -> DExp -> q (DPat, DExp)
#

Desugar a pattern, along with processing a (desugared) expression that is the entire scope of the variables bound in the pattern.

valuedsPatX :: DsMonad q => Pat -> q (DPat, [(Name, DExp)])
#

Desugar a pattern, returning a list of (Name, DExp) pairs of extra variables that must be bound within the scope of the pattern

valuedsCon
  1. :: DsMonad q
  2. => [DTyVarBndrSpec]

    The universally quantified type variables (used if desugaring a non-GADT constructor).

  3. -> DType

    The original data declaration's type (used if desugaring a non-GADT constructor).

  4. -> Con
  5. -> q [DCon]
#

Desugar a single Con.

Because we always desugar Cons to GADT syntax (see the documentation for DCon), it is not always possible to desugar with just a Con alone. For instance, we must desugar:

data Foo a = forall b. MkFoo b

To this:

data Foo a :: Type where
  MkFoo :: forall a b. b -> Foo a

If our only argument was forall b. MkFoo b, it would be somewhat awkward to figure out (1) what the set of universally quantified type variables ([a]) was, and (2) what the return type (Foo a) was. For this reason, we require passing these as arguments. (If we desugar an actual GADT constructor, these arguments are ignored.)

Secondary desugaring functions

typetype PatM (q :: Type -> Type) = WriterT [(Name, DExp)] q
#

Desugaring a pattern also returns the list of variables bound in as-patterns and the values they should be bound to. This variables must be brought into scope in the "body" of the pattern.

A backwards-compatible type synonym for the thing representing a single derived class in a deriving clause. (This is a DerivClause, Pred, or Name depending on the GHC version.)

valuedsLetDec :: DsMonad q => Dec -> q ([DLetDec], DExp -> DExp)
#

Desugar a single Dec that can appear in a let expression. This produces the following output:

  • One or more DLetDecs (a single Dec can produce multiple DLetDecs in the event of a value declaration that binds multiple things by way of pattern matching.

  • A function of type DExp -> DExp, which should be applied to the expression immediately following the DLetDecs. This function prepends binding forms for any implicit params that were bound in the argument Dec. (If no implicit params are bound, this is simply the id function.)

For instance, if the argument to dsLetDec is the ?x = 42 part of this expression:

let { ?x = 42 } in ?x

Then the output is:

  • let new_x_val = 42
  • \z -> bindIP @"x" new_x_val z

This way, the expression let { new_x_val = 42 } in bindIP @"x" new_x_val (ip @"x") can be formed. The implicit param binders always come after all the other DLetDecs to support parallel assignment of implicit params.

datadata MatchContext
#

The context of a pattern match. This is used to produce Non-exhaustive patterns in... messages that are tailored to specific situations. Compare this to GHC's HsMatchContext data type (https:/gitlab.haskell.orgghcghc-blob81cf52bb301592ff3d043d03eb9a0d547891a3e1compilerLanguageHaskellSyntax/Expr.hs#L1662-1695), from which the MatchContext data type takes inspiration.

Constructors

datadata LamCaseVariant
#

Which kind of lambda case are we dealing with? Compare this to GHC's LamCaseVariant data type (https:/gitlab.haskell.orgghcghc-blob81cf52bb301592ff3d043d03eb9a0d547891a3e1compilerLanguageHaskellSyntax/Expr.hs#L686-690) from which we take inspiration.

Constructors

valuedsMatches
  1. :: DsMonad q
  2. => MatchContext

    The context in which the matches arise

  3. -> [Match]

    Matches of the case or \case expression

  4. -> q [DMatch]
#

Desugar a list of matches for a case or \case expression.

valuedsBody
  1. :: DsMonad q
  2. => Body

    body to desugar

  3. -> [Dec]

    "where" declarations

  4. -> DExp

    what to do if the guards don't match

  5. -> q DExp
#

Desugar a Body

Converting desugared AST back to TH AST

0 declarations

Expanding type synonyms

2 declarations
valueexpand :: (DsMonad q, Data a) => a -> q a
#

Expand all type synonyms and type families in the desugared abstract syntax tree provided, where type family simplification is on a "best effort" basis. Normally, the first parameter should have a type like DExp or DLetDec.

valueexpandType :: DsMonad q => DType -> q DType
#

Expands all type synonyms in a desugared type. Also expands open type family applications. (In GHCs before 7.10, this part does not work if there are any variables.) Attempts to expand closed type family applications, but aborts the moment it spots anything strange, like a nested type family application or type variable.

Reification

1 declaration
valuereifyWithWarning :: (Quasi q, MonadFail q) => Name -> q Info
#

Reify a declaration, warning the user about splices if the reify fails. The warning says that reification can fail if you try to reify a type in the same splice as it is declared.

Local reification

template-haskell reification functions like reify and qReify, as well as th-desugar's reifyWithWarning, only look through declarations that either (1) have already been typechecked in the current module, or (2) are in scope because of imports. We refer to this as global reification. Sometimes, however, you may wish to reify declarations that have been quoted but not yet been typechecked, such as in the following example:

example :: IO ()
example = putStrLn
  $(do decs <- [d| data Foo = MkFoo |]
       info <- reify (mkName "Foo")
       stringE $ pprint info)

Because Foo only exists in a TH quote, it is not available globally. As a result, the call to reify (mkName "Foo") will fail.

To make this sort of example possible, th-desugar extends global reification with local reification. A function that performs local reification (such as dsReify, reifyWithLocals, or similar functions that have a DsMonad context) looks through both typechecked (or imported) declarations and quoted declarations that are currently in scope. One can add quoted declarations in the current scope by using the withLocalDeclarations function. Here is an example of how to repair the example above using withLocalDeclarations:

example2 :: IO ()
example2 = putStrLn
  $(do decs <- [d| data Foo = MkFoo |]
       info <- withLocalDeclarations decs $
                 reifyWithLocals (mkName "Foo")
       stringE $ pprint info)

Note that withLocalDeclarations should only be used to add quoted declarations with names that are not duplicates of existing global or local declarations. Adding duplicate declarations through withLocalDeclarations is undefined behavior and should be avoided. This is unlikely to happen if you are only using withLocalDeclarations in conjunction with TH quotes, however. For instance, this is not an example of duplicate declarations:

data T = MkT1

$(do decs <- [d| data T = MkT2 |]
     info <- withLocalDeclarations decs ...
     ...)

The quoted data T = MkT2 does not conflict with the top-level data T = Mk1 since declaring a data type within TH quotes gives it a fresh, unique name that distinguishes it from any other data types already in scope.

valuereifyWithLocals_maybe :: DsMonad q => Name -> q (Maybe Info)
#

Like reify from Template Haskell, but looks also in any not-yet-typechecked declarations. To establish this list of not-yet-typechecked declarations, use withLocalDeclarations. Returns Nothing if reification fails. Note that no inferred type information is available from local declarations; bottoms may be used if necessary.

valuemkDataNameWithLocals :: DsMonad q => String -> q Name
#

Like TH's lookupValueName, but if this name is not bound, then we assume it is declared in the current module.

Unlike mkDataName, this also consults the local declarations in scope when determining if the name is currently bound.

valuemkTypeNameWithLocals :: DsMonad q => String -> q Name
#

Like TH's lookupTypeName, but if this name is not bound, then we assume it is declared in the current module.

Unlike mkTypeName, this also consults the local declarations in scope when determining if the name is currently bound.

valuereifyNameSpace :: DsMonad q => Name -> q (Maybe NameSpace)
#

Determines a Name's NameSpace. If the NameSpace is attached to the Name itself (i.e., it is unambiguous), then that NameSpace is immediately returned. Otherwise, reification is used to lookup up the NameSpace (consulting local declarations if necessary).

Note that if a Name lives in two different NameSpaces (which can genuinely happen--for instance, mkName "==", where == is both a function and a type family), then this function will simply return whichever NameSpace is discovered first via reification. If you wish to find a Name in a particular NameSpace, use the lookupValueNameWithLocals or lookupTypeNameWithLocals functions.

classclass (Quasi m, MonadFail m) => DsMonad (m :: Type -> Type) where
#

A DsMonad stores some list of declarations that should be considered in scope. DsM is the prototypical inhabitant of DsMonad.

Methods

Instances7DsMonad, …
newtypenewtype DsM (q :: Type -> Type) a
#

A convenient implementation of the DsMonad class. Use by calling withLocalDeclarations.

Instances9MonadTrans, Monad, Functor, MonadFail, Applicative, Quote, …
  • MonadTrans DsMDefined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Reify
  • Monad q => Monad (DsM q)Defined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Reify
  • Functor q => Functor (DsM q)Defined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Reify
  • MonadFail q => MonadFail (DsM q)Defined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Reify
  • Applicative q => Applicative (DsM q)Defined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Reify
  • Quote q => Quote (DsM q)Defined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Reify
  • Quasi q => Quasi (DsM q)Defined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Reify
  • MonadIO q => MonadIO (DsM q)Defined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Reify
  • (Quasi q, MonadFail q) => DsMonad (DsM q)Defined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Reify

Nested pattern flattening

2 declarations
valuescExp :: DsMonad q => DExp -> q DExp
#

Remove all nested pattern-matches within this expression. This also removes all DTildePas and DBangPas. After this is run, every pattern is guaranteed to be either a DConPa with bare variables as arguments, a DLitPa, or a DWildPa.

Capture-avoiding substitution and utilities

0 declarations

Free variable calculation

2 declarations

Extract the term variables bound by a DPat.

This does not extract any type variables bound by pattern signatures, constructor patterns, or type patterns.

Utility functions

44 declarations
valueflattenDValD :: Quasi q => DLetDec -> q [DLetDec]
#

If the declaration passed in is a DValD, creates new, equivalent declarations such that the DPat in all DValDs is just a plain DVarPa. Other declarations are passed through unchanged. Note that the declarations that come out of this function are rather less efficient than those that come in: they have many more pattern matches.

valuegetRecordSelectors :: DsMonad q => [DCon] -> q [DLetDec]
#

Produces DLetDecs representing the record selector functions from the provided DCons.

Note that if the same record selector appears in multiple constructors, getRecordSelectors will return only one binding for that selector. For example, if you had:

data X = X1 {y :: Symbol} | X2 {y :: Symbol}

Then calling getRecordSelectors on [X1, X2] will return:

[ DSigD y (DAppT (DAppT DArrowT (DConT X)) (DConT Symbol))
, DFunD y [ DClause [DConP X1 [DVarP field]] (DVarE field)
          , DClause [DConP X2 [DVarP field]] (DVarE field) ] ]

instead of returning one binding for X1 and another binding for X2.

getRecordSelectors does not attempt to filter out "naughty" record selectors—that is, records whose field types mention existentially quantified type variables that do not appear in the constructor's return type. Here is an example of a naughty record selector:

data Some :: (Type -> Type) -> Type where
  MkSome :: { getSome :: f a } -> Some f

GHC itself will not allow the use of getSome as a top-level function due to its type f a mentioning the existential variable a, but getRecordSelectors will return it nonetheless. Ultimately, this design choice is a practical one, as detecting which type variables are existential in Template Haskell is difficult in the general case.

valuemkTypeName :: Quasi q => String -> q Name
#

Like TH's lookupTypeName, but if this name is not bound, then we assume it is declared in the current module.

valuemkDataName :: Quasi q => String -> q Name
#

Like TH's lookupDataName, but if this name is not bound, then we assume it is declared in the current module.

valuenewUniqueName :: Quasi q => String -> q Name
#

Like newName, but even more unique (unique across different splices), and with unique nameBases. Precondition: the string is a valid Haskell alphanumeric identifier (could be upper- or lower-case).

valuemaybeDCasesE :: MatchContext -> [DExp] -> [DClause] -> DExp
#

If the list of clauses is non-empty, make a \cases expression and apply it using the expressions as arguments. Otherwise, make an error statement.

Precondition: if the list of DClauses is non-empty, then the number of patterns in each DClause must be equal to the number of DExp arguments.

valuedCaseE :: DExp -> [DMatch] -> DExp
#

Construct a DExp value that is equivalent to writing a case expression. Under the hood, this uses \cases (DLamCasesE). For instance, given this code:

case scrut of
  pat_1 -> rhs_1
  ...
  pat_n -> rhs_n

The following \cases expression will be created under the hood:

(\cases
  pat_1 -> rhs_1
  ...
  pat_n -> rhs_n) scrut
valuedCasesE :: [DExp] -> [DClause] -> DExp
#

Construct a DExp value that is equivalent to writing a case expression that scrutinizes multiple values at once. Under the hood, this uses \cases (DLamCasesE). For instance, given this code:

case (scrut_1, ..., scrut_n) of
  (pat_1_1, ..., pat_1_n) -> rhs_1
  ...
  (pat_m_1, ..., pat_m_n) -> rhs_n

The following \cases expression will be created under the hood:

(\cases
  pat_1_1 ... pat_1_n -> rhs_1
  ...
  pat_m_1 ... pat_m_n -> rhs_n) scrut_1 ... scrut_n

In other words, this creates a DLamCasesE value and then applies it to argument values.

Preconditions:

  • If the list of DClauses is non-empty, then the number of patterns in each DClause must be equal to the number of DExp arguments.

  • If the list of DClauses is empty, then there must be exactly one DExp argument.

valuedLamE :: [DPat] -> DExp -> DExp
#

Construct a DExp value that is equivalent to writing a lambda expression. Under the hood, this uses \cases (DLamCasesE). For instance, given this code:

\var_1 ... var_n -> rhs

The following \cases expression will be created under the hood:

\cases var_1 ... var_n -> rhs
valuedLamCaseE :: [DMatch] -> DExp
#

Construct a DExp value that is equivalent to writing a \case expression. Under the hood, this uses \cases (DLamCasesE). For instance, given this code:

\case
  pat_1 -> rhs_1
  ...
  pat_n -> rhs_n

The following \cases expression will be created under the hood:

\cases
  pat_1 -> rhs_1
  ...
  pat_n -> rhs_n

Extract the degree of a tuple Name.

In addition to recognizing tuple syntax (e.g., ''(,,)), this also recognizes the following:

  • ''Unit (for 0-tuples)

  • ''Solo/'MkSolo (for 1-tuples)

  • ''TupleN (for N-tuples)

In recent versions of GHC, ''() is a synonym for ''Unit, ''(,) is a synonym for ''Tuple2, and so on. As a result, we must check for ''Unit and ''TupleN in tupleDegree_maybe to be thorough. (There is no special tuple syntax for ''Solo/'MkSolo, but we check them here as well for the sake of completeness.)

Extract the degree of an unboxed sum Name.

In addition to recognizing unboxed sum syntax (e.g., ''()), this also recognizes ''SumN# (for unboxed N-ary sum type constructors). In recent versions of GHC, ''Sum2# is a synonym for ''(), ''Sum3# is a synonym for ''(), and so on. As a result, we must check for ''SumN# in unboxedSumNameDegree_maybe to be thorough.

Extract the degree of an unboxed tuple Name.

In addition to recognizing unboxed tuple syntax (e.g., ''()), this also recognizes the following:

  • ''Unit# (for unboxed 0-tuples)

  • ''Solo#/'Solo# (for unboxed 1-tuples)

  • ''TupleN# (for unboxed N-tuples)

In recent versions of GHC, ''(##) is a synonym for ''Unit#, ''() is a synonym for ''Tuple2#, and so on. As a result, we must check for ''Unit#, and ''TupleN in unboxedTupleNameDegree_maybe to be thorough. (There is no special unboxed tuple type constructor for ''Solo#/'Solo#, but we check them here as well for the sake of completeness.)

valuebindIP :: a -> (IP name a => r) -> r
#

Get an implicit param constraint (IP name a, which is the desugared form of (?name :: a)) from an explicit value.

This function is only available with GHC 8.0 or later.

Create new kind variable binder names corresponding to the return kind of a data type. This is useful when you have a data type like:

data Foo :: forall k. k -> Type -> Type where ...

But you want to be able to refer to the type Foo a b. mkExtraDKindBinders will take the kind forall k. k -> Type -> Type, discover that is has two visible argument kinds, and return as a result two new kind variable binders [a :: k, b :: Type], where a and b are fresh type variable names.

This expands kind synonyms if necessary.

Take a list of DTypes, find their free variables, and sort them in reverse topological order to ensure that they are well scoped. In other words, the free variables are ordered such that:

  1. Whenever an explicit kind signature of the form (A :: K) is encountered, the free variables of K will always appear to the left of the free variables of A in the returned result.

  2. The constraint in (1) notwithstanding, free variables will appear in left-to-right order of their original appearance.

On older GHCs, this takes measures to avoid returning explicitly bound kind variables, which was not possible before TypeInType.

Take a telescope of DTyVarBndrs, find the free variables in their kinds, and sort them in reverse topological order to ensure that they are well scoped. Because the argument list is assumed to be telescoping, kind variables that are bound earlier in the list are not returned. For example, this:

toposortKindVarsOfTvbs [a :: k, b :: Proxy a]

Will return [k], not [k, a], since a is bound earlier by a :: k.

datadata ForAllTyFlag
#

Constructors

Instances9Eq, Data, Ord, Show, Generic, PprFlag, …

Convert a list of TyVarBndr ForAllTyFlags to a list of TyVarBndrSpecs, which is suitable for use in an invisible forall. Specifically:

  • Variable binders that use Invisible spec are converted to spec.

  • Variable binders that are Required are converted to SpecifiedSpec, as all of the TyVarBndrSpecs are invisible. As an example of how this is used, consider what would happen when singling this data type:

  type T :: forall k -> k -> Type
  data T k (a :: k) where ...
  

Here, the k binder is Required. When we produce the standalone kind signature for the singled data type, we use tvbForAllTyFlagsToSpecs to produce the type variable binders in the outermost forall:

  type ST :: forall k (a :: k). T k a -> Type
  data ST z where ...
  

Note that the k is bound visibily (i.e., using SpecifiedSpec) in the outermost, invisible forall.

Convert a list of TyVarBndr ForAllTyFlags to a list of TyVarBndrVises, which is suitable for use in a type-level declaration (e.g., the var_1 ... var_n in class C var_1 ... var_n). Specifically:

Convert a list of DTyVarBndr ForAllTyFlags to a list of DTyVarBndrSpecs, which is suitable for use in an invisible forall. Specifically:

  • Variable binders that use Invisible spec are converted to spec.

  • Variable binders that are Required are converted to SpecifiedSpec, as all of the DTyVarBndrSpecs are invisible. As an example of how this is used, consider what would happen when singling this data type:

  type T :: forall k -> k -> Type
  data T k (a :: k) where ...
  

Here, the k binder is Required. When we produce the standalone kind signature for the singled data type, we use dtvbForAllTyFlagsToSpecs to produce the type variable binders in the outermost forall:

  type ST :: forall k (a :: k). T k a -> Type
  data ST z where ...
  

Note that the k is bound visibily (i.e., using SpecifiedSpec) in the outermost, invisible forall.

Convert a list of DTyVarBndr ForAllTyFlags to a list of DTyVarBndrVises, which is suitable for use in a type-level declaration (e.g., the var_1 ... var_n in class C var_1 ... var_n). Specifically:

FunArgs and VisFunArg

datadata FunArgs
#

The list of arguments in a function Type.

Constructors

Instances3Eq, Data, Show
  • Eq FunArgsDefined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Util
  • Data FunArgsDefined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Util
  • Show FunArgsDefined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Util
datadata ForallTelescope
#

The type variable binders in a forall. This is not used by the TH AST itself, but this is used as an intermediate data type in FAForalls.

Constructors

Instances3Eq, Data, Show
datadata VisFunArg
#

A visible function argument type (i.e., one that must be supplied explicitly in the source code). This is in contrast to invisible arguments (e.g., the c in c => r), which are instantiated without the need for explicit user input.

Constructors

Instances3Eq, Data, Show
  • Eq VisFunArgDefined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Util
  • Data VisFunArgDefined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Util
  • Show VisFunArgDefined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Util

DFunArgs and DVisFunArg

datadata DFunArgs
#

The list of arguments in a function DType.

Constructors

Instances5Eq, Data, Show, Generic, Rep
datadata DVisFunArg
#

A visible function argument type (i.e., one that must be supplied explicitly in the source code). This is in contrast to invisible arguments (e.g., the c in c => r), which are instantiated without the need for explicit user input.

Constructors

Instances5Eq, Data, Show, Generic, Rep

TypeArg

datadata TypeArg
#

An argument to a type, either a normal type (TANormal) or a visible kind application (TyArg).

TypeArg is useful when decomposing an application of a Type to its arguments (e.g., in unfoldType).

Constructors

Instances4Eq, Data, Show, Desugar
  • Eq TypeArgDefined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Util
  • Data TypeArgDefined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Util
  • Show TypeArgDefined in th-desugar-1.19 · Language.Haskell.TH.Desugar.Util
  • Desugar TypeArg DTypeArgDefined in th-desugar-1.19 · Language.Haskell.TH.Desugar
valueunfoldType :: Type -> (Type, [TypeArg])
#

Decompose an applied type into its individual components. For example, this:

Proxy @Type Char

would be unfolded to this:

(ConT ''Proxy, [TyArg (ConT ''Type), TANormal (ConT ''Char)])

This process forgets about infix application, so both of these types:

Int :++: Int
(:++:) Int Int

will be unfolded to this:

(ConT ''(:+:), [TANormal (ConT ''Int), TANormal (ConT ''Int)])

This function should only be used after all UInfixT and PromotedUInfixT types have been resolved (e.g., via th-abstraction's resolveInfixT function).

DTypeArg

datadata DTypeArg
#

An argument to a type, either a normal type (DTANormal) or a visible kind application (DTyArg).

DTypeArg does not appear directly in the th-desugar AST, but it is useful when decomposing an application of a DType to its arguments.

Instances6Eq, Data, Show, Generic, Desugar, Rep

Extracting bound names

Extract the names bound in a Stmt.

This does not extract any type variables bound by pattern signatures, constructor patterns, or type patterns.

Extract the names bound in a Dec that could appear in a let expression.

This does not extract any type variables bound by pattern signatures, constructor patterns, or type patterns.

Extract the names bound in a Pat.

This does not extract any type variables bound by pattern signatures, constructor patterns, or type patterns.