Commit c8f623e3 authored by spinda's avatar spinda Committed by Ben Gamari

Expand declaration QQs first (#10047)

Declaration QuasiQuoters do not cause a group split like $(...)
splices, and are run and expanded before other declarations in
the group.

Resolves the lingering issue with #10047, and fixes broken tests
qq007 and qq008.

Test Plan: validate

Reviewers: goldfire, austin, bgamari

Reviewed By: bgamari

Subscribers: goldfire, simonpj, thomie, spinda

Differential Revision: https://phabricator.haskell.org/D1199

GHC Trac Issues: #10047
parent ba5554ec
......@@ -13,7 +13,7 @@ module RnSource (
#include "HsVersions.h"
import {-# SOURCE #-} RnExpr( rnLExpr )
import {-# SOURCE #-} RnSplice ( rnSpliceDecl )
import {-# SOURCE #-} RnSplice ( rnSpliceDecl, rnTopSpliceDecls )
import HsSyn
import RdrName
......@@ -1510,6 +1510,13 @@ addl gp (L l d : ds) = add gp l d ds
add :: HsGroup RdrName -> SrcSpan -> HsDecl RdrName -> [LHsDecl RdrName]
-> RnM (HsGroup RdrName, Maybe (SpliceDecl RdrName, [LHsDecl RdrName]))
-- #10047: Declaration QuasiQuoters are expanded immediately, without
-- causing a group split
add gp _ (SpliceD (SpliceDecl (L _ qq@HsQuasiQuote{}) _)) ds
= do { (ds', _) <- rnTopSpliceDecls qq
; addl gp (ds' ++ ds)
}
add gp loc (SpliceD splice@(SpliceDecl _ flag)) ds
= do { -- We've found a top-level splice. If it is an *implicit* one
-- (i.e. a naked top level expression)
......
......@@ -13,3 +13,5 @@ rnSpliceType :: HsSplice RdrName -> PostTc Name Kind
rnSplicePat :: HsSplice RdrName -> RnM ( Either (Pat RdrName) (Pat Name)
, FreeVars )
rnSpliceDecl :: SpliceDecl RdrName -> RnM (SpliceDecl Name, FreeVars)
rnTopSpliceDecls :: HsSplice RdrName -> RnM ([LHsDecl RdrName], FreeVars)
......@@ -194,6 +194,18 @@
pragmas.
</para>
</listitem>
<listitem>
<para>
Internally, the implementation of quasi-quotes has been
unified with that of normal Template Haskell splices. Under
the previous implementation, top-level declaration
quasi-quotes did not cause a break in the declaration
groups, unlike splices of the form
<literal>$(...)</literal>. This behavior has been
preserved under the new implementation, and is now
recognized and documented in <xref linked="th-syntax"/>.
</para>
</listitem>
</itemizedlist>
</sect3>
......@@ -255,16 +267,19 @@
</listitem>
<listitem>
<para>
The functions <literal>error</literal>,
<literal>undefined</literal>, and
<literal>assertError</literal> now take an implicit
<literal>CallStack</literal> parameter, and will
output a formatted call stack alongside the error
message.
A new module <literal>GHC.SrcLoc</literal> was added,
exporting a new type <literal>SrcLoc</literal>. A
<literal>SrcLoc</literal> contains package, module,
and file names, as well as start and end positions.
</para>
</listitem>
<listitem>
<para>
See <xref linkend="implicit-parameters-special"/> for a description of the
implicit call stack feature.
A new type <literal>CallStack</literal> was added for use
with the new implicit callstack parameters. A
<literal>CallStack</literal> is a
<literal>[(String, SrcLoc)]</literal>, sorted by most-recent
call.
</para>
</listitem>
<listitem>
......@@ -403,22 +418,6 @@
Version number XXXXX (was 0.3.1.0)
</para>
</listitem>
<listitem>
<para>
A new type <literal>SrcLoc</literal> was added. A
<literal>SrcLoc</literal> contains package, module,
and file names, as well as start and end positions.
</para>
</listitem>
<listitem>
<para>
A new type <literal>CallStack</literal> was added for use
with the new implicit callstack parameters. A
<literal>CallStack</literal> is a
<literal>[(String, SrcLoc)]</literal>, sorted by most-recent
call.
</para>
</listitem>
</itemizedlist>
</sect3>
......
......@@ -9721,8 +9721,8 @@ Wiki page</ulink>.
</listitem>
<listitem><para>
A quasi-quotation can appear in either a pattern context or an
expression context and is also written in Oxford brackets:
A quasi-quotation can appear in a pattern, type, expression, or
declaration context and is also written in Oxford brackets:
<itemizedlist>
<listitem><para> <literal>[<replaceable>varid</replaceable>| ... |]</literal>,
where the "..." is an arbitrary string; a full description of the
......@@ -9868,6 +9868,17 @@ f n = \ [haskell|y|] -> y+n
declaration group, but no more.
</para>
<para>
Unlike normal declaration splices, declaration quasiquoters
do not cause a break. These quasiquoters are expanded before
the rest of the declaration group is processed, and the
declarations they generate are merged into the surrounding
declaration group. Consequently, the type environment seen
by <literal>reify</literal> from a declaration quasiquoter
will not include anything from the quasiquoter's declaration
group.
</para>
<para>
Concretely, consider the following code
<programlisting>
......@@ -9876,6 +9887,8 @@ module M where
f x = x
$(th1 4)
h y = k y y $(blah1)
[qq|blah|]
k x y = x + y
$(th2 10)
w z = $(blah2)
</programlisting>
......@@ -9918,6 +9931,23 @@ module M where
as the splice <literal>$(th2...)</literal>.
</para>
</listitem>
<listitem>
<para>
The body of <literal>h</literal> <emphasis>is</emphasis>
able to refer to the function <literal>k</literal>
appearing on the other side of the declaration
quasiquoter, as quasiquoters never cause a declaration
group to be broken up.
</para>
<para>
A <literal>reify</literal> inside the
<literal>qq</literal> quasiquoter would be able to see
the definition of <literal>f</literal> from the
preceding declaration group, but not the definitions of
<literal>h</literal> or <literal>k</literal>, or any
definitions from subsequent declaration groups.
</para>
</listitem>
</orderedlist>
</para>
</listitem>
......@@ -10220,6 +10250,11 @@ A quasi-quote is expanded by applying the appropriate parser to the string
enclosed by the Oxford brackets. The context of the quasi-quote (expression, pattern,
type, declaration) determines which of the parsers is called.
</para></listitem>
<listitem><para>
Unlike normal declaration splices of the form <literal>$(...)</literal>,
declaration quasi-quotes do not cause a declaration group break. See
<xref linkend="th-syntax"/> for more information.
</para></listitem>
</itemizedlist>
</para>
<para>
......
......@@ -2,7 +2,6 @@ test('qq007',
[when(fast(), skip),
extra_clean(['QQ.hi', 'QQ.o', 'Test.hi', 'Test.o']),
pre_cmd('$MAKE -s --no-print-directory TH_QQ'),
expect_broken(10047),
],
multimod_compile,
['Test', '-v0'])
......@@ -2,7 +2,6 @@ test('qq008',
[when(fast(), skip),
extra_clean(['QQ.hi', 'QQ.o', 'Test.hi', 'Test.o']),
pre_cmd('$MAKE -s --no-print-directory TH_QQ'),
expect_broken(10047),
],
multimod_compile,
['Test', '-v0'])
TOP=../../..
include $(TOP)/mk/boilerplate.mk
include $(TOP)/mk/test.mk
.PHONY: TH_QQ
TH_QQ:
ifeq "$(GhcDynamic)" "YES"
'$(TEST_HC)' $(TEST_HC_OPTS) -c QQ.hs -dynamic -osuf dyn_o -hisuf dyn_hi
else
'$(TEST_HC)' $(TEST_HC_OPTS) -c QQ.hs
endif
{-# LANGUAGE TemplateHaskell #-}
module QQ where
import Language.Haskell.TH.Quote
import Language.Haskell.TH.Syntax
import Language.Haskell.TH
pq = QuasiQuoter { quoteDec = \_ -> return [sig],
quoteType = \_ -> undefined,
quoteExp = \_ -> undefined,
quotePat = \_ -> undefined }
sig = SigD (mkName "f") (ArrowT `AppT` int `AppT` int)
int = ConT (mkName "Int")
{-# LANGUAGE QuasiQuotes #-}
module Test where
import QQ
f' = f . (+ 1)
[pq| foo |] -- Expands to f :: Int -> Int
f x = x + 1
test('qq009',
[when(fast(), skip),
extra_clean(['QQ.hi', 'QQ.o', 'Test.hi', 'Test.o']),
pre_cmd('$MAKE -s --no-print-directory TH_QQ'),
],
multimod_compile,
['Test', '-v0'])
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment