GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2024-03-27T15:40:22Zhttps://gitlab.haskell.org/ghc/ghc/-/issues/23536Making template-haskell refactorable2024-03-27T15:40:22ZAdam GundryMaking template-haskell refactorable### Background
The `template-haskell` package is a wired-in package that contains some known-key names. These are identifiers and data constructors that the compiler expects to be in specific locations in the `template-haskell` package ...### Background
The `template-haskell` package is a wired-in package that contains some known-key names. These are identifiers and data constructors that the compiler expects to be in specific locations in the `template-haskell` package when it desugars things like quotes or derived `Lift` instances. (Or indeed for recognizing the `Lift` type class as one that has bespoke deriving logic at all!)
At the moment, the `ghc` package and some of its dependencies (`bytestring`, `containers`, `exceptions`, `filepath` and `text`) depend on the `template-haskell` package. More specifically the compiler itself `ghc` depends on _its own in-tree version_ of `template-haskell`, while boot libraries like `bytestring` contain derived `Lift` instances and quotes.
### Problem
Now consider what happens when we build a stage-1 ghc, with some bootstrap version of ghc:
1. We must build the _in-tree_ version of `template-haskell` (with the boot compiler) because the `ghc` package being build depends on that in-tree version.
2. We compile a derived `Lift` instance in one of the boot libraries like `bytestring`, the bootstrap compiler will only accept the derived instance if the class itself lives at the specific wired-in location `template-haskell:Language.Haskell.TH.Syntax.Lift`. Furthermore, the body of the derived instance will refer to various known-key names in `template-haskell:Language.Haskell.TH.Lib.Internal` and elsewhere.
This makes it difficult to make changes to `Language.Haskell.TH.Syntax`, which defines many wired-in names used by TH: If we move or change one, in step 2 the boot compiler will still try to look it up at its old location and use it as if it had its old type. See for example #20828 and #22229 which have run into this issue.
### Possible solutions
1. One possible fix would be to make it possible to compile these packages without depending on `template-haskell` (e.g. using a Cabal flag and CPP). Then we could build stage-1 GHC without the boot compiler ever touching any `template-haskell` package at all, and hence it would be possible to move definitions around. The stage-2 GHC build would then depend on `template-haskell` as normal.
* This would require changes to several boot libraries, and although their dependencies on `template-haskell` are fairly trivial, the relevant maintainers may not all be happy about expanding the configuration spaces for these packages to accommodate this approach.
2. Another possibility is to build a stage-1 `ghc` against the version of `template-haskell` shipped with the bootstrap compiler instead of the in-tree `template-haskell`. Then in step 2 above, the lookups by the bootstrap compiler will succeed because the bootstrap compiler performs these lookup based on where things are in its own version of `template-haskell`.
* This means that the compiler must be buildable with multiple versions of `template-haskell`, most likely through some awkward CPP.
3. A third possibility is to build the various boot libraries for the stage-1 `ghc` against the `template-haskell` shipped with the bootstrap compiler, but make the stage-1 `ghc` itself directly depend on another package that provides the same API as the in-tree version of `template-haskell`. This package's implementation could consist of a `.cabal` file and a hadrian-created symlink into the in-tree `template-haskell`'s sources.
* This introduces a bit of complexity into hadrian, but requires no CPP anywhere.
Any of these would make it easier to refactor `Language.Haskell.TH.Syntax`, which is currently rather unwieldy and could do with API cleanup.https://gitlab.haskell.org/ghc/ghc/-/issues/22069Tracking ticket for using TemplateHaskell in GHC bootstrapping2024-03-27T15:02:20ZBen GamariTracking ticket for using TemplateHaskell in GHC bootstrappingCurrently GHC has a policy of avoiding use of TH in its bootstrapping process. However, we suspect that on-going work in cross-compilation should address many of the technical barriers to using it. Moreover, TH can be a compelling altern...Currently GHC has a policy of avoiding use of TH in its bootstrapping process. However, we suspect that on-going work in cross-compilation should address many of the technical barriers to using it. Moreover, TH can be a compelling alternative to `Generic` instance deriving in many cases. @mpickering and I have discussed options for achieving this, including possibly running splices on the host.https://gitlab.haskell.org/ghc/ghc/-/issues/24021Making Template Haskell (more) stable across GHC releases2024-03-27T14:08:44ZAdam GundryMaking Template Haskell (more) stable across GHC releasesSee also
* [This thread on ghc-devs](https://mail.haskell.org/pipermail/ghc-devs/2024-March/021569.html)
## The problem
The AST for Template Haskell, in the `template-haskell` library, in Langauge.Haskell.TH.Syntax, is tightly coupled ...See also
* [This thread on ghc-devs](https://mail.haskell.org/pipermail/ghc-devs/2024-March/021569.html)
## The problem
The AST for Template Haskell, in the `template-haskell` library, in Langauge.Haskell.TH.Syntax, is tightly coupled to GHC.
When GHC gets a syntactic extension, it is not long before the TH AST needs it too. The problem is that as a result:
* The `template-haskell` library needs a major bump with every GHC release.
* Using `--allow-newer` may allow some TH clients to squeeze by, but others will break because they pattern-match on the TH AST, and
now have missing constructors, or constructors with the wrong fields.
As a result, churn in the TH AST is a major reason that it is hard to compile old programs unchanged with a new GHC.
## A possible approach
One approach that has often been discussed is to **define an API for Template Haskell that is pretty stable across GHC releases, and yet is enough for most clients**. Example of earlier discussion:
* !11200 (comment 524484)
* #20828
The idea is to have two distinct packages:
* One internal package `th-internal`, closely coupled to GHC,
supporting exactly and only the AST provided by that GHC
version. This is essentially what we have at the moment, but we
suggest renaming it to stress its instability. Users would be
discouraged from depending on it directly (much like ghc-internal).
* One user-facing package `template-haskell`, defining a stable external API for Template Haskell with a (fairly) stable API, much like `base`.
Crucially, the user-facing package would be a normal, reinstallable Hackage package, so its version would not necessarily be tied to the GHC version. As a normal package it would be easier to refactor and clean up the API over time without running into issues like #23536.
## The million dollar question
The million dollar question is, of course: can we design an API that is
* Sufficient for most TH clients.
* Able to be implemented on top of a succession of `th-internal` ASTs, as they evolve.
This is a design challenge, and we would need someone to lead the process of designing it.
It is worth classifying how clients use TH:
* **TH quotations and quasi-quotes** are not vulnerable to changes in the Template Haskell data type. Clients who use only quotations and splices need
not even import the `template-haskell` libarary.
* Programs that **construct syntax trees** can do so using the little smart-contructor functions (e.g. `varE`). These smart constructors can readily form part of the stable API.
* Some TH clients, notably various forms of `deriving`, use **reification** to interrogate the program, and reification currently returns the TH AST; see "Reification" below.
Claim: these three use-cases satisfy most clients. If we could satisfy them with a stable API, that would represent a major step forwards.
## Reification
Template Haskell offers
```
reify :: Name -> Q Info
reifyType :: Name -> Q Type
data Info
= ClassI Dec [InstanceDec]
| ClassOpI Name Type ParentName
| TyConI Dec
| FamilyI Dec [InstanceDec]
| PrimTyConI Name Arity Unlifted
| DataConI Name Type ParentName
| PatSynI Name PatSynType
| VarI Name Type (Maybe Dec)
| TyVarI Name Type
```
The data type `Info` is used exclusively for reification. But (crucially) `Type`, `Dec` etc *are simply the TH AST data types*.
That seems logical but it isn't. For example, the TH type `Type` looks like
```
data Type
= ParensT Type
| InfixT Type Name Type -- Infix
| UInfixT Type Name Type -- "Unresolved infix"
| ....
```
The idea is that `Type` can faithfully represent the rich concrete syntax of Haskell types.
*But that is not necessary for reification*. Indeed, it gets in the way. The `deriving` code just wants to know "is this type a type application, and if so, with what argments?". It's a pain having to deal with the plethora of concrete syntax.
So it would be entirely possible for reify to present an API that was entirely decoupled from the TH AST, just as `Info` is.
The exact design isn't clear (A new data type? A collection of view functions?) but the design space opens up once it is
decoupled from the TH AST itself.
## Other (somewhat diconnected) thoughts
* With enough (no doubt ghastly) CPP hackery, we could potentially arrange for each version to be compatible with the "internal AST" used by a range of GHC versions. I imagine this would be hard to do over many releases, but even being able to support 2-3 versions simultaneously would signific
antly help ease migration.
* Ideally we would release new minor versions of past major series of the library when a new GHC is released, allowing (partial) forward compatibility with future releases. That raises the question of how to deal with constructors in the "future AST" that aren't supported by the GHC version being used for compilation, but at least they will never show up in quotes, and perhaps simply failing at splice time is acceptable.
An advantage of this over version-numbered data constructors (as suggested in !11200 (comment 525994)) would be that each package version presented a single consistent view of the AST (rather than accumulating pattern synonyms in a single package). I imagine it might be harder to maintain, though.
* An interesting possibility suggested by @bgamari on #20828 would be to have distinct modules in the package that define exactly the AST of a particular language version (e.g. Haskell2010 or GHC2021). That could potentially be maintained over a longer period. It runs into the issue that new language extensions might introduce syntax that is not representable, but still might be useful in some cases. (Again, there's a question of whether to provide pattern synonym views of the existing AST types, or specialised datatypes plus conversion functions that check whether e.g. some quoted syntax is representable in GHC2021 syntax.)https://gitlab.haskell.org/ghc/ghc/-/issues/24572RequiredTypeArguments: application of infix type fails when combined with Tem...2024-03-26T15:29:03ZRyan ScottRequiredTypeArguments: application of infix type fails when combined with TemplateHaskellI am using the `master` branch of GHC on commit da2a10ceab7498fbbd5723dee0393ce75f2bb562. That includes a fix for https://gitlab.haskell.org/ghc/ghc/-/issues/24570, so this program now typechecks:
```hs
{-# LANGUAGE GHC2024 #-}
{-# LANG...I am using the `master` branch of GHC on commit da2a10ceab7498fbbd5723dee0393ce75f2bb562. That includes a fix for https://gitlab.haskell.org/ghc/ghc/-/issues/24570, so this program now typechecks:
```hs
{-# LANGUAGE GHC2024 #-}
{-# LANGUAGE RequiredTypeArguments #-}
{-# LANGUAGE TemplateHaskell #-}
module Foo where
import Language.Haskell.TH
idee :: forall a -> a -> a
idee _ x = x
type (!@#) = Bool
f :: Bool -> Bool
f = idee (!@#)
```
Surprisingly, however, this variation of `f` does not typecheck:
```hs
g :: Bool -> Bool
g = $([| idee (!@#) |])
```
```
~/Software/ghc/_build/stage1/bin/ghc Foo.hs
[1 of 1] Compiling Foo ( Foo.hs, Foo.o )
Foo.hs:17:6: error: [GHC-55017]
• Illegal data constructor name: ‘!@#’
When splicing a TH expression: Foo.idee (Foo.!@#)
• In the untyped splice: $([| idee (!@#) |])
|
17 | g = $([| idee (!@#) |])
| ^^^^^^^^^^^^^^^^^^
```
Why is GHC complaining about a data constructor name when `(!@#)` is a type name? If you compile this program with `-ddump-simpl`, you'll see:
```
$ ~/Software/ghc/_build/stage1/bin/ghc Foo.hs -ddump-simpl
[1 of 1] Compiling Foo ( Foo.hs, Foo.o )
==================== Simplified expression ====================
Language.Haskell.TH.Lib.Internal.appE
@Language.Haskell.TH.Syntax.Q
Language.Haskell.TH.Syntax.$fQuoteQ
(Language.Haskell.TH.Lib.Internal.varE
@Language.Haskell.TH.Syntax.Q
Language.Haskell.TH.Syntax.$fQuoteQ
(Language.Haskell.TH.Syntax.mkNameG_v
(GHC.CString.unpackCString# "main"#)
(GHC.CString.unpackCString# "Foo"#)
(GHC.CString.unpackCString# "idee"#)))
(Language.Haskell.TH.Lib.Internal.conE
@Language.Haskell.TH.Syntax.Q
Language.Haskell.TH.Syntax.$fQuoteQ
(Language.Haskell.TH.Syntax.mkNameG_tc
(GHC.CString.unpackCString# "main"#)
(GHC.CString.unpackCString# "Foo"#)
(GHC.CString.unpackCString# "!@#"#)))
```
Which reveals that GHC is desugaring `g` to something like this:
```hs
g :: Bool -> Bool
g = $(varE 'idee `appE` conE ''(!@#))
```
I believe `conE` is the culprit here. If you look into how `conE` is desugared, you'll find that it calls [`cName`](https://gitlab.haskell.org/ghc/ghc/-/blob/da2a10ceab7498fbbd5723dee0393ce75f2bb562/compiler/GHC/ThToHs.hs#L2101):
```hs
cName n = cvtName OccName.dataName n
```
Where [`cvtName`](https://gitlab.haskell.org/ghc/ghc/-/blob/da2a10ceab7498fbbd5723dee0393ce75f2bb562/compiler/GHC/ThToHs.hs#L2127-2136) is defined as:
```hs
cvtName :: OccName.NameSpace -> TH.Name -> CvtM RdrName
cvtName ctxt_ns (TH.Name occ flavour)
| not (okOcc ctxt_ns occ_str) = failWith (IllegalOccName ctxt_ns occ_str)
| otherwise
= do { loc <- getL
; let rdr_name = thRdrName loc ctxt_ns occ_str flavour
; force rdr_name
; return rdr_name }
where
occ_str = TH.occString occ
```
Note the `not (okOcc ctxt_ns occ_str)` check. When calling `cName`, `ctxt_ns` is `dataName`, so this check will only succeed if the supplied `Name` is a valid data constructor. `''(!@#)` isn't a valid data constructor `Name`, so it fails this check.
-----
Two possible ways of fixing this include:
1. Relaxing this check. (I'm not sure what the consequences of this would be.)
2. Change the way `RequiredTypeArguments` applications are desugared so that `[| idee (!@#) |]` is desugared to ``varE 'idee `appE` typeE (conT ''(!@#))`` instead. This would have the downside that `[| idee (!@#) |]` would be indistinguishable from `[| idee (type (!@#$)) |]` after desugaring, however.https://gitlab.haskell.org/ghc/ghc/-/issues/23647Usage of Template Haskell quotes in GHC source tree vs. usage of GHC as a lib...2024-03-25T20:31:01ZGergő ÉrdiUsage of Template Haskell quotes in GHC source tree vs. usage of GHC as a libraryA recent commit 983ce55815f2dd57f84ee86eee97febf7d80b470 starts using
`TemplateHaskellQuotes` in the GHC codebase. It seems this is at odds
with using GHC as a library, a la `ghc-lib`.
The `ghc-lib` approach is to basically take the mo...A recent commit 983ce55815f2dd57f84ee86eee97febf7d80b470 starts using
`TemplateHaskellQuotes` in the GHC codebase. It seems this is at odds
with using GHC as a library, a la `ghc-lib`.
The `ghc-lib` approach is to basically take the module hierarchy from
the `compiler/` subtree, and compile it as a completely vanilla
Haskell library, with no direct attachment to the host GHC
version. This enables using e.g. GHC 9.4 to compile a program using
the GHC 9.6 API, and so on. In particular, it also makes it very easy
to apply patches to the version of GHC used as a library, since in
this setup it doesn't need to be able to bootstrap.
So what is the problem with using `TemplateHaskellQuotes`? The problem
is the dependency on the `template-haskell` package. When a module
inside GHC-as-a-library containing TH quotes is compiled, the quotes
are translated into applications of the constructors defined by the
*host* GHC's TH package. But because GHC is tightly coupled to the TH
support library, GHC-as-a-library needs to ship with its own internal
version of the library. So the code that tries to process the results
of these quotes is using the *target* GHC's TH definitions. And that
leads to a conflict: code like
```
leftName :: Namel
leftName = 'Left
```
is now a type mismatch between the type of `'Left` being
`template-haskell-2.19.0.0:Language.Haskell.TH.Syntax.Name` (example
when using GHC 9.4.5 as the host) and the type of `leftName` being
`ghc-lib-9.9.20230712:Language.Haskell.TH.Syntax.Name` (example when
the target version is built from recent `master`).
Currently, `ghc-lib-gen` has a pre-processing step on the GHC source
tree that replaces these quotations with applications containing
direct references to the target TH constructors:
https://github.com/digital-asset/ghc-lib/blob/ab01fb2b4d1e3a9338390e9c10ccd769bbf37aeb/ghc-lib-gen/src/Ghclibgen.hs#L419-L467
but I am worried that this is very fragile.
So any ideas on how to tackle this situation better?Matthew PickeringMatthew Pickeringhttps://gitlab.haskell.org/ghc/ghc/-/issues/24559Lambda with invisible type pattern fails to splice with TemplateHaskell2024-03-25T19:13:15ZRyan ScottLambda with invisible type pattern fails to splice with TemplateHaskellI am using GHC 9.10.1-alpha1, which introduces `@`-binders in more places in pattern contexts (https://gitlab.haskell.org/ghc/ghc/-/merge_requests/11109). Here is an example of an expression one can write with this feature:
```hs
{-# LA...I am using GHC 9.10.1-alpha1, which introduces `@`-binders in more places in pattern contexts (https://gitlab.haskell.org/ghc/ghc/-/merge_requests/11109). Here is an example of an expression one can write with this feature:
```hs
{-# LANGUAGE GHC2024 #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeAbstractions #-}
module Foo where
import Data.Kind
import Data.Proxy
f :: (forall (a :: Type). Proxy a) -> Proxy Bool
f k = k @Bool
g1 :: Proxy Bool
g1 = f (\ @a -> Proxy @a)
```
So far, so good. Now let's introduce a variant of `g1` where the expression is spliced in via `TemplateHaskell`:
```hs
g2 :: Proxy Bool
g2 = f $([| \ @a -> Proxy @a |])
```
I would expect this to typecheck just like `g1` does. And yet, it doesn't:
```
$ ghc-9.10 Foo.hs
[1 of 1] Compiling Foo ( Foo.hs, Foo.o )
Foo.hs:16:9: error: [GHC-14964]
• Invisible type pattern a has no associated forall
• In the first argument of ‘f’, namely ‘(\ @a -> Proxy @a)’
In the expression: f (\ @a -> Proxy @a)
In an equation for ‘g2’: g2 = f (\ @a -> Proxy @a)
|
16 | g2 = f $([| \ @a -> Proxy @a |])
| ^^^^^^^^^^^^^^^^^^^^^^^^
```9.10.1Simon Peyton JonesSimon Peyton Joneshttps://gitlab.haskell.org/ghc/ghc/-/issues/24537template-haskell's RecordWildCards support2024-03-25T11:11:54ZLiam Goodacretemplate-haskell's RecordWildCards support## Summary
RecordWildCards syntax `Con {..}` doesn't appear to be represented in template-haskell.
Suppose we have a data type:
```hs
data G = H { field0 :: Int, field1 :: String }
deriving stock Show
```
Using `[e|H {..}|]` yields...## Summary
RecordWildCards syntax `Con {..}` doesn't appear to be represented in template-haskell.
Suppose we have a data type:
```hs
data G = H { field0 :: Int, field1 :: String }
deriving stock Show
```
Using `[e|H {..}|]` yields `RecConE Main.H []`.
But this is indistinguishable from `[e|H {}|]`.
However, using `H {}` in place of `H {..}` won't compile if `H` has fields.
## Expected behavior
Have `RecConE` support wildcards.
### (Solutionising)
Perhaps something like:
```hs
data RecWild = NoRecWildCard | RecWildCard
data Exp ...
| RecConE Name [FieldExp] RecWild
data Pat ...
| RecP Name [FieldPat] RecWild
```
Supporting both `H {..}` and `H {field1=42, ..}`.
Maybe `.Lib` could keep its existing `recConE` & `recP` but add `recConWildE` & `recWildP`? (if that's desirable)
```
recConE :: Quote m => Name -> [m (Name, Exp)] -> m Exp
recConE c fs = do { flds <- sequenceA fs; pure (RecConE c flds NoRecWildCard) }
recConWildE :: Quote m => Name -> [m (Name, Exp)] -> m Exp
recConWildE c fs = do { flds <- sequenceA fs; pure (RecConE c flds RecWildCard) }
```
## Environment
* GHC version used: 9.8.2 and below.https://gitlab.haskell.org/ghc/ghc/-/issues/24299`tc_infer_hs_type` doesn't add module finalisers2024-03-21T11:53:38ZAndrei Borzenkov`tc_infer_hs_type` doesn't add module finalisers## Summary
I investigated https://gitlab.haskell.org/ghc/ghc/-/issues/23639 and found that `tc_hs_type` calls `addModFinalizersWithLclEnv` on untyped top-level splices, but `tc_infer_hs_type` does not. I found this behavior to be strang...## Summary
I investigated https://gitlab.haskell.org/ghc/ghc/-/issues/23639 and found that `tc_hs_type` calls `addModFinalizersWithLclEnv` on untyped top-level splices, but `tc_infer_hs_type` does not. I found this behavior to be strange and is likely a bug. After some investigation, I came up with a test case that exhibits the problem. Luckily, the fix for this bug should be a one line change.
## Steps to reproduce
```haskell
{-# LANGUAGE TemplateHaskell #-}
module T where
import Language.Haskell.TH.Syntax (addModFinalizer, runIO)
import GHC.Types (Type)
type Proxy :: forall a. a -> Type
data Proxy a = MkProxy
check :: ($(addModFinalizer (runIO (putStrLn "check")) >>
[t| Proxy |]) :: Type -> Type) Int -- There is kind signature, we are in check mode
check = MkProxy
infer :: ($(addModFinalizer (runIO (putStrLn "infer")) >>
[t| Proxy |]) ) Int -- no kind signature, inference mode is enabled
infer = MkProxy
```
Attempt to compile this code will result in the following stdout:
```
$ ghc T.hs -fforce-recomp
[1 of 1] Compiling T ( T.hs, T.o )
check
```
## Expected behavior
```
$ ghc T.hs -fforce-recomp
[1 of 1] Compiling T ( T.hs, T.o )
check
infer
```
## Environment
* GHC version used: masterAndrei BorzenkovAndrei Borzenkovhttps://gitlab.haskell.org/ghc/ghc/-/issues/24562Hide Language.Haskell.TH.Lib.Internal from hoogle/haddocks2024-03-19T14:42:24ZTeo CamarasuHide Language.Haskell.TH.Lib.Internal from hoogle/haddocksOn this mailing list thread: https://mail.haskell.org/pipermail/ghc-devs/2024-March/021569.html
@yav mentions that it's confusing that identifiers from [`Language.Haskell.TH.Lib.Internal`](https://hackage.haskell.org/package/template-has...On this mailing list thread: https://mail.haskell.org/pipermail/ghc-devs/2024-March/021569.html
@yav mentions that it's confusing that identifiers from [`Language.Haskell.TH.Lib.Internal`](https://hackage.haskell.org/package/template-haskell-2.21.0.0/docs/Language-Haskell-TH-Lib-Internal.html) come up when searching on Hoogle and in Haddocks, especially since they have the same names as identifiers from the user-facing `Language.Haskell.TH.Lib` module.
Perhaps we could hide this module from Hoogle/Haddock to avoid this confusion as this module isn't meant to be user-facing anyway?
I think the right way to do this is to add a `hide` hadddock options pragma to the file.
Alternatively we could just remove the module from `exposed-modules` but that seems like an unnecessary breaking change.
Hackage search[^1] reveals only HList depends on this module in an example. The other references are from `ghc`, `ghc-lib` and `ghc-lib-parser`, so I don't think users depend on it in practice either.
[^1]: https://hackage-search.serokell.io/?q=Language.Haskell.TH.Lib.Internal9.10.1Rodrigo MesquitaRodrigo Mesquitahttps://gitlab.haskell.org/ghc/ghc/-/issues/24455Allow annotating fields to be lazy even if the module is not using StrictData2024-03-18T19:54:59ZOleg GrenrusAllow annotating fields to be lazy even if the module is not using StrictDataThis comes up when using Template Haskell.
There is no convenient way to say that the field of data field in generated declaration to be explicitly lazy.
The current go to approach is to query whether `StrictData` extension is enabled ...This comes up when using Template Haskell.
There is no convenient way to say that the field of data field in generated declaration to be explicitly lazy.
The current go to approach is to query whether `StrictData` extension is enabled and then generate `data Foo = Foo ~Int ~Char` or `data = Foo Int Char` based on that.
Or maybe library functions like [`normalC`](https://hackage.haskell.org/package/template-haskell-2.21.0.0/docs/Language-Haskell-TH-Lib-Internal.html#v:normalC) or `sourceLazy` should query whether `StrictData` is enabled and just work.
---
Note, that for terms, one can ask people to enable `BangPatterns` so one could generate explicitly banged code like, `let !foo = 2 + 2 in ...`, but there is no extensions to just enable writing `data Foo = Foo ~Int ~Char` without also changing the meaning of `data Foo = Foo Int Char`, i.e. there is no `LazyDataAnnotations`. In my opinion that is design flaw in `StrictData` extension: it bundles syntax *and* changes defaults.https://gitlab.haskell.org/ghc/ghc/-/issues/14030Implement the "Derive Lift instances for data types in template-haskell" prop...2024-03-18T14:36:50ZRyan ScottImplement the "Derive Lift instances for data types in template-haskell" proposalBack in September 2015, I [proposed](https://mail.haskell.org/pipermail/libraries/2015-September/026117.html) using the `DeriveLift` extension to, well, derive `Lift` instance for data types in the `template-haskell` library. The proposa...Back in September 2015, I [proposed](https://mail.haskell.org/pipermail/libraries/2015-September/026117.html) using the `DeriveLift` extension to, well, derive `Lift` instance for data types in the `template-haskell` library. The proposal was well received, but I was unable to implement it at the time due to `DeriveLift`'s newness (having only been introduced in GHC 8.0). Now that GHC 8.0 is the oldest version of GHC that we support bootstrapping with, this is no longer an obstacle.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ---------------- |
| Version | 8.3 |
| Type | Task |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Template Haskell |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Implement the \"Derive Lift instances for data types in template-haskell\" proposal","status":"New","operating_system":"","component":"Template Haskell","related":[],"milestone":"8.4.1","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Task","description":"Back in September 2015, I [https://mail.haskell.org/pipermail/libraries/2015-September/026117.html proposed] using the `DeriveLift` extension to, well, derive `Lift` instance for data types in the `template-haskell` library. The proposal was well received, but I was unable to implement it at the time due to `DeriveLift`'s newness (having only been introduced in GHC 8.0). Now that GHC 8.0 is the oldest version of GHC that we support bootstrapping with, this is no longer an obstacle.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/22229DeriveLift leads to undeclared dependencies on Language.Haskell.TH.Lib2024-03-18T13:24:28ZMatthew PickeringDeriveLift leads to undeclared dependencies on Language.Haskell.TH.LibModules in containers use DeriveLift in order to give Lift instances for
the data types. This is problematic for multi-component sessions which involve
loading containers and template-haskell into the same session because
* Lift comes f...Modules in containers use DeriveLift in order to give Lift instances for
the data types. This is problematic for multi-component sessions which involve
loading containers and template-haskell into the same session because
* Lift comes from Language.Haskell.TH.Syntax
* DeriveLift used identifiers from Language.Haskell.TH.Lib.Internal
Therefore the modules add an import on Language.Haskell.TH.Syntax (in order to import Lift)
but no dependency is recorded between the module and
Language.Haskell.TH.Lib.Internal. However, we need to compile the Internal module
before the module in containers as the desugared code for DeriveLift depends on the
combinators defined in this module.
Can we fix this in GHC? How about adding these edges if a module enables DeriveLift?
This option is precluded because -XDeriveLift is included in Haskell2021 so almost
all modules which exhibit a new dependency on `template-haskell` library without
using it. The most straightforward but ugly solution is to explicitly add these
edges to the build graph. Most projects will not encounter this issue because
they will not be compiled in the same session as the `template-haskell` package.
This has already caused a couple of build system issues in GHC, see !9049 for example.
Note that
* This only affects hard-core GHC developers, who are building GHC itself.
* Hadrian (used by the aforementioned developers) is clever enough to know the dependency of a module M of package A, on a module X of a different package B. So we can start building package A before finishing building package B.https://gitlab.haskell.org/ghc/ghc/-/issues/24031Deprecate `PrimTyConI`2024-03-18T13:15:51ZTeo CamarasuDeprecate `PrimTyConI`See also
* #20914
## Motivation
One of the possible response forms from reifying a datatype using `template-haskell` is the [`PrimTyConI`](https://hackage.haskell.org/package/template-haskell-2.20.0.0/docs/Language-Haskell-TH-Syntax.ht...See also
* #20914
## Motivation
One of the possible response forms from reifying a datatype using `template-haskell` is the [`PrimTyConI`](https://hackage.haskell.org/package/template-haskell-2.20.0.0/docs/Language-Haskell-TH-Syntax.html#v:PrimTyConI) constructor.
This is defined as:
```hs
data Info =
...
-- | A \"primitive\" type constructor, which can't be expressed with a 'Dec'.
-- Examples: @(->)@, @Int#@.
| PrimTyConI
Name
Arity
Unlifted
...
```
The strange thing about this constructor is that it could be completely subsumed into the `TyConI` case, which is the more general one for type constructors.
The only thing that sets it apart is that it labels the type as "primitive" (which I take to be wired-in unlifted/unboxed types). Yet, not all primitive types are represented by this constructor. Reifying unboxed tuples and sums gives you a `TyConI` constructor. So, it doesn't even give users an accurate portrait of which types are "primitive".
I think this used to be necessary before GHC had proper support for unboxed/unlifted kinds, but I'm not sure if it's still needed.
It just appears to be a vestigial edge case.
## Proposal
Stop emitting instances of this constructor and consistently use `TyConI` instead.
I don't think there's any immediate need to get rid of the constructor for now, since code might rely on its existence.https://gitlab.haskell.org/ghc/ghc/-/issues/24395Profiled GHC flavour segfaults when building a target project with TH or GHC ...2024-03-18T13:14:06ZIan-Woo KimProfiled GHC flavour segfaults when building a target project with TH or GHC plugin## Summary
When I use GHC built with the `profiled_ghc` flavour, GHC segfaults when it compiles a target code with TH or with a GHC plugin (with profiling on for the target project).
The segfaults happened in most of time on my machine,...## Summary
When I use GHC built with the `profiled_ghc` flavour, GHC segfaults when it compiles a target code with TH or with a GHC plugin (with profiling on for the target project).
The segfaults happened in most of time on my machine, but sometimes it passes, so the error happens nondeterministically.
With a smaller probability, it sometimes leads to GHC internal errors showing this is related to code relocation on linking:
```
ghc: internal error: Relocation out of range for SUBTRACTOR
```
By the way, this problem happens almost in building many of dependency packages that use TH or GHC plugins in a big private project with `library_profiling: True`.
## Steps to reproduce
I made a sample project here:
https://gist.github.com/wavewave/97c802cb80aecf8146a7d5af21cf4bf1
and one can reproduce it by the following build command:
```
$ cabal build --project-file=ghcHEAD-cabal-profiledGHC.project
Build profile: -w ghc-9.9.20240115 -O0
In order, the following will be built (use -v for more details):
- myfailure-2.11.0 (lib) (file MyFailure.hs changed)
Preprocessing library for myfailure-2.11.0..
Building library for myfailure-2.11.0..
<no location info>: warning: [GHC-42258] [-Wunused-packages]
The following packages were specified via -package or -package-id flags,
but were not needed for compilation:
- bytestring-0.12.0.2 (exposed by flag -package-id bytestring-0.12.0.2-inplace)
- http-conduit-2.3.8.3 (exposed by flag -package-id http-cndt-2.3.8.3-68b1c994)
- microlens-0.4.13.1 (exposed by flag -package-id mcrlns-0.4.13.1-4239c11e)
- aeson-2.2.0.0 (exposed by flag -package-id sn-2.2.0.0-921d37e9)
[1 of 1] Compiling MyFailure ( MyFailure.hs, /Users/ianwookim/tmp/profiledGHC/hoauth2-2.11.0/dist-newstyle/build/aarch64-osx/ghc-9.9.20240115/myfailure-2.11.0/noopt/build/MyFailure.o ) [Source file changed]
Error: cabal: Failed to build myfailure-2.11.0. The build process segfaulted
(i.e. SIGSEGV).
```
Note that I intentionally add redundant deps. When I remove one of those deps, the probability of the segfaults got reduced. (probably, another indicator that this bug is related to code relocation offset amount)
## Expected behavior
Segfault should not happen in any case. If something is wrong (such as linker couldn't find some symbols etc), it should show that error.
## Environment
* GHC version used: GHC master, 9.9.20240115 version (`da908790670cd5161cffc3d83757fb8048bdafda`)
Optional:
* Operating System: macOS Sonoma 14.2.1
* System Architecture: Apple M1 Max (AArch64)ZubinZubinhttps://gitlab.haskell.org/ghc/ghc/-/issues/24009TH Match quotations2024-03-11T10:51:07ZOleg GrenrusTH Match quotationsCurrently it's possible to quote expressions `[| e |] :: ExpQ`, patterns `[p| pat |] :: PatQ`, types `[t| Ty |] :: TypeQ` and declarations `[d| data Bar |] :: DecsQ`.
I think it should be possible to quote "matches":
```haskell
[m| Jus...Currently it's possible to quote expressions `[| e |] :: ExpQ`, patterns `[p| pat |] :: PatQ`, types `[t| Ty |] :: TypeQ` and declarations `[d| data Bar |] :: DecsQ`.
I think it should be possible to quote "matches":
```haskell
[m| Just x -> print x |] :: MatchQ
```
As matches can have binders, that cannot be easily split into pattern and expression (+ `where` declarations) quotes, i.e. in
`[p| Just x |]`, the `x` is fresh, and in `[e| print x |]`, we have `UnboundVarE x`.
So to construct `MatchQ` we need to manually call `newName`:
```haskell
x <- newName "x"
match (conP 'Just [varP x]) (normalB $ appE (varE 'print) (varE x)) []
```
A lot obscurer than above `[m| Just x -> print x |]`.https://gitlab.haskell.org/ghc/ghc/-/issues/21794TH silently drops quantification in instance heads2024-02-27T13:58:42ZMichael Peyton JonesTH silently drops quantification in instance heads## Summary
Here's a program I was writing, the exact program doesn't matter except that it uses a `forall` in the instance head to bind a variable (and give it an explicit kind, which is what I care about).
```haskell
{-# LANGUAGE Data...## Summary
Here's a program I was writing, the exact program doesn't matter except that it uses a `forall` in the instance head to bind a variable (and give it an explicit kind, which is what I care about).
```haskell
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -ddump-splices -ddump-to-file -dsuppress-uniques -dsuppress-coercions -dsuppress-type-applications -dsuppress-unfoldings -dsuppress-idinfo -dppr-cols=200 -dumpdir /tmp/dumps #-}
module Repro where
import Data.Kind
$([d|
data P = L | R
data T (a :: P) where
A :: T a
B :: T R
type TConstraint = forall a . T a -> Constraint
type ForAllA :: TConstraint -> Constraint
class (forall a . constr @a A) => ForAllA constr
instance forall (constr :: TConstraint) . (forall a . constr @a A) => ForAllA constr
|])
```
The splice output is this:
```
Repro.hs:(17,2)-(27,6): Splicing declarations
[d| type ForAllA :: TConstraint -> Constraint
data P = L | R
data T (a :: P)
where
A :: T a
B :: T R
type TConstraint = forall a. T a -> Constraint
class (forall a. constr @a A) => ForAllA constr
instance forall (constr :: TConstraint). (forall a. constr @a A) => ForAllA constr |]
======>
data P = L | R
data T (a :: P)
where
A :: T a
B :: T 'R
type TConstraint = forall a. T a -> Constraint
type ForAllA :: TConstraint -> Constraint
class (forall a. constr @a 'A) => ForAllA constr
instance (forall a. constr @a 'A) => ForAllA constr
```
Note the absence of the forall. And indeed, the program fails to compile in exactly the way it would if the forall was missing (which happens to be https://gitlab.haskell.org/ghc/ghc/-/issues/21793).
## Steps to reproduce
The above file should compile standalone and show the problem.
## Expected behavior
Actually include all the syntax!
## Environment
* GHC version used: 9.2.3sheafsam.derbyshire@gmail.comsheafsam.derbyshire@gmail.comhttps://gitlab.haskell.org/ghc/ghc/-/issues/1475Adding imports and exports with Template Haskell2024-02-22T00:34:11ZIan Lynagh <igloo@earth.li>Adding imports and exports with Template Haskell(wished for by Adrian Hey in http://www.haskell.org/pipermail/template-haskell/2007-June/000598.html)
It would be useful to be able to add module exports with TH, although I'm not sure exactly how it would be done. Perhaps something lik...(wished for by Adrian Hey in http://www.haskell.org/pipermail/template-haskell/2007-June/000598.html)
It would be useful to be able to add module exports with TH, although I'm not sure exactly how it would be done. Perhaps something like
```
$( do n <- newName "foo"
let d = funD n ...
addExport (varE n)
return [d]
```
but at the point we call `addExport` the typechecker doesn't know that there will be a declaration for the name.
Less useful, as TH names include the package and module of the name's definition, is the ability to add module imports. However, this can still be used to get a kind of dynamic binding effect, either with `mkName`'s names or plain Haskell code, e.g.:
```
$( addImport (if ... then '''Data.ByteString else '''Data.ByteString.Lazy)
(mkName "BS") )
foo :: BS.ByteString
foo = BS.append ...
```
(we'd actually probably want a datatype that mirrors Haskell import decls more closely).
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ---------------- |
| Version | 6.6.1 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Template Haskell |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | Unknown |
| Architecture | Unknown |
</details>
<!-- {"blocked_by":[],"summary":"Adding imports and exports with Template Haskell","status":"New","operating_system":"Unknown","component":"Template Haskell","related":[],"milestone":"6.8 branch","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.6.1","keywords":[],"differentials":[],"test_case":"","architecture":"Unknown","cc":[""],"type":"FeatureRequest","description":"(wished for by Adrian Hey in http://www.haskell.org/pipermail/template-haskell/2007-June/000598.html)\r\n\r\nIt would be useful to be able to add module exports with TH, although I'm not sure exactly how it would be done. Perhaps something like\r\n{{{\r\n$( do n <- newName \"foo\"\r\n let d = funD n ...\r\n addExport (varE n)\r\n return [d]\r\n}}}\r\nbut at the point we call `addExport` the typechecker doesn't know that there will be a declaration for the name.\r\n\r\nLess useful, as TH names include the package and module of the name's definition, is the ability to add module imports. However, this can still be used to get a kind of dynamic binding effect, either with `mkName`'s names or plain Haskell code, e.g.:\r\n{{{\r\n$( addImport (if ... then '''Data.ByteString else '''Data.ByteString.Lazy)\r\n (mkName \"BS\") )\r\n\r\nfoo :: BS.ByteString\r\nfoo = BS.append ...\r\n}}}\r\n(we'd actually probably want a datatype that mirrors Haskell import decls more closely).","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/14032Can't splice TH quote with infix declaration for name in two different namesp...2024-02-21T10:01:03ZRyan ScottCan't splice TH quote with infix declaration for name in two different namespacesSpun off from #13799 (and #13054\##14032). This code compiles:
```hs
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
infix 5 :*:
data a :*: b = a :*: b
```
But this code does not:
```hs
{-# LANGUAGE TemplateHaskell #-...Spun off from #13799 (and #13054\##14032). This code compiles:
```hs
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
infix 5 :*:
data a :*: b = a :*: b
```
But this code does not:
```hs
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
$([d| infix 5 :*:
data a :*: b = a :*: b
|])
```
```
$ /opt/ghc/8.2.1/bin/ghc -ddump-splices Bug.hs
[1 of 1] Compiling Main ( Bug.hs, Bug.o )
Bug.hs:(4,3)-(6,6): Splicing declarations
[d| infix 5 :*:_anM, :*:_anL
data a_anN :*:_anL b_anO = a_anN :*:_anM b_anO |]
======>
infix 5 :*:_a3IL
infix 5 :*:_a3IK
data (:*:_a3IK) a_a3IM b_a3IN = a_a3IM :*:_a3IL b_a3IN
Bug.hs:4:3: error:
Multiple fixity declarations for ‘:*:_a3IL’
also at Bug.hs:(4,3)-(6,6)
|
4 | $([d| infix 5 :*:
| ^^^^^^^^^^^^^^^...
```
Inspecting the `-ddump-splices` output reveals why: when `infix 5 :*:` is renamed, because `:*:` refers to two different names in both the value and type namespaces, it actually gets renamed to `infix 5 :*:_anM, :*:_anL`, where `:*:_anM` and `:*:_anL` are the same name with different uniques.
Normally, this isn't a problem, since feeding `infix 5 :*:_anM, :*:_anL` to the typechecker works fine. However, when it's spliced in via Template Haskell, it gets fed back into the renamer, where it believes that `:*:_anM` and `:*:_anL` are duplicate names, causing the error.
Really, this is just a symptom of the fact that infix declarations are insufficiently powerful to encode information for identical names in different namespaces. But until GHC gains this ability, we need to find some workaround for this problem. My hunch is that we'll need to give GHC the power to recognize these sorts of duplicate fixity declarations in `Convert` and only emit one actual fixity declaration per set of duplicates. (Disclaimer: I haven't worked out all the fiddly details yet.)
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ---------------- |
| Version | 8.0.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Template Haskell |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Can't splice TH quote with infix declaration for name in two different namespaces","status":"New","operating_system":"","component":"Template Haskell","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.0.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Spun off from #13799 (and https://ghc.haskell.org/trac/ghc/ticket/13054#comment:2). This code compiles:\r\n\r\n{{{#!hs\r\n{-# LANGUAGE TemplateHaskell #-}\r\n{-# LANGUAGE TypeOperators #-}\r\n\r\ninfix 5 :*:\r\ndata a :*: b = a :*: b\r\n}}}\r\n\r\nBut this code does not:\r\n\r\n{{{#!hs\r\n{-# LANGUAGE TemplateHaskell #-}\r\n{-# LANGUAGE TypeOperators #-}\r\n\r\n$([d| infix 5 :*:\r\n data a :*: b = a :*: b\r\n |])\r\n}}}\r\n{{{\r\n$ /opt/ghc/8.2.1/bin/ghc -ddump-splices Bug.hs\r\n[1 of 1] Compiling Main ( Bug.hs, Bug.o )\r\nBug.hs:(4,3)-(6,6): Splicing declarations\r\n [d| infix 5 :*:_anM, :*:_anL\r\n \r\n data a_anN :*:_anL b_anO = a_anN :*:_anM b_anO |]\r\n ======>\r\n infix 5 :*:_a3IL\r\n infix 5 :*:_a3IK\r\n data (:*:_a3IK) a_a3IM b_a3IN = a_a3IM :*:_a3IL b_a3IN\r\n\r\nBug.hs:4:3: error:\r\n Multiple fixity declarations for ‘:*:_a3IL’\r\n also at Bug.hs:(4,3)-(6,6)\r\n |\r\n4 | $([d| infix 5 :*:\r\n | ^^^^^^^^^^^^^^^...\r\n}}}\r\n\r\nInspecting the `-ddump-splices` output reveals why: when `infix 5 :*:` is renamed, because `:*:` refers to two different names in both the value and type namespaces, it actually gets renamed to `infix 5 :*:_anM, :*:_anL`, where `:*:_anM` and `:*:_anL` are the same name with different uniques.\r\n\r\nNormally, this isn't a problem, since feeding `infix 5 :*:_anM, :*:_anL` to the typechecker works fine. However, when it's spliced in via Template Haskell, it gets fed back into the renamer, where it believes that `:*:_anM` and `:*:_anL` are duplicate names, causing the error.\r\n\r\nReally, this is just a symptom of the fact that infix declarations are insufficiently powerful to encode information for identical names in different namespaces. But until GHC gains this ability, we need to find some workaround for this problem. My hunch is that we'll need to give GHC the power to recognize these sorts of duplicate fixity declarations in `Convert` and only emit one actual fixity declaration per set of duplicates. (Disclaimer: I haven't worked out all the fiddly details yet.)","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/24440More informative error reporting from QuasiQuoters2024-02-20T14:42:01ZDavid FeuerMore informative error reporting from QuasiQuoters## Motivation
When a `QuasiQuoter` fails (calling `fail`), there are (essentially)
two potential reasons:
1. There is something wrong with part or all of the string it is
asked to interpret.
2. There is something wrong with the cont...## Motivation
When a `QuasiQuoter` fails (calling `fail`), there are (essentially)
two potential reasons:
1. There is something wrong with part or all of the string it is
asked to interpret.
2. There is something wrong with the context it occurs in.
GHC's error highlighter assumes the first reason. For example, suppose
```haskell
defaultQuasiQuoter :: QuasiQuoter
defaultQuasiQuoter = QuasiQuoter
{ quoteExp = f "use in expression contexts."
, quotePat = f "use in pattern contexts."
, quoteType = f "use in types."
, quoteDec = f "creating declarations."
}
where
f m _ = fail $ "This quasiquoter is not for " ++ m
```
If I write
```haskell
f [defaultQuasiQuoter| whatever |] = 3
```
I get the error
```
Vest.hs:6:12: error:
• This quasiquoter is not for use in pattern contexts.
• In the quasi-quotation: [myPatQQ| Whatever |]
|
6 | f [myPatQQ| Whatever |] = 3
| ^^^^^^^^^^^^
```
The error highlighting suggests that the problem is in `Whatever`, but in fact it is not.
## Proposal
It would be nice to have a mechanism by which the `QuasiQuoter` can signal whether it's reporting an error with its argument or with its context. Where it's reporting an error with its argument, it would also be great if it could (optionally) indicate where in its argument string it encountered a problem. These argument strings can be *extremely* long, so just telling the user that the problem is "somewhere out that way" isn't very helpful. The options I can think of:
1. Add appropriate methods to `Quasi`. This seems cleanest.
2. Use the fact that `Quasi` is a subclass of `MonadIO`, letting particular thrown exception types represent these situations. This is pretty hideous, and doesn't deal nicely with recoverable errors.https://gitlab.haskell.org/ghc/ghc/-/issues/24434Add default QuasiQuoter(s)2024-02-14T19:23:59ZDavid FeuerAdd default QuasiQuoter(s)## Motivation
`Language.Haskell.TH.Quote` gives us
```haskell
data QuasiQuoter = QuasiQuoter {
-- | Quasi-quoter for expressions, invoked by quotes like @lhs = $[q|...]@
quoteExp :: String -> Q Exp,
-- | Quasi-quoter for p...## Motivation
`Language.Haskell.TH.Quote` gives us
```haskell
data QuasiQuoter = QuasiQuoter {
-- | Quasi-quoter for expressions, invoked by quotes like @lhs = $[q|...]@
quoteExp :: String -> Q Exp,
-- | Quasi-quoter for patterns, invoked by quotes like @f $[q|...] = rhs@
quotePat :: String -> Q Pat,
-- | Quasi-quoter for types, invoked by quotes like @f :: $[q|...]@
quoteType :: String -> Q Type,
-- | Quasi-quoter for declarations, invoked by top-level quotes
quoteDec :: String -> Q [Dec]
}
```
The documentation suggests that
> if you are only interested
> in defining a quasiquoter to be used for expressions, you would
> define a 'QuasiQuoter' with only 'quoteExp', and leave the other
> fields stubbed out with errors.
This is not ideal. There are a few problems:
The easiest path, which some packages take, is to write something like
```haskell
myqq = QuasiQuoter
{ quoteExp = ... }
```
The error message produced when `myqq` is used in the wrong context will not explain the problem at all; it'll just point out that there was an exception in Template Haskell code. The second problem is that using `error`, even more informatively, will produce an overly verbose, poorly formatted message because GHC assumes that it represents a bug in the quasiquoter. The correct thing is instead to use `fail` as usual.
## Proposal
I suggest offering one or perhaps a couple of suitable "default" `QuasiQuoter` definitions. These could look like so:
```haskell
defaultQuasiQuoter :: QuasiQuoter
defaultQuasiQuoter = QuasiQuoter
{ quoteExp = \_ -> fail "This quasiquoter is not for use in expressions"
, quoteType = \_ -> fail "This quasiquoter is not for use in types"
, quotePat = \_ -> fail "This quasiquoter is not for use in patterns"
, quoteDec = \_ -> fail "This quasiquoter is not for producing declarations"
}
namedDefaultQuasiQuoter :: String -> QuasiQuoter
namedDefaultQuasiQuoter n = QuasiQuoter
{ quoteExp = \_ -> fail $ "The " ++ n ++ " quasiquoter is not for use in expressions"
, quoteType = \_ -> fail $ "The " ++ n ++ " quasiquoter is not for use in types"
, quotePat = \_ -> fail $ "The " ++ n ++ " quasiquoter is not for use in patterns"
, quoteDec = \_ -> fail $ "The " ++ n ++ " quasiquoter is not for producing declarations"
}
```
Now users can write things like
```haskell
myqq = (namedDefaultQuasiQuoter "myqq")
{ quoteExp = ... }
```
The documentation should also indicate that the unused fields should `fail` rather than `error`.David FeuerDavid Feuer