[GHC] #10697: Change template-haskell API to allow NOUNPACK, lazy annotations
GHC
ghc-devs at haskell.org
Sat Dec 12 21:41:51 UTC 2015
#10697: Change template-haskell API to allow NOUNPACK, lazy annotations
-------------------------------------+-------------------------------------
Reporter: RyanGlScott | Owner:
Type: feature request | Status: patch
Priority: normal | Milestone:
Component: Template Haskell | Version: 7.10.1
Resolution: | Keywords:
Operating System: Unknown/Multiple | Architecture:
| Unknown/Multiple
Type of failure: None/Unknown | Test Case:
Blocked By: | Blocking:
Related Tickets: #5290, #8347 | Differential Rev(s): Phab:D1603
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by RyanGlScott):
I will admit that I got a little too ambitious with my proposal in
comment:12, which Simon noted. TH splices should never be altered if given
"bad" input like what I had proposed. I like Simon's idea of granting the
user the ability to reify a constructor's fields' strictness after
compilation, which I incorporated in Phab:D1603.
I'll go ahead and post the updated design here so we have a common point
to reference in this discussion. Here is the API that concerns reification
of data types, which coincides precisely with the strictness annotations a
user writes in source code (i.e., `HsSrcBang`):
{{{#!hs
data SourceUnpackedness = NoSourceUnpackedness
| SourceNoUnpack
| SourceUnpack
data SourceStrictness = NoSourceStrictness
| SourceLazy
| SourceStrict
data Con = NormalC Name [BangType]
| RecC Name [VarBangType]
| InfixC BangType Name BangType
| ForallC [TyVarBndr] Cxt Con
data Bang = Bang SourceUnpackedness SourceStrictness
type BangType = (Bang, Type)
type VarBangType = (Name, Bang, Type)
}}}
There is also a similar API for discovering what GHC actually turns these
strictness/unpackedness combinations into after compilation (i.e.,
`HsImplBang`), which can be affected by `-XStrictData`, `-funbox-strict-
fields`, etc.
{{{#!hs
data DecidedStrictness = DecidedLazy
| DecidedStrict
| DecidedUnpack
class Monad m => Quasi m where
...
qReifyConStrictness :: Con -> m [DecidedStrictness]
}}}
> 1. TH quotes should faithfully turn user-written syntax into the TH AST.
Agreed.
> But it's not obliged to deal with meaningless user-written syntax. Are
all nine possibilities enumerated in the original post meaningful? I don't
think so. (Does `{-# UNPACK #-} ~blah` ever make sense?) If it makes the
design of TH harder, I don't think we need to deal with the non-meaningful
combinations. But, all else being equal, being able to represent what the
user wrote is helpful.
I somewhat disagree here. TH splices should produce syntactically valid
code, but there's no guarantee that code that it will be meaningful. After
all, you could conceivably splice in something like `foo :: Maybe ->
Maybe`.
You're right in that internally, GHC doesn't think all nine combinations
are compatible. In fact, `HsImplBang` only has three combinations: strict,
lazy, and unpacked. But the source language is much richer, and it would
be difficult to graft `{-# NOUNPACK #-}` and laziness annotations onto
Template Haskell without acknowledging that unpackedness annotations and
strictness annotations can be used independently of each other in source
code.
Not only that, you can't always tell what GHC will produce just from
examining the unpackedness and strictness annotations alone; it's also
affected by language extensions, optimization levels, and other
inscrutable factors. That's why GHC keeps track of `HsSrcBang` information
even after it's determined what the `HsImplBang`s are. If it didn't,
there'd be no way things like GHCi could tell you how the original data
type was written in source code, since that information could have been
distorted.
For these reasons, I feel strongly that we need to be able to express all
combinations of annotations, even if some of them aren't meaningful to
GHC.
> 2. Splicing should respect what extensions are on in the splicing
module, ''not'' the quoting module. When splicing a quote, GHC should
behave exactly as if the code were copied and pasted from the quote to the
splice.
Also agreed. I moved the `DecidedStrictness` stuff out of the AST so that
this property would be preserved.
> 3. Reification, as implemented, is a lie. GHC does not save the actual
syntax the user wrote and so does a best-effort approximation. It's always
going to be a bit wrong, at least until we're giving users a `TyCon`
directly (which I'm not suggesting here).
True, but I think that as long as property 2 holds, this isn't a big deal.
Not only that, but TH's `SourceStrictness`, `SourceUnpackedness`, and
`DecidedStrictness` are in one-to-one correspondence with GHC's
`SrcStrictness`, `SrcUnpackedness`, and `HsImplBang`, respectively, so we
don't have to lie in this particular case.
> 4. Reification should behave identically no matter what extensions are
enabled. Anything else seems doomed to endlessly befuddle users.
I feel like you need to be more specific here before I can respond to
this. Are you referring to reification of what the user ''wrote'', or
reification of GHC-specific info that depends on compilation settings? If
it's the former, I agree, but not if it's the latter.
> I think I favor an implementation of reification that never returns
`NoStrictAnnot` and never returns `NoUnpackAnnot`; that is, it tells you
precisely what GHC is doing, all the time. This has the noted downside
that laziness annotations will cause compilation problems without
`StrictData`. So we also add new (quite straightforward, pure) functions
that make a reified data declaration suitable for `-XNoStrictData` or
`-XStrictData`. Perhaps with Phab:D1200 complete (extension checking), we
can offer a function that just does the right thing.
Again, are you referring to the source strictness or the GHC-decided
strictness here? If it's the decided strictness, then as you say, it
doesn't make sense to return "no strictness". If it's the source
strictness, adding a "no strictness" option is, IMO, unavoidable (see my
response to point 1).
> This reification problem is quite similar (as you point out) to kind
annotations on type variable binders. A few versions ago, reification used
`PlainTV` for all `*`-kinded variables and `KindedTV` for others. But this
was just bogus, and now there are a lot more kind signatures. Of course,
this means that reified code might not always compile if spliced -- just
like what I'm proposing about strictness, etc.
Upon further thought, I don't think this comparison is a very good one.
`TyVarBndr` is special because it's possible to write type variables
without kind signatures and have GHC infer them; that is, there's a
special input form for splicing that never appears in the reified output.
Strictness, on the other hand, has special ''output'' forms that should
never appear in the spliced input. Going the other way is problematic, and
for that reason, I adopted Simon's suggestion of splitting off the
`DecidedStrictness` stuff and moving it to a `reifyConStrictness`
function.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/10697#comment:16>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list