[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 4 commits: configure: Allow use of LLVM 20
by Marge Bot (@marge-bot) 18 Aug '25
by Marge Bot (@marge-bot) 18 Aug '25
18 Aug '25
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
ca03226d by Ben Gamari at 2025-08-18T13:43:20+00:00
configure: Allow use of LLVM 20
- - - - -
08bf0694 by Cheng Shao at 2025-08-18T15:02:06-04:00
compiler: use `UniqMap` instead of `Map` for `BCEnv` in bytecode compiler
The bytecode compiler maintains a `BCEnv` which was previously `Map Id
StackDepth`. Given `Id` is `Uniquable`, we might as well use `UniqMap`
here as a more efficient data structure, hence this patch.
Co-authored-by: Codex <codex(a)openai.com>
- - - - -
9495d735 by fendor at 2025-08-18T15:02:07-04:00
rts: Strip lower three bits when hashing Word instead of lower eight bits
- - - - -
78b13403 by Cheng Shao at 2025-08-18T15:02:08-04:00
libffi: update to 3.5.2
Bumps libffi submodule.
- - - - -
4 changed files:
- compiler/GHC/StgToByteCode.hs
- configure.ac
- libffi-tarballs
- rts/Hash.c
Changes:
=====================================
compiler/GHC/StgToByteCode.hs
=====================================
@@ -84,11 +84,11 @@ import Data.Coerce (coerce)
#if MIN_VERSION_rts(1,0,3)
import qualified Data.ByteString.Char8 as BS
#endif
-import Data.Map (Map)
import Data.IntMap (IntMap)
import qualified Data.Map as Map
import qualified Data.IntMap as IntMap
-import qualified GHC.Data.FiniteMap as Map
+import GHC.Types.Unique.Map (UniqMap)
+import qualified GHC.Types.Unique.Map as UniqMap
import Data.Ord
import Data.Either ( partitionEithers )
@@ -209,7 +209,7 @@ type StackDepth = ByteOff
-- | Maps Ids to their stack depth. This allows us to avoid having to mess with
-- it after each push/pop.
-type BCEnv = Map Id StackDepth -- To find vars on the stack
+type BCEnv = UniqMap Id StackDepth -- To find vars on the stack
{-
ppBCEnv :: BCEnv -> SDoc
@@ -379,7 +379,7 @@ schemeR_wrk fvs nm original_body (args, body)
sum_szsb_args = sum szsb_args
-- Make a stack offset for each argument or free var -- they should
-- appear contiguous in the stack, in order.
- p_init = Map.fromList (zip all_args (mkStackOffsets 0 szsb_args))
+ p_init = UniqMap.listToUniqMap (zip all_args (mkStackOffsets 0 szsb_args))
-- make the arg bitmap
bits = argBits platform (reverse (map (idArgRep platform) all_args))
@@ -442,7 +442,7 @@ fvsToEnv :: BCEnv -> CgStgRhs -> [Id]
-- it, have to agree about this layout
fvsToEnv p rhs = [v | v <- dVarSetElems $ freeVarsOfRhs rhs,
- v `Map.member` p]
+ v `UniqMap.elemUniqMap` p]
-- -----------------------------------------------------------------------------
-- schemeE
@@ -533,7 +533,7 @@ schemeE d s p (StgLet _xlet
alloc_code <- mkConAppCode d s p data_con args
platform <- targetPlatform <$> getDynFlags
let !d2 = d + wordSize platform
- body_code <- schemeE d2 s (Map.insert x d2 p) body
+ body_code <- schemeE d2 s (UniqMap.addToUniqMap p x d2) body
return (alloc_code `appOL` body_code)
-- General case for let. Generates correct, if inefficient, code in
-- all situations.
@@ -557,7 +557,7 @@ schemeE d s p (StgLet _ext binds body) = do
-- after the closures have been allocated in the heap (but not
-- filled in), and pointers to them parked on the stack.
offsets = mkStackOffsets d (genericReplicate n_binds (wordSize platform))
- p' = Map.insertList (zipEqual xs offsets) p
+ p' = UniqMap.addListToUniqMap p $ zipEqual xs offsets
d' = d + wordsToBytes platform n_binds
-- ToDo: don't build thunks for things with no free variables
@@ -1180,7 +1180,7 @@ doCase d s p scrut bndr alts
-- Env in which to compile the alts, not including
-- any vars bound by the alts themselves
- p_alts = Map.insert bndr d_bndr p
+ p_alts = UniqMap.addToUniqMap p bndr d_bndr
bndr_ty = idType bndr
isAlgCase = isAlgType bndr_ty
@@ -1208,12 +1208,11 @@ doCase d s p scrut bndr alts
stack_bot = d_alts
- p' = Map.insertList
+ p' = UniqMap.addListToUniqMap p_alts
[ (arg, tuple_start -
wordsToBytes platform (nativeCallSize call_info) +
offset)
| (NonVoid arg, offset) <- args_offsets]
- p_alts
in do
rhs_code <- schemeE stack_bot s p' rhs
return (NoDiscr, rhs_code)
@@ -1227,10 +1226,9 @@ doCase d s p scrut bndr alts
stack_bot = d_alts + wordsToBytes platform size
-- convert offsets from Sp into offsets into the virtual stack
- p' = Map.insertList
+ p' = UniqMap.addListToUniqMap p_alts
[ (arg, stack_bot - ByteOff offset)
| (NonVoid arg, offset) <- args_offsets ]
- p_alts
in do
massert isAlgCase
@@ -1312,12 +1310,13 @@ doCase d s p scrut bndr alts
-- NB: unboxed tuple cases bind the scrut binder to the same offset
-- as one of the alt binders, so we have to remove any duplicates here:
-- 'toAscList' takes care of sorting the result, which was previously done after the application of 'filter'.
- rel_slots = IntSet.toAscList $ IntSet.fromList $ Map.elems $ Map.mapMaybeWithKey spread p
- spread id offset | isUnboxedTupleType (idType id) ||
- isUnboxedSumType (idType id) = Nothing
- | isFollowableArg (idArgRep platform id) = Just (fromIntegral rel_offset)
- | otherwise = Nothing
- where rel_offset = bytesToWords platform (d - offset)
+ rel_slots = IntSet.toAscList $ UniqMap.nonDetFoldUniqMap go IntSet.empty p
+ go (var, offset) !acc
+ | isUnboxedTupleType (idType var) || isUnboxedSumType (idType var)
+ = acc
+ | isFollowableArg (idArgRep platform var)
+ = fromIntegral (bytesToWords platform (d - offset)) `IntSet.insert` acc
+ | otherwise = acc
bitmap = intsToReverseBitmap platform bitmap_size' pointers
@@ -2546,7 +2545,7 @@ instance Outputable Discr where
lookupBCEnv_maybe :: Id -> BCEnv -> Maybe ByteOff
-lookupBCEnv_maybe = Map.lookup
+lookupBCEnv_maybe v env = UniqMap.lookupUniqMap env v
idSizeW :: Platform -> Id -> WordOff
idSizeW platform = WordOff . argRepSizeW platform . idArgRep platform
=====================================
configure.ac
=====================================
@@ -536,7 +536,7 @@ AC_SUBST(InstallNameToolCmd)
# versions of LLVM simultaneously, but that stopped working around
# 3.5/3.6 release of LLVM.
LlvmMinVersion=13 # inclusive
-LlvmMaxVersion=20 # not inclusive
+LlvmMaxVersion=21 # not inclusive
AC_SUBST([LlvmMinVersion])
AC_SUBST([LlvmMaxVersion])
=====================================
libffi-tarballs
=====================================
@@ -1 +1 @@
-Subproject commit a5480d7e7f86a9bb5b44dd1156a92f69f7c185ec
+Subproject commit 7c51059557b68d29820a0a87cebfa6fe73c8adf5
=====================================
rts/Hash.c
=====================================
@@ -81,7 +81,7 @@ hashWord(const HashTable *table, StgWord key)
int bucket;
/* Strip the boring zero bits */
- key >>= sizeof(StgWord);
+ key /= sizeof(StgWord);
/* Mod the size of the hash table (a power of 2) */
bucket = key & table->mask1;
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/c5ff559181f877c6d8bc0d2848be1b…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/c5ff559181f877c6d8bc0d2848be1b…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/fendor/bump-bootstrap-ci-version] 2 commits: Bump dependencies of hadrian-bootstrap-gen to use GHC 9.6.7
by Hannes Siebenhandl (@fendor) 18 Aug '25
by Hannes Siebenhandl (@fendor) 18 Aug '25
18 Aug '25
Hannes Siebenhandl pushed to branch wip/fendor/bump-bootstrap-ci-version at Glasgow Haskell Compiler / GHC
Commits:
467eab9a by fendor at 2025-08-18T20:29:58+02:00
Bump dependencies of hadrian-bootstrap-gen to use GHC 9.6.7
- - - - -
7cd0dbc3 by fendor at 2025-08-18T20:29:58+02:00
Bump required GHC version for test-bootstrap jobs to 9.10.1
Include test-bootstrap job for GHC 9.12.2.
Update hadrian bootstrap plans use GHC 9.10 and 9.12
Remove older GHC bootstrap configurations.
We require at least GHC 9.10.1 to build GHC.
Adds plans for:
* 9.10.1
* 9.10.2
* 9.12.1
* 9.12.2
- - - - -
22 changed files:
- .gitlab-ci.yml
- hadrian/bootstrap/generate_bootstrap_plans
- hadrian/bootstrap/hadrian-bootstrap-gen.cabal
- hadrian/bootstrap/plan-9_10_1.json
- hadrian/bootstrap/plan-9_6_5.json → hadrian/bootstrap/plan-9_10_2.json
- hadrian/bootstrap/plan-9_6_6.json → hadrian/bootstrap/plan-9_12_1.json
- hadrian/bootstrap/plan-9_6_4.json → hadrian/bootstrap/plan-9_12_2.json
- − hadrian/bootstrap/plan-9_6_1.json
- − hadrian/bootstrap/plan-9_6_2.json
- − hadrian/bootstrap/plan-9_6_3.json
- − hadrian/bootstrap/plan-9_8_1.json
- − hadrian/bootstrap/plan-9_8_2.json
- hadrian/bootstrap/plan-bootstrap-9_10_1.json
- hadrian/bootstrap/plan-bootstrap-9_6_5.json → hadrian/bootstrap/plan-bootstrap-9_10_2.json
- hadrian/bootstrap/plan-bootstrap-9_6_6.json → hadrian/bootstrap/plan-bootstrap-9_12_1.json
- hadrian/bootstrap/plan-bootstrap-9_8_1.json → hadrian/bootstrap/plan-bootstrap-9_12_2.json
- − hadrian/bootstrap/plan-bootstrap-9_6_1.json
- − hadrian/bootstrap/plan-bootstrap-9_6_2.json
- − hadrian/bootstrap/plan-bootstrap-9_6_3.json
- − hadrian/bootstrap/plan-bootstrap-9_6_4.json
- − hadrian/bootstrap/plan-bootstrap-9_8_2.json
- hadrian/bootstrap/src/Main.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/20f87cee5bbe0c1ff77864a150296e…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/20f87cee5bbe0c1ff77864a150296e…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
18 Aug '25
recursion-ninja pushed new branch wip/fix-25664 at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/wip/fix-25664
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/backports-9.14] users-guide: Release notes formatting wibbles
by Ben Gamari (@bgamari) 18 Aug '25
by Ben Gamari (@bgamari) 18 Aug '25
18 Aug '25
Ben Gamari pushed to branch wip/backports-9.14 at Glasgow Haskell Compiler / GHC
Commits:
4a8df35b by Ben Gamari at 2025-08-18T12:38:39-04:00
users-guide: Release notes formatting wibbles
- - - - -
1 changed file:
- docs/users_guide/9.14.1-notes.rst
Changes:
=====================================
docs/users_guide/9.14.1-notes.rst
=====================================
@@ -104,7 +104,7 @@ Compiler
- Polymorphic specialisation has been reenabled by default in optimisation levels 1 and higher (:ghc-ticket:`23559`)
-- An improved error message is introduced to refer users to the heap-controlling flags of the RTS when there is a heap overflow during compilation. (#25198)
+- An improved error message is introduced to refer users to the heap-controlling flags of the RTS when there is a heap overflow during compilation. (:ghc-ticket:`25198`)
- The kind checker now does a better job of finding type family instances for
use in the kinds of other declarations in the same module. This fixes a number
@@ -118,14 +118,14 @@ Compiler
subordinate import lists (:ghc-ticket:`22581`).
- A new flag, :ghc-flag:`-Wuseless-specialisations`, controls warnings emitted when GHC
- determines that a SPECIALISE pragma would have no effect.
+ determines that a ``SPECIALISE`` pragma would have no effect.
-- A new flag, :ghc-flag:`-Wrule-lhs-equalities`, controls warnings emitted for RULES
+- A new flag, :ghc-flag:`-Wrule-lhs-equalities`, controls warnings emitted for ``RULES``
whose left-hand side attempts to quantify over equality constraints that
previous GHC versions accepted quantifying over. GHC will now drop such RULES,
emitting a warning message controlled by this flag.
- This warning is intended to give visibility to the fact that the RULES that
+ This warning is intended to give visibility to the fact that the ``RULES`` that
previous GHC versions generated in such circumstances could never fire.
- A new flag, :ghc-flag:`-Wunusable-unpack-pragmas`, controls warnings emitted
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/4a8df35bf60e46affe13dbef3637a6c…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/4a8df35bf60e46affe13dbef3637a6c…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/ncg-loopinfo-noop] compiler: use zero cost coerce in GHC.CmmToAsm.CFG.loopInfo
by Cheng Shao (@TerrorJack) 18 Aug '25
by Cheng Shao (@TerrorJack) 18 Aug '25
18 Aug '25
Cheng Shao pushed to branch wip/ncg-loopinfo-noop at Glasgow Haskell Compiler / GHC
Commits:
52225c88 by Cheng Shao at 2025-08-18T18:23:35+02:00
compiler: use zero cost coerce in GHC.CmmToAsm.CFG.loopInfo
This patch refactors GHC.CmmToAsm.CFG.loopInfo to use zero cost coerce
and thus addresses the TODO. For coerce to work, constructors of
Label/LabelMap/LabelSet from GHC.Cmm.Dataflow.Label are exposed,
though I believe it's a worthy tradeoff to avoid unnecessary runtime
cost without using unsafeCoerce, since the latter could be a landmine
for future refactoring.
Co-authored-by: Codex <codex(a)openai.com>
- - - - -
2 changed files:
- compiler/GHC/Cmm/Dataflow/Label.hs
- compiler/GHC/CmmToAsm/CFG.hs
Changes:
=====================================
compiler/GHC/Cmm/Dataflow/Label.hs
=====================================
@@ -7,9 +7,9 @@
{-# OPTIONS_GHC -Wno-unused-top-binds #-}
module GHC.Cmm.Dataflow.Label
- ( Label
- , LabelMap
- , LabelSet
+ ( Label(..)
+ , LabelMap(..)
+ , LabelSet(..)
, FactBase
, lookupFact
, mkHooplLabel
=====================================
compiler/GHC/CmmToAsm/CFG.hs
=====================================
@@ -56,22 +56,18 @@ import GHC.Utils.Misc
import GHC.Data.Graph.Directed
import GHC.Data.Maybe
-import GHC.Types.Unique
import qualified GHC.CmmToAsm.CFG.Dominators as Dom
import GHC.CmmToAsm.CFG.Weight
-import GHC.Data.Word64Map.Strict (Word64Map)
-import GHC.Data.Word64Set (Word64Set)
import Data.IntMap.Strict (IntMap)
import Data.IntSet (IntSet)
import qualified Data.IntMap.Strict as IM
-import qualified GHC.Data.Word64Map.Strict as WM
import qualified Data.Map as M
import qualified Data.IntSet as IS
-import qualified GHC.Data.Word64Set as WS
import qualified Data.Set as S
import Data.Tree
import Data.Bifunctor
+import Data.Coerce
import GHC.Utils.Outputable
import GHC.Utils.Panic
@@ -92,7 +88,6 @@ import Data.Array.Base (unsafeRead, unsafeWrite)
import Control.Monad
import GHC.Data.UnionFind
-import Data.Word
type Prob = Double
@@ -849,10 +844,8 @@ loopInfo cfg root = LoopInfo { liBackEdges = backEdges
fmap (setFromList . mapKeys ) cfg :: LabelMap LabelSet
- --TODO - This should be a no op: Export constructors? Use unsafeCoerce? ...
- rooted = ( fromBlockId root
- , toWord64Map $ fmap toWord64Set graph) :: (Word64, Word64Map Word64Set)
- tree = fmap toBlockId $ Dom.domTree rooted :: Tree BlockId
+ rooted = coerce (root, graph)
+ tree = coerce (Dom.domTree rooted) :: Tree BlockId
-- Map from Nodes to their dominators
domMap :: LabelMap LabelSet
@@ -898,11 +891,6 @@ loopInfo cfg root = LoopInfo { liBackEdges = backEdges
loopCount n = length $ nub . map fst . filter (setMember n . snd) $ bodies
in map (\n -> (n, loopCount n)) $ nodes :: [(BlockId, Int)]
- toWord64Set :: LabelSet -> Word64Set
- toWord64Set s = WS.fromList . map fromBlockId . setElems $ s
- toWord64Map :: LabelMap a -> Word64Map a
- toWord64Map m = WM.fromList $ map (\(x,y) -> (fromBlockId x,y)) $ mapToList m
-
mkDomMap :: Tree BlockId -> LabelMap LabelSet
mkDomMap root = mapFromList $ go setEmpty root
where
@@ -916,12 +904,6 @@ loopInfo cfg root = LoopInfo { liBackEdges = backEdges
(\n -> go (setInsert (rootLabel n) parents) n)
leaves
- fromBlockId :: BlockId -> Word64
- fromBlockId = getKey . getUnique
-
- toBlockId :: Word64 -> BlockId
- toBlockId = mkBlockId . mkUniqueGrimily
-
-- We make the CFG a Hoopl Graph, so we can reuse revPostOrder.
newtype BlockNode (e :: Extensibility) (x :: Extensibility) = BN (BlockId,[BlockId])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/52225c8817e5d6a841d1d86e4f35ed0…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/52225c8817e5d6a841d1d86e4f35ed0…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
18 Aug '25
Cheng Shao pushed new branch wip/ncg-loopinfo-noop at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/wip/ncg-loopinfo-noop
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 4 commits: Resolving issues #20645 and #26109
by Marge Bot (@marge-bot) 18 Aug '25
by Marge Bot (@marge-bot) 18 Aug '25
18 Aug '25
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
706d33e3 by Recursion Ninja at 2025-08-15T04:12:12-04:00
Resolving issues #20645 and #26109
Correctly sign extending and casting smaller bit width types for LLVM operations:
- bitReverse8#
- bitReverse16#
- bitReverse32#
- byteSwap16#
- byteSwap32#
- pdep8#
- pdep16#
- pext8#
- pext16#
- - - - -
1cdc6f46 by Cheng Shao at 2025-08-15T04:12:56-04:00
hadrian: enforce have_llvm=False for wasm32/js
This patch fixes hadrian to always pass have_llvm=False to the
testsuite driver for wasm32/js targets. These targets don't really
support the LLVM backend, and the optllvm test way doesn't work. We
used to special-case wasm32/js to avoid auto-adding optllvm way in
testsuite/config/ghc, but this is still problematic if someone writes
a new LLVM-related test and uses something like when(have_llvm(),
extra_ways(["optllvm"])). So better just enforce have_llvm=False for
these targets here.
- - - - -
5df0d908 by Cheng Shao at 2025-08-18T12:00:36-04:00
compiler: use `UniqMap` instead of `Map` for `BCEnv` in bytecode compiler
The bytecode compiler maintains a `BCEnv` which was previously `Map Id
StackDepth`. Given `Id` is `Uniquable`, we might as well use `UniqMap`
here as a more efficient data structure, hence this patch.
Co-authored-by: Codex <codex(a)openai.com>
- - - - -
c5ff5591 by Cheng Shao at 2025-08-18T12:00:37-04:00
libffi: update to 3.5.2
Bumps libffi submodule.
- - - - -
17 changed files:
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/CmmToLlvm/CodeGen.hs
- compiler/GHC/StgToByteCode.hs
- hadrian/src/Settings/Builders/RunTest.hs
- libffi-tarballs
- libraries/ghc-internal/cbits/pdep.c
- libraries/ghc-internal/cbits/pext.c
- testsuite/config/ghc
- + testsuite/tests/llvm/should_run/T20645.hs
- + testsuite/tests/llvm/should_run/T20645.stdout
- testsuite/tests/llvm/should_run/all.T
- testsuite/tests/numeric/should_run/foundation.hs
- utils/genprimopcode/Lexer.x
- utils/genprimopcode/Main.hs
- utils/genprimopcode/Parser.y
- utils/genprimopcode/ParserM.hs
- utils/genprimopcode/Syntax.hs
Changes:
=====================================
compiler/GHC/Builtin/primops.txt.pp
=====================================
@@ -148,6 +148,7 @@ defaults
vector = []
deprecated_msg = {} -- A non-empty message indicates deprecation
div_like = False -- Second argument expected to be non zero - used for tests
+ defined_bits = Nothing -- The number of bits the operation is defined for (if not all bits)
-- Note [When do out-of-line primops go in primops.txt.pp]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1065,8 +1066,10 @@ primop CtzOp "ctz#" GenPrimOp Word# -> Word#
primop BSwap16Op "byteSwap16#" GenPrimOp Word# -> Word#
{Swap bytes in the lower 16 bits of a word. The higher bytes are undefined. }
+ with defined_bits = 16
primop BSwap32Op "byteSwap32#" GenPrimOp Word# -> Word#
{Swap bytes in the lower 32 bits of a word. The higher bytes are undefined. }
+ with defined_bits = 32
primop BSwap64Op "byteSwap64#" GenPrimOp Word64# -> Word64#
{Swap bytes in a 64 bits of a word.}
primop BSwapOp "byteSwap#" GenPrimOp Word# -> Word#
@@ -1074,10 +1077,13 @@ primop BSwapOp "byteSwap#" GenPrimOp Word# -> Word#
primop BRev8Op "bitReverse8#" GenPrimOp Word# -> Word#
{Reverse the order of the bits in a 8-bit word.}
+ with defined_bits = 8
primop BRev16Op "bitReverse16#" GenPrimOp Word# -> Word#
{Reverse the order of the bits in a 16-bit word.}
+ with defined_bits = 16
primop BRev32Op "bitReverse32#" GenPrimOp Word# -> Word#
{Reverse the order of the bits in a 32-bit word.}
+ with defined_bits = 32
primop BRev64Op "bitReverse64#" GenPrimOp Word64# -> Word64#
{Reverse the order of the bits in a 64-bit word.}
primop BRevOp "bitReverse#" GenPrimOp Word# -> Word#
=====================================
compiler/GHC/CmmToLlvm/CodeGen.hs
=====================================
@@ -230,23 +230,22 @@ genCall t@(PrimTarget (MO_Prefetch_Data localityInt)) [] args
statement $ Expr $ Call StdCall fptr (argVars' ++ argSuffix) []
| otherwise = panic $ "prefetch locality level integer must be between 0 and 3, given: " ++ (show localityInt)
--- Handle PopCnt, Clz, Ctz, and BSwap that need to only convert arg
--- and return types
-genCall t@(PrimTarget (MO_PopCnt w)) dsts args =
- genCallSimpleCast w t dsts args
-
-genCall t@(PrimTarget (MO_Pdep w)) dsts args =
- genCallSimpleCast2 w t dsts args
-genCall t@(PrimTarget (MO_Pext w)) dsts args =
- genCallSimpleCast2 w t dsts args
-genCall t@(PrimTarget (MO_Clz w)) dsts args =
- genCallSimpleCast w t dsts args
-genCall t@(PrimTarget (MO_Ctz w)) dsts args =
- genCallSimpleCast w t dsts args
-genCall t@(PrimTarget (MO_BSwap w)) dsts args =
- genCallSimpleCast w t dsts args
-genCall t@(PrimTarget (MO_BRev w)) dsts args =
- genCallSimpleCast w t dsts args
+-- Handle Clz, Ctz, BRev, BSwap, Pdep, Pext, and PopCnt that need to only
+-- convert arg and return types
+genCall (PrimTarget op@(MO_Clz w)) [dst] args =
+ genCallSimpleCast w op dst args
+genCall (PrimTarget op@(MO_Ctz w)) [dst] args =
+ genCallSimpleCast w op dst args
+genCall (PrimTarget op@(MO_BRev w)) [dst] args =
+ genCallSimpleCast w op dst args
+genCall (PrimTarget op@(MO_BSwap w)) [dst] args =
+ genCallSimpleCast w op dst args
+genCall (PrimTarget op@(MO_Pdep w)) [dst] args =
+ genCallSimpleCast w op dst args
+genCall (PrimTarget op@(MO_Pext w)) [dst] args =
+ genCallSimpleCast w op dst args
+genCall (PrimTarget op@(MO_PopCnt w)) [dst] args =
+ genCallSimpleCast w op dst args
genCall (PrimTarget (MO_AtomicRMW width amop)) [dst] [addr, n] = runStmtsDecls $ do
addrVar <- exprToVarW addr
@@ -640,63 +639,28 @@ genCallExtract _ _ _ _ =
-- since GHC only really has i32 and i64 types and things like Word8 are backed
-- by an i32 and just present a logical i8 range. So we must handle conversions
-- from i32 to i8 explicitly as LLVM is strict about types.
-genCallSimpleCast :: Width -> ForeignTarget -> [CmmFormal] -> [CmmActual]
- -> LlvmM StmtData
-genCallSimpleCast w t@(PrimTarget op) [dst] args = do
- let width = widthToLlvmInt w
- dstTy = cmmToLlvmType $ localRegType dst
-
- fname <- cmmPrimOpFunctions op
- (fptr, _, top3) <- getInstrinct fname width [width]
-
- (dstV, _dst_ty) <- getCmmReg (CmmLocal dst)
-
- let (_, arg_hints) = foreignTargetHints t
- let args_hints = zip args arg_hints
- (argsV, stmts2, top2) <- arg_vars args_hints ([], nilOL, [])
- (argsV', stmts4) <- castVars Signed $ zip argsV [width]
- (retV, s1) <- doExpr width $ Call StdCall fptr argsV' []
- (retVs', stmts5) <- castVars (cmmPrimOpRetValSignage op) [(retV,dstTy)]
- let retV' = singletonPanic "genCallSimpleCast" retVs'
- let s2 = Store retV' dstV Nothing []
-
- let stmts = stmts2 `appOL` stmts4 `snocOL`
- s1 `appOL` stmts5 `snocOL` s2
- return (stmts, top2 ++ top3)
-genCallSimpleCast _ _ dsts _ =
- panic ("genCallSimpleCast: " ++ show (length dsts) ++ " dsts")
-
--- Handle simple function call that only need simple type casting, of the form:
--- truncate arg >>= \a -> call(a) >>= zext
---
--- since GHC only really has i32 and i64 types and things like Word8 are backed
--- by an i32 and just present a logical i8 range. So we must handle conversions
--- from i32 to i8 explicitly as LLVM is strict about types.
-genCallSimpleCast2 :: Width -> ForeignTarget -> [CmmFormal] -> [CmmActual]
- -> LlvmM StmtData
-genCallSimpleCast2 w t@(PrimTarget op) [dst] args = do
- let width = widthToLlvmInt w
- dstTy = cmmToLlvmType $ localRegType dst
-
- fname <- cmmPrimOpFunctions op
- (fptr, _, top3) <- getInstrinct fname width (const width <$> args)
-
- (dstV, _dst_ty) <- getCmmReg (CmmLocal dst)
-
- let (_, arg_hints) = foreignTargetHints t
- let args_hints = zip args arg_hints
- (argsV, stmts2, top2) <- arg_vars args_hints ([], nilOL, [])
- (argsV', stmts4) <- castVars Signed $ zip argsV (const width <$> argsV)
- (retV, s1) <- doExpr width $ Call StdCall fptr argsV' []
- (retVs', stmts5) <- castVars (cmmPrimOpRetValSignage op) [(retV,dstTy)]
- let retV' = singletonPanic "genCallSimpleCast2" retVs'
- let s2 = Store retV' dstV Nothing []
+genCallSimpleCast :: Width -> CallishMachOp -> CmmFormal -> [CmmActual]
+ -> LlvmM StmtData
+genCallSimpleCast specW op dst args = do
+ let width = widthToLlvmInt specW
+ argsW = const width <$> args
+ dstType = cmmToLlvmType $ localRegType dst
+ signage = cmmPrimOpRetValSignage op
+
+ fname <- cmmPrimOpFunctions op
+ (fptr, _, top3) <- getInstrinct fname width argsW
+ (dstV, _dst_ty) <- getCmmReg (CmmLocal dst)
+ let (_, arg_hints) = foreignTargetHints $ PrimTarget op
+ let args_hints = zip args arg_hints
+ (argsV, stmts2, top2) <- arg_vars args_hints ([], nilOL, [])
+ (argsV', stmts4) <- castVars signage $ zip argsV argsW
+ (retV, s1) <- doExpr width $ Call StdCall fptr argsV' []
+ (retV', stmts5) <- castVar signage retV dstType
+ let s2 = Store retV' dstV Nothing []
let stmts = stmts2 `appOL` stmts4 `snocOL`
- s1 `appOL` stmts5 `snocOL` s2
+ s1 `snocOL` stmts5 `snocOL` s2
return (stmts, top2 ++ top3)
-genCallSimpleCast2 _ _ dsts _ =
- panic ("genCallSimpleCast2: " ++ show (length dsts) ++ " dsts")
-- | Create a function pointer from a target.
getFunPtrW :: (LMString -> LlvmType) -> ForeignTarget
@@ -811,11 +775,47 @@ castVar signage v t | getVarType v == t
Signed -> LM_Sext
Unsigned -> LM_Zext
-
cmmPrimOpRetValSignage :: CallishMachOp -> Signage
cmmPrimOpRetValSignage mop = case mop of
- MO_Pdep _ -> Unsigned
- MO_Pext _ -> Unsigned
+ -- Some bit-wise operations /must/ always treat the input and output values
+ -- as 'Unsigned' in order to return the expected result values when pre/post-
+ -- operation bit-width truncation and/or extension occur. For example,
+ -- consider the Bit-Reverse operation:
+ --
+ -- If the result of a Bit-Reverse is treated as signed,
+ -- an positive input can result in an negative output, i.e.:
+ --
+ -- identity(0x03) = 0x03 = 00000011
+ -- breverse(0x03) = 0xC0 = 11000000
+ --
+ -- Now if an extension is performed after the operation to
+ -- promote a smaller bit-width value into a larger bit-width
+ -- type, it is expected that the /bit-wise/ operations will
+ -- not be treated /numerically/ as signed.
+ --
+ -- To illustrate the difference, consider how a signed extension
+ -- for the type i16 to i32 differs for out values above:
+ -- ext_zeroed(i32, breverse(0x03)) = 0x00C0 = 0000000011000000
+ -- ext_signed(i32, breverse(0x03)) = 0xFFC0 = 1111111111000000
+ --
+ -- Here we can see that the former output is the expected result
+ -- of a bit-wise operation which needs to be promoted to a larger
+ -- bit-width type. The latter output is not desirable when we must
+ -- constraining a value into a range of i16 within an i32 type.
+ --
+ -- Hence we always treat the "signage" as unsigned for Bit-Reverse!
+ --
+ -- The same reasoning applied to Bit-Reverse above applies to the other
+ -- bit-wise operations; do not sign extend a possibly negated number!
+ MO_BRev _ -> Unsigned
+ MO_BSwap _ -> Unsigned
+ MO_Clz _ -> Unsigned
+ MO_Ctz _ -> Unsigned
+ MO_Pdep _ -> Unsigned
+ MO_Pext _ -> Unsigned
+ MO_PopCnt _ -> Unsigned
+
+ -- All other cases, default to preserving the numeric sign when extending.
_ -> Signed
-- | Decide what C function to use to implement a CallishMachOp
=====================================
compiler/GHC/StgToByteCode.hs
=====================================
@@ -84,11 +84,11 @@ import Data.Coerce (coerce)
#if MIN_VERSION_rts(1,0,3)
import qualified Data.ByteString.Char8 as BS
#endif
-import Data.Map (Map)
import Data.IntMap (IntMap)
import qualified Data.Map as Map
import qualified Data.IntMap as IntMap
-import qualified GHC.Data.FiniteMap as Map
+import GHC.Types.Unique.Map (UniqMap)
+import qualified GHC.Types.Unique.Map as UniqMap
import Data.Ord
import Data.Either ( partitionEithers )
@@ -209,7 +209,7 @@ type StackDepth = ByteOff
-- | Maps Ids to their stack depth. This allows us to avoid having to mess with
-- it after each push/pop.
-type BCEnv = Map Id StackDepth -- To find vars on the stack
+type BCEnv = UniqMap Id StackDepth -- To find vars on the stack
{-
ppBCEnv :: BCEnv -> SDoc
@@ -379,7 +379,7 @@ schemeR_wrk fvs nm original_body (args, body)
sum_szsb_args = sum szsb_args
-- Make a stack offset for each argument or free var -- they should
-- appear contiguous in the stack, in order.
- p_init = Map.fromList (zip all_args (mkStackOffsets 0 szsb_args))
+ p_init = UniqMap.listToUniqMap (zip all_args (mkStackOffsets 0 szsb_args))
-- make the arg bitmap
bits = argBits platform (reverse (map (idArgRep platform) all_args))
@@ -442,7 +442,7 @@ fvsToEnv :: BCEnv -> CgStgRhs -> [Id]
-- it, have to agree about this layout
fvsToEnv p rhs = [v | v <- dVarSetElems $ freeVarsOfRhs rhs,
- v `Map.member` p]
+ v `UniqMap.elemUniqMap` p]
-- -----------------------------------------------------------------------------
-- schemeE
@@ -533,7 +533,7 @@ schemeE d s p (StgLet _xlet
alloc_code <- mkConAppCode d s p data_con args
platform <- targetPlatform <$> getDynFlags
let !d2 = d + wordSize platform
- body_code <- schemeE d2 s (Map.insert x d2 p) body
+ body_code <- schemeE d2 s (UniqMap.addToUniqMap p x d2) body
return (alloc_code `appOL` body_code)
-- General case for let. Generates correct, if inefficient, code in
-- all situations.
@@ -557,7 +557,7 @@ schemeE d s p (StgLet _ext binds body) = do
-- after the closures have been allocated in the heap (but not
-- filled in), and pointers to them parked on the stack.
offsets = mkStackOffsets d (genericReplicate n_binds (wordSize platform))
- p' = Map.insertList (zipEqual xs offsets) p
+ p' = UniqMap.addListToUniqMap p $ zipEqual xs offsets
d' = d + wordsToBytes platform n_binds
-- ToDo: don't build thunks for things with no free variables
@@ -1180,7 +1180,7 @@ doCase d s p scrut bndr alts
-- Env in which to compile the alts, not including
-- any vars bound by the alts themselves
- p_alts = Map.insert bndr d_bndr p
+ p_alts = UniqMap.addToUniqMap p bndr d_bndr
bndr_ty = idType bndr
isAlgCase = isAlgType bndr_ty
@@ -1208,12 +1208,11 @@ doCase d s p scrut bndr alts
stack_bot = d_alts
- p' = Map.insertList
+ p' = UniqMap.addListToUniqMap p_alts
[ (arg, tuple_start -
wordsToBytes platform (nativeCallSize call_info) +
offset)
| (NonVoid arg, offset) <- args_offsets]
- p_alts
in do
rhs_code <- schemeE stack_bot s p' rhs
return (NoDiscr, rhs_code)
@@ -1227,10 +1226,9 @@ doCase d s p scrut bndr alts
stack_bot = d_alts + wordsToBytes platform size
-- convert offsets from Sp into offsets into the virtual stack
- p' = Map.insertList
+ p' = UniqMap.addListToUniqMap p_alts
[ (arg, stack_bot - ByteOff offset)
| (NonVoid arg, offset) <- args_offsets ]
- p_alts
in do
massert isAlgCase
@@ -1312,12 +1310,13 @@ doCase d s p scrut bndr alts
-- NB: unboxed tuple cases bind the scrut binder to the same offset
-- as one of the alt binders, so we have to remove any duplicates here:
-- 'toAscList' takes care of sorting the result, which was previously done after the application of 'filter'.
- rel_slots = IntSet.toAscList $ IntSet.fromList $ Map.elems $ Map.mapMaybeWithKey spread p
- spread id offset | isUnboxedTupleType (idType id) ||
- isUnboxedSumType (idType id) = Nothing
- | isFollowableArg (idArgRep platform id) = Just (fromIntegral rel_offset)
- | otherwise = Nothing
- where rel_offset = bytesToWords platform (d - offset)
+ rel_slots = IntSet.toAscList $ UniqMap.nonDetFoldUniqMap go IntSet.empty p
+ go (var, offset) !acc
+ | isUnboxedTupleType (idType var) || isUnboxedSumType (idType var)
+ = acc
+ | isFollowableArg (idArgRep platform var)
+ = fromIntegral (bytesToWords platform (d - offset)) `IntSet.insert` acc
+ | otherwise = acc
bitmap = intsToReverseBitmap platform bitmap_size' pointers
@@ -2546,7 +2545,7 @@ instance Outputable Discr where
lookupBCEnv_maybe :: Id -> BCEnv -> Maybe ByteOff
-lookupBCEnv_maybe = Map.lookup
+lookupBCEnv_maybe v env = UniqMap.lookupUniqMap env v
idSizeW :: Platform -> Id -> WordOff
idSizeW platform = WordOff . argRepSizeW platform . idArgRep platform
=====================================
hadrian/src/Settings/Builders/RunTest.hs
=====================================
@@ -86,6 +86,16 @@ data TestCompilerArgs = TestCompilerArgs{
, pkgConfCacheFile :: FilePath }
deriving (Eq, Show)
+-- | Some archs like wasm32/js used to report have_llvm=True because
+-- they are based on LLVM related toolchains like wasi-sdk/emscripten,
+-- but these targets don't really support the LLVM backend, and the
+-- optllvm test way doesn't work. We used to special-case wasm32/js to
+-- avoid auto-adding optllvm way in testsuite/config/ghc, but this is
+-- still problematic if someone writes a new LLVM-related test and
+-- uses something like when(have_llvm(), extra_ways(["optllvm"])). So
+-- better just enforce have_llvm=False for these targets here.
+allowHaveLLVM :: String -> Bool
+allowHaveLLVM = not . (`elem` ["wasm32", "javascript"])
-- | If the tree is in-compiler then we already know how we will build it so
-- don't build anything in order to work out what we will build.
@@ -129,7 +139,7 @@ inTreeCompilerArgs stg = do
llc_cmd <- queryTargetTarget tgtLlc
llvm_as_cmd <- queryTargetTarget tgtLlvmAs
- let have_llvm = all isJust [llc_cmd, llvm_as_cmd]
+ let have_llvm = allowHaveLLVM arch && all isJust [llc_cmd, llvm_as_cmd]
top <- topDirectory
@@ -176,7 +186,7 @@ outOfTreeCompilerArgs = do
let debugged = "debug" `isInfixOf` rtsWay
llc_cmd <- getTestSetting TestLLC
- have_llvm <- liftIO (isJust <$> findExecutable llc_cmd)
+ have_llvm <- (allowHaveLLVM arch &&) <$> liftIO (isJust <$> findExecutable llc_cmd)
profiled <- getBooleanSetting TestGhcProfiled
pkgConfCacheFile <- getTestSetting TestGhcPackageDb <&> (</> "package.cache")
=====================================
libffi-tarballs
=====================================
@@ -1 +1 @@
-Subproject commit a5480d7e7f86a9bb5b44dd1156a92f69f7c185ec
+Subproject commit 7c51059557b68d29820a0a87cebfa6fe73c8adf5
=====================================
libraries/ghc-internal/cbits/pdep.c
=====================================
@@ -24,20 +24,23 @@ hs_pdep64(StgWord64 src, StgWord64 mask)
return result;
}
+// When dealing with values of bit-width shorter than uint64_t, ensure to
+// cast the return value to correctly truncate the undefined upper bits.
+// This is *VERY* important when GHC is using the LLVM backend!
StgWord
hs_pdep32(StgWord src, StgWord mask)
{
- return hs_pdep64(src, mask);
+ return (StgWord) ((StgWord32) hs_pdep64(src, mask));
}
StgWord
hs_pdep16(StgWord src, StgWord mask)
{
- return hs_pdep64(src, mask);
+ return (StgWord) ((StgWord16) hs_pdep64(src, mask));
}
StgWord
hs_pdep8(StgWord src, StgWord mask)
{
- return hs_pdep64(src, mask);
+ return (StgWord) ((StgWord8) hs_pdep64(src, mask));
}
=====================================
libraries/ghc-internal/cbits/pext.c
=====================================
@@ -1,13 +1,13 @@
#include "Rts.h"
#include "MachDeps.h"
-StgWord64
-hs_pext64(StgWord64 src, StgWord64 mask)
+static StgWord64
+hs_pext(const unsigned char bit_width, const StgWord64 src, const StgWord64 mask)
{
uint64_t result = 0;
int offset = 0;
- for (int bit = 0; bit != sizeof(uint64_t) * 8; ++bit) {
+ for (int bit = 0; bit != bit_width; ++bit) {
const uint64_t src_bit = (src >> bit) & 1;
const uint64_t mask_bit = (mask >> bit) & 1;
@@ -20,20 +20,29 @@ hs_pext64(StgWord64 src, StgWord64 mask)
return result;
}
+StgWord64
+hs_pext64(const StgWord64 src, const StgWord64 mask)
+{
+ return hs_pext(64, src, mask);
+}
+
+// When dealing with values of bit-width shorter than uint64_t, ensure to
+// cast the return value to correctly truncate the undefined upper bits.
+// This is *VERY* important when GHC is using the LLVM backend!
StgWord
-hs_pext32(StgWord src, StgWord mask)
+hs_pext32(const StgWord src, const StgWord mask)
{
- return hs_pext64(src, mask);
+ return (StgWord) ((StgWord32) hs_pext(32, src, mask));
}
StgWord
-hs_pext16(StgWord src, StgWord mask)
+hs_pext16(const StgWord src, const StgWord mask)
{
- return hs_pext64(src, mask);
+ return (StgWord) ((StgWord16) hs_pext(16, src, mask));
}
StgWord
-hs_pext8(StgWord src, StgWord mask)
+hs_pext8(const StgWord src, const StgWord mask)
{
- return hs_pext64(src, mask);
+ return (StgWord) ((StgWord8) hs_pext(8, src, mask));
}
=====================================
testsuite/config/ghc
=====================================
@@ -70,7 +70,7 @@ if windows:
config.other_ways += winio_ways
# LLVM
-if not config.unregisterised and not config.arch in {"wasm32", "javascript"} and config.have_llvm:
+if not config.unregisterised and config.have_llvm:
config.compile_ways.append('optllvm')
config.run_ways.append('optllvm')
=====================================
testsuite/tests/llvm/should_run/T20645.hs
=====================================
@@ -0,0 +1,18 @@
+-- Minimal reproducer for https://gitlab.haskell.org/ghc/ghc/-/issues/20645
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE ExtendedLiterals #-}
+import GHC.Exts
+import GHC.Word
+import Numeric (showHex)
+
+opaqueInt8# :: Int8# -> Int8#
+opaqueInt8# x = x
+{-# OPAQUE opaqueInt8# #-}
+
+main :: IO ()
+main = let !x = opaqueInt8# 109#Int8
+ !y = opaqueInt8# 1#Int8
+ in putStrLn $ flip showHex "" (W# ( pext8#
+ (word8ToWord# (int8ToWord8# (0#Int8 `subInt8#` x )))
+ (word8ToWord# (int8ToWord8# (y `subInt8#` 4#Int8)))
+ ))
=====================================
testsuite/tests/llvm/should_run/T20645.stdout
=====================================
@@ -0,0 +1 @@
+49
=====================================
testsuite/tests/llvm/should_run/all.T
=====================================
@@ -17,3 +17,4 @@ test('T22487', [normal, normalise_errmsg_fun(ignore_llvm_and_vortex)], compile_a
test('T22033', [normal, normalise_errmsg_fun(ignore_llvm_and_vortex)], compile_and_run, [''])
test('T25730', [req_c, unless(arch('x86_64'), skip), normalise_errmsg_fun(ignore_llvm_and_vortex)], compile_and_run, ['T25730C.c'])
# T25730C.c contains Intel instrinsics, so only run this test on x86
+test('T20645', [normal, normalise_errmsg_fun(ignore_llvm_and_vortex), when(have_llvm(), extra_ways(["optllvm"]))], compile_and_run, [''])
=====================================
testsuite/tests/numeric/should_run/foundation.hs
=====================================
@@ -24,6 +24,7 @@ module Main
( main
) where
+import Data.Bits (Bits((.&.), bit))
import Data.Word
import Data.Int
import GHC.Natural
@@ -408,6 +409,33 @@ instance TestPrimop (Word# -> Int# -> Word#) where
testPrimop s l r = Property s $ \(uWord -> a1) (uInt -> a2) -> (wWord (l a1 a2)) === wWord (r a1 a2)
-}
+-- | A special data-type for representing functions where,
+-- since only some number of the lower bits are defined,
+-- testing for strict equality in the undefined upper bits is not appropriate!
+-- Without using this data-type, false-positive failures will be reported
+-- when the undefined bit regions do not match, even though the equality of bits
+-- in this undefined region has no bearing on correctness.
+data LowerBitsAreDefined =
+ LowerBitsAreDefined
+ { definedLowerWidth :: Word
+ -- ^ The (strictly-non-negative) number of least-significant bits
+ -- for which the attached function is defined.
+ , undefinedBehavior :: (Word# -> Word#)
+ -- ^ Function with undefined behavior for some of its most significant bits.
+ }
+
+instance TestPrimop LowerBitsAreDefined where
+ testPrimop s l r = Property s $ \ (uWord#-> x0) ->
+ let -- Create a mask to unset all bits in the undefined area,
+ -- leaving set bits only in the area of defined behavior.
+ -- Since the upper bits are undefined,
+ -- if the function defines behavior for the lower N bits,
+ -- then /only/ the lower N bits are preserved,
+ -- and the upper WORDSIZE - N bits are discarded.
+ mask = bit (fromEnum (definedLowerWidth r)) - 1
+ valL = wWord# (undefinedBehavior l x0) .&. mask
+ valR = wWord# (undefinedBehavior r x0) .&. mask
+ in valL === valR
twoNonZero :: (a -> a -> b) -> a -> NonZero a -> b
twoNonZero f x (NonZero y) = f x y
@@ -655,13 +683,13 @@ testPrimops = Group "primop"
, testPrimop "ctz32#" Primop.ctz32# Wrapper.ctz32#
, testPrimop "ctz64#" Primop.ctz64# Wrapper.ctz64#
, testPrimop "ctz#" Primop.ctz# Wrapper.ctz#
- , testPrimop "byteSwap16#" Primop.byteSwap16# Wrapper.byteSwap16#
- , testPrimop "byteSwap32#" Primop.byteSwap32# Wrapper.byteSwap32#
+ , testPrimop "byteSwap16#" (16 `LowerBitsAreDefined` Primop.byteSwap16#) (16 `LowerBitsAreDefined` Wrapper.byteSwap16#)
+ , testPrimop "byteSwap32#" (32 `LowerBitsAreDefined` Primop.byteSwap32#) (32 `LowerBitsAreDefined` Wrapper.byteSwap32#)
, testPrimop "byteSwap64#" Primop.byteSwap64# Wrapper.byteSwap64#
, testPrimop "byteSwap#" Primop.byteSwap# Wrapper.byteSwap#
- , testPrimop "bitReverse8#" Primop.bitReverse8# Wrapper.bitReverse8#
- , testPrimop "bitReverse16#" Primop.bitReverse16# Wrapper.bitReverse16#
- , testPrimop "bitReverse32#" Primop.bitReverse32# Wrapper.bitReverse32#
+ , testPrimop "bitReverse8#" (8 `LowerBitsAreDefined` Primop.bitReverse8#) (8 `LowerBitsAreDefined` Wrapper.bitReverse8#)
+ , testPrimop "bitReverse16#" (16 `LowerBitsAreDefined` Primop.bitReverse16#) (16 `LowerBitsAreDefined` Wrapper.bitReverse16#)
+ , testPrimop "bitReverse32#" (32 `LowerBitsAreDefined` Primop.bitReverse32#) (32 `LowerBitsAreDefined` Wrapper.bitReverse32#)
, testPrimop "bitReverse64#" Primop.bitReverse64# Wrapper.bitReverse64#
, testPrimop "bitReverse#" Primop.bitReverse# Wrapper.bitReverse#
, testPrimop "narrow8Int#" Primop.narrow8Int# Wrapper.narrow8Int#
=====================================
utils/genprimopcode/Lexer.x
=====================================
@@ -56,6 +56,7 @@ words :-
<0> "CanFail" { mkT TCanFail }
<0> "ThrowsException" { mkT TThrowsException }
<0> "ReadWriteEffect" { mkT TReadWriteEffect }
+ <0> "defined_bits" { mkT TDefinedBits }
<0> "can_fail_warning" { mkT TCanFailWarnFlag }
<0> "DoNotWarnCanFail" { mkT TDoNotWarnCanFail }
<0> "WarnIfEffectIsCanFail" { mkT TWarnIfEffectIsCanFail }
=====================================
utils/genprimopcode/Main.hs
=====================================
@@ -10,6 +10,7 @@ module Main where
import Parser
import Syntax
+import Control.Applicative (asum)
import Data.Char
import Data.List (union, intersperse, intercalate, nub, sort)
import Data.Maybe ( catMaybes, mapMaybe )
@@ -116,9 +117,15 @@ desugarVectorSpec i = case vecOptions i of
main :: IO ()
main = getArgs >>= \args ->
if length args /= 1 || head args `notElem` known_args
- then error ("usage: genprimopcode command < primops.txt > ...\n"
+ then error ("Usage: genprimopcode command < primops.txt > ...\n"
++ " where command is one of\n"
++ unlines (map (" "++) known_args)
+ ++ unlines
+ [ ""
+ , "Nota Bene: Be sure to manually run primops.txt through the C Pre-Processor"
+ , " before sending the input stream to STDIN, i.e:"
+ , ""
+ , " cpp -P -w primops.txt | genprimopcode command" ]
)
else
do hSetEncoding stdin utf8 -- The input file is in UTF-8. Set the encoding explicitly.
@@ -312,6 +319,7 @@ gen_hs_source (Info defaults entries) =
opt (OptionVector _) = ""
opt (OptionFixity mf) = "fixity = " ++ show mf
opt (OptionEffect eff) = "effect = " ++ show eff
+ opt (OptionDefinedBits bc) = "defined_bits = " ++ show bc
opt (OptionCanFailWarnFlag wf) = "can_fail_warning = " ++ show wf
hdr s@(Section {}) = sec s
@@ -638,6 +646,7 @@ gen_switch_from_attribs attrib_name fn_name (Info defaults entries)
getAltRhs (OptionVector _) = "True"
getAltRhs (OptionFixity mf) = show mf
getAltRhs (OptionEffect eff) = show eff
+ getAltRhs (OptionDefinedBits bc) = show bc
getAltRhs (OptionCanFailWarnFlag wf) = show wf
mkAlt po
@@ -753,7 +762,12 @@ gen_foundation_tests (Info _ entries)
= let testPrimOpHow = if is_divLikeOp po
then "testPrimopDivLike"
else "testPrimop"
- in Just $ intercalate " " [testPrimOpHow, "\"" ++ poName ++ "\"", wrap "Primop" poName, wrap "Wrapper" poName]
+ qualOp qualification =
+ let qName = wrap qualification poName
+ in case mb_defined_bits po of
+ Nothing -> qName
+ Just bs -> concat ["(", show bs, " `LowerBitsAreDefined` ", qName, ")"]
+ in Just $ intercalate " " [testPrimOpHow, "\"" ++ poName ++ "\"", qualOp "Primop", qualOp "Wrapper"]
| otherwise = Nothing
@@ -771,6 +785,16 @@ gen_foundation_tests (Info _ entries)
divableTyCons = ["Int#", "Word#", "Word8#", "Word16#", "Word32#", "Word64#"
,"Int8#", "Int16#", "Int32#", "Int64#"]
+ mb_defined_bits :: Entry -> Maybe Word
+ mb_defined_bits op@(PrimOpSpec{}) =
+ let opOpts = opts op
+ getDefBits :: Option -> Maybe Word
+ getDefBits (OptionDefinedBits x) = x
+ getDefBits _ = Nothing
+ in asum $ getDefBits <$> opOpts
+ mb_defined_bits _ = Nothing
+
+
------------------------------------------------------------------
-- Create PrimOpInfo text from PrimOpSpecs -----------------------
------------------------------------------------------------------
=====================================
utils/genprimopcode/Parser.y
=====================================
@@ -50,6 +50,7 @@ import AccessOps
CanFail { TCanFail }
ThrowsException { TThrowsException }
ReadWriteEffect { TReadWriteEffect }
+ defined_bits { TDefinedBits }
can_fail_warning { TCanFailWarnFlag }
DoNotWarnCanFail { TDoNotWarnCanFail }
WarnIfEffectIsCanFail { TWarnIfEffectIsCanFail }
@@ -81,13 +82,14 @@ pOptions : pOption pOptions { $1 : $2 }
| {- empty -} { [] }
pOption :: { Option }
-pOption : lowerName '=' false { OptionFalse $1 }
- | lowerName '=' true { OptionTrue $1 }
- | lowerName '=' pStuffBetweenBraces { OptionString $1 $3 }
- | lowerName '=' integer { OptionInteger $1 $3 }
- | vector '=' pVectorTemplate { OptionVector $3 }
- | fixity '=' pInfix { OptionFixity $3 }
- | effect '=' pEffect { OptionEffect $3 }
+pOption : lowerName '=' false { OptionFalse $1 }
+ | lowerName '=' true { OptionTrue $1 }
+ | lowerName '=' pStuffBetweenBraces { OptionString $1 $3 }
+ | lowerName '=' integer { OptionInteger $1 $3 }
+ | vector '=' pVectorTemplate { OptionVector $3 }
+ | fixity '=' pInfix { OptionFixity $3 }
+ | effect '=' pEffect { OptionEffect $3 }
+ | defined_bits '=' pGoodBits { OptionDefinedBits $3 }
| can_fail_warning '=' pPrimOpCanFailWarnFlag { OptionCanFailWarnFlag $3 }
pInfix :: { Maybe Fixity }
@@ -102,6 +104,10 @@ pEffect : NoEffect { NoEffect }
| ThrowsException { ThrowsException }
| ReadWriteEffect { ReadWriteEffect }
+pGoodBits :: { Maybe Word }
+pGoodBits : integer { Just $ toEnum $1 }
+ | nothing { Nothing }
+
pPrimOpCanFailWarnFlag :: { PrimOpCanFailWarnFlag }
pPrimOpCanFailWarnFlag : DoNotWarnCanFail { DoNotWarnCanFail }
| WarnIfEffectIsCanFail { WarnIfEffectIsCanFail }
=====================================
utils/genprimopcode/ParserM.hs
=====================================
@@ -116,6 +116,7 @@ data Token = TEOF
| TCanFail
| TThrowsException
| TReadWriteEffect
+ | TDefinedBits
| TCanFailWarnFlag
| TDoNotWarnCanFail
| TWarnIfEffectIsCanFail
=====================================
utils/genprimopcode/Syntax.hs
=====================================
@@ -76,6 +76,7 @@ data Option
| OptionFixity (Maybe Fixity) -- fixity = infix{,l,r} <int> | Nothing
| OptionEffect PrimOpEffect -- effect = NoEffect | DoNotSpeculate | CanFail | ThrowsException | ReadWriteEffect | FallibleReadWriteEffect
| OptionCanFailWarnFlag PrimOpCanFailWarnFlag -- can_fail_warning = DoNotWarnCanFail | WarnIfEffectIsCanFail | YesWarnCanFail
+ | OptionDefinedBits (Maybe Word) -- defined_bits = Just 16 | Nothing
deriving Show
-- categorises primops
@@ -196,6 +197,7 @@ get_attrib_name (OptionVector _) = "vector"
get_attrib_name (OptionFixity _) = "fixity"
get_attrib_name (OptionEffect _) = "effect"
get_attrib_name (OptionCanFailWarnFlag _) = "can_fail_warning"
+get_attrib_name (OptionDefinedBits _) = "defined_bits"
lookup_attrib :: String -> [Option] -> Maybe Option
lookup_attrib _ [] = Nothing
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/0982b7bbe6912b8673ece2b676b16a…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/0982b7bbe6912b8673ece2b676b16a…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/T26217] 3 commits: ghc-internal: Split out GHC.Internal.TH.Monad from .Syntax
by Teo Camarasu (@teo) 18 Aug '25
by Teo Camarasu (@teo) 18 Aug '25
18 Aug '25
Teo Camarasu pushed to branch wip/T26217 at Glasgow Haskell Compiler / GHC
Commits:
5ea41e1a by Teo Camarasu at 2025-08-18T15:29:36+01:00
ghc-internal: Split out GHC.Internal.TH.Monad from .Syntax
Split the Quasi/Q, etc definition out of GHC.Internal.TH.Syntax
into its own module.
We do this for a few reasons:
- it enables future refactors to speed up compilation of these modules.
- it reduces the size of this very large module.
- it clarifies which modules in the GHC tree depend on the TH monads (Q/Quasi, etc) and
which just care about the syntax tree.
A step towards addressing: #26217
- - - - -
194ea830 by Teo Camarasu at 2025-08-18T15:29:50+01:00
ghc-internal: Move Data instance for TH.Syntax to Data.Data
This means that Data.Data no longer blocks building TH.Syntax, which
allows greater parallelism in our builds.
Previously TH.Syntax was a bottleneck when compiling ghc-internal. Now
it is less of a bottle-neck and is also slightly quicker to
compile (since it no longer contains these instances) at the cost of
making Data.Data slightly more expensive to compile.
TH.Lift which depends on TH.Syntax can also compile quicker and no
longer blocks ghc-internal finishing to compile.
Resolves #26217
- - - - -
63c0ea33 by Teo Camarasu at 2025-08-18T15:29:50+01:00
compiler: delete unused names in Builtins.Names.TH
returnQ and bindQ are no longer used in the compiler.
There was also a very old comment that referred to them that I have modernized
- - - - -
27 changed files:
- compiler/GHC/Builtin/Names/TH.hs
- compiler/GHC/Hs/Expr.hs
- compiler/GHC/HsToCore/Quote.hs
- compiler/GHC/Rename/Splice.hs
- compiler/GHC/Tc/Gen/Splice.hs
- compiler/GHC/Tc/Gen/Splice.hs-boot
- compiler/GHC/Tc/Types/TH.hs
- libraries/base/src/Data/Array/Byte.hs
- libraries/base/src/Data/Fixed.hs
- + libraries/ghc-boot-th/GHC/Boot/TH/Monad.hs
- libraries/ghc-boot-th/ghc-boot-th.cabal.in
- libraries/ghc-internal/ghc-internal.cabal.in
- libraries/ghc-internal/src/GHC/Internal/Data/Data.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Lib.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Lift.hs
- + libraries/ghc-internal/src/GHC/Internal/TH/Monad.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Quote.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Syntax.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/TH.hs
- libraries/template-haskell/Language/Haskell/TH/Quote.hs
- libraries/template-haskell/Language/Haskell/TH/Syntax.hs
- testsuite/tests/th/T11452.stderr
- testsuite/tests/th/T15321.stderr
- testsuite/tests/th/T7276.stderr
- testsuite/tests/th/TH_NestedSplicesFail3.stderr
- testsuite/tests/th/TH_NestedSplicesFail4.stderr
Changes:
=====================================
compiler/GHC/Builtin/Names/TH.hs
=====================================
@@ -30,7 +30,7 @@ templateHaskellNames :: [Name]
-- Should stay in sync with the import list of GHC.HsToCore.Quote
templateHaskellNames = [
- returnQName, bindQName, sequenceQName, newNameName, liftName, liftTypedName,
+ sequenceQName, newNameName, liftName, liftTypedName,
mkNameName, mkNameG_vName, mkNameG_dName, mkNameG_tcName, mkNameG_fldName,
mkNameLName,
mkNameSName, mkNameQName,
@@ -181,26 +181,30 @@ templateHaskellNames = [
-- Quasiquoting
quasiQuoterTyConName, quoteDecName, quoteTypeName, quoteExpName, quotePatName]
-thSyn, thLib, qqLib, liftLib :: Module
+thSyn, thMonad, thLib, qqLib, liftLib :: Module
thSyn = mkTHModule (fsLit "GHC.Internal.TH.Syntax")
+thMonad = mkTHModule (fsLit "GHC.Internal.TH.Monad")
thLib = mkTHModule (fsLit "GHC.Internal.TH.Lib")
qqLib = mkTHModule (fsLit "GHC.Internal.TH.Quote")
liftLib = mkTHModule (fsLit "GHC.Internal.TH.Lift")
+
mkTHModule :: FastString -> Module
mkTHModule m = mkModule ghcInternalUnit (mkModuleNameFS m)
-libFun, libTc, thFun, thTc, thCls, thCon, liftFun :: FastString -> Unique -> Name
+libFun, libTc, thFun, thTc, thCon, liftFun, thMonadTc, thMonadCls, thMonadFun :: FastString -> Unique -> Name
libFun = mk_known_key_name varName thLib
libTc = mk_known_key_name tcName thLib
thFun = mk_known_key_name varName thSyn
thTc = mk_known_key_name tcName thSyn
-thCls = mk_known_key_name clsName thSyn
thCon = mk_known_key_name dataName thSyn
liftFun = mk_known_key_name varName liftLib
+thMonadTc = mk_known_key_name tcName thMonad
+thMonadCls = mk_known_key_name clsName thMonad
+thMonadFun = mk_known_key_name varName thMonad
-thFld :: FastString -> FastString -> Unique -> Name
-thFld con = mk_known_key_name (fieldName con) thSyn
+thMonadFld :: FastString -> FastString -> Unique -> Name
+thMonadFld con = mk_known_key_name (fieldName con) thSyn
qqFld :: FastString -> Unique -> Name
qqFld = mk_known_key_name (fieldName (fsLit "QuasiQuoter")) qqLib
@@ -210,14 +214,14 @@ liftClassName :: Name
liftClassName = mk_known_key_name clsName liftLib (fsLit "Lift") liftClassKey
quoteClassName :: Name
-quoteClassName = thCls (fsLit "Quote") quoteClassKey
+quoteClassName = thMonadCls (fsLit "Quote") quoteClassKey
qTyConName, nameTyConName, fieldExpTyConName, patTyConName,
fieldPatTyConName, expTyConName, decTyConName, typeTyConName,
matchTyConName, clauseTyConName, funDepTyConName, predTyConName,
codeTyConName, injAnnTyConName, overlapTyConName, decsTyConName,
modNameTyConName, quasiQuoterTyConName :: Name
-qTyConName = thTc (fsLit "Q") qTyConKey
+qTyConName = thMonadTc (fsLit "Q") qTyConKey
nameTyConName = thTc (fsLit "Name") nameTyConKey
fieldExpTyConName = thTc (fsLit "FieldExp") fieldExpTyConKey
patTyConName = thTc (fsLit "Pat") patTyConKey
@@ -230,20 +234,18 @@ matchTyConName = thTc (fsLit "Match") matchTyConKey
clauseTyConName = thTc (fsLit "Clause") clauseTyConKey
funDepTyConName = thTc (fsLit "FunDep") funDepTyConKey
predTyConName = thTc (fsLit "Pred") predTyConKey
-codeTyConName = thTc (fsLit "Code") codeTyConKey
+codeTyConName = thMonadTc (fsLit "Code") codeTyConKey
injAnnTyConName = thTc (fsLit "InjectivityAnn") injAnnTyConKey
overlapTyConName = thTc (fsLit "Overlap") overlapTyConKey
modNameTyConName = thTc (fsLit "ModName") modNameTyConKey
quasiQuoterTyConName = mk_known_key_name tcName qqLib (fsLit "QuasiQuoter") quasiQuoterTyConKey
-returnQName, bindQName, sequenceQName, newNameName, liftName,
+sequenceQName, newNameName, liftName,
mkNameName, mkNameG_vName, mkNameG_fldName, mkNameG_dName, mkNameG_tcName,
mkNameLName, mkNameSName, liftStringName, unTypeName, unTypeCodeName,
unsafeCodeCoerceName, liftTypedName, mkModNameName, mkNameQName :: Name
-returnQName = thFun (fsLit "returnQ") returnQIdKey
-bindQName = thFun (fsLit "bindQ") bindQIdKey
-sequenceQName = thFun (fsLit "sequenceQ") sequenceQIdKey
-newNameName = thFun (fsLit "newName") newNameIdKey
+sequenceQName = thMonadFun (fsLit "sequenceQ") sequenceQIdKey
+newNameName = thMonadFun (fsLit "newName") newNameIdKey
mkNameName = thFun (fsLit "mkName") mkNameIdKey
mkNameG_vName = thFun (fsLit "mkNameG_v") mkNameG_vIdKey
mkNameG_dName = thFun (fsLit "mkNameG_d") mkNameG_dIdKey
@@ -253,9 +255,9 @@ mkNameLName = thFun (fsLit "mkNameL") mkNameLIdKey
mkNameQName = thFun (fsLit "mkNameQ") mkNameQIdKey
mkNameSName = thFun (fsLit "mkNameS") mkNameSIdKey
mkModNameName = thFun (fsLit "mkModName") mkModNameIdKey
-unTypeName = thFld (fsLit "TExp") (fsLit "unType") unTypeIdKey
-unTypeCodeName = thFun (fsLit "unTypeCode") unTypeCodeIdKey
-unsafeCodeCoerceName = thFun (fsLit "unsafeCodeCoerce") unsafeCodeCoerceIdKey
+unTypeName = thMonadFld (fsLit "TExp") (fsLit "unType") unTypeIdKey
+unTypeCodeName = thMonadFun (fsLit "unTypeCode") unTypeCodeIdKey
+unsafeCodeCoerceName = thMonadFun (fsLit "unsafeCodeCoerce") unsafeCodeCoerceIdKey
liftName = liftFun (fsLit "lift") liftIdKey
liftStringName = liftFun (fsLit "liftString") liftStringIdKey
liftTypedName = liftFun (fsLit "liftTyped") liftTypedIdKey
@@ -808,12 +810,10 @@ dataNamespaceSpecifierDataConKey = mkPreludeDataConUnique 215
-- IdUniques available: 200-499
-- If you want to change this, make sure you check in GHC.Builtin.Names
-returnQIdKey, bindQIdKey, sequenceQIdKey, liftIdKey, newNameIdKey,
+sequenceQIdKey, liftIdKey, newNameIdKey,
mkNameIdKey, mkNameG_vIdKey, mkNameG_fldIdKey, mkNameG_dIdKey, mkNameG_tcIdKey,
mkNameLIdKey, mkNameSIdKey, unTypeIdKey, unTypeCodeIdKey,
unsafeCodeCoerceIdKey, liftTypedIdKey, mkModNameIdKey, mkNameQIdKey :: Unique
-returnQIdKey = mkPreludeMiscIdUnique 200
-bindQIdKey = mkPreludeMiscIdUnique 201
sequenceQIdKey = mkPreludeMiscIdUnique 202
liftIdKey = mkPreludeMiscIdUnique 203
newNameIdKey = mkPreludeMiscIdUnique 204
=====================================
compiler/GHC/Hs/Expr.hs
=====================================
@@ -68,7 +68,7 @@ import GHC.Tc.Utils.TcType (TcType, TcTyVar)
import {-# SOURCE #-} GHC.Tc.Types.LclEnv (TcLclEnv)
import GHCi.RemoteTypes ( ForeignRef )
-import qualified GHC.Boot.TH.Syntax as TH (Q)
+import qualified GHC.Boot.TH.Monad as TH (Q)
-- libraries:
import Data.Data hiding (Fixity(..))
=====================================
compiler/GHC/HsToCore/Quote.hs
=====================================
@@ -245,14 +245,14 @@ first generate a polymorphic definition and then just apply the wrapper at the e
[| \x -> x |]
====>
- gensym (unpackString "x"#) `bindQ` \ x1::String ->
- lam (pvar x1) (var x1)
+ newName (unpackString "x"#) >>= \ x1::Name ->
+ lamE (varP x1) (varE x1)
[| \x -> $(f [| x |]) |]
====>
- gensym (unpackString "x"#) `bindQ` \ x1::String ->
- lam (pvar x1) (f (var x1))
+ newName (unpackString "x"#) >>= \ x1::Name ->
+ lamE (varP x1) (f (varE x1))
-}
=====================================
compiler/GHC/Rename/Splice.hs
=====================================
@@ -68,7 +68,7 @@ import {-# SOURCE #-} GHC.Tc.Gen.Splice
import GHC.Tc.Zonk.Type
import GHCi.RemoteTypes ( ForeignRef )
-import qualified GHC.Boot.TH.Syntax as TH (Q)
+import qualified GHC.Boot.TH.Monad as TH (Q)
import qualified GHC.LanguageExtensions as LangExt
import qualified Data.Set as Set
=====================================
compiler/GHC/Tc/Gen/Splice.hs
=====================================
@@ -144,6 +144,7 @@ import qualified GHC.LanguageExtensions as LangExt
-- THSyntax gives access to internal functions and data types
import qualified GHC.Boot.TH.Syntax as TH
+import qualified GHC.Boot.TH.Monad as TH
import qualified GHC.Boot.TH.Ppr as TH
#if defined(HAVE_INTERNAL_INTERPRETER)
=====================================
compiler/GHC/Tc/Gen/Splice.hs-boot
=====================================
@@ -12,6 +12,7 @@ import GHC.Hs.Extension ( GhcRn, GhcPs, GhcTc )
import GHC.Hs ( HsQuote, HsExpr, LHsExpr, LHsType, LPat, LHsDecl, ThModFinalizers, HsUntypedSpliceResult, HsTypedSpliceResult, HsTypedSplice )
import qualified GHC.Boot.TH.Syntax as TH
+import qualified GHC.Boot.TH.Monad as TH
tcTypedSplice :: HsTypedSpliceResult
-> HsTypedSplice GhcRn
=====================================
compiler/GHC/Tc/Types/TH.hs
=====================================
@@ -18,7 +18,7 @@ module GHC.Tc.Types.TH (
import GHC.Prelude
import GHCi.RemoteTypes
-import qualified GHC.Boot.TH.Syntax as TH
+import qualified GHC.Boot.TH.Monad as TH
import GHC.Tc.Types.Evidence
import GHC.Utils.Outputable
import GHC.Tc.Types.TcRef
=====================================
libraries/base/src/Data/Array/Byte.hs
=====================================
@@ -32,6 +32,7 @@ import GHC.Internal.Show (intToDigit)
import GHC.Internal.ST (ST(..), runST)
import GHC.Internal.Word (Word8(..))
import GHC.Internal.TH.Syntax
+import GHC.Internal.TH.Monad
import GHC.Internal.TH.Lift
import GHC.Internal.ForeignPtr
import Prelude
=====================================
libraries/base/src/Data/Fixed.hs
=====================================
@@ -91,7 +91,7 @@ import GHC.Internal.TypeLits (KnownNat, natVal)
import GHC.Internal.Read
import GHC.Internal.Text.ParserCombinators.ReadPrec
import GHC.Internal.Text.Read.Lex
-import qualified GHC.Internal.TH.Syntax as TH
+import qualified GHC.Internal.TH.Monad as TH
import qualified GHC.Internal.TH.Lift as TH
import Data.Typeable
import Prelude
=====================================
libraries/ghc-boot-th/GHC/Boot/TH/Monad.hs
=====================================
@@ -0,0 +1,6 @@
+{-# LANGUAGE Safe #-}
+{-# OPTIONS_HADDOCK not-home #-}
+module GHC.Boot.TH.Monad
+ (module GHC.Internal.TH.Monad) where
+
+import GHC.Internal.TH.Monad
=====================================
libraries/ghc-boot-th/ghc-boot-th.cabal.in
=====================================
@@ -60,9 +60,11 @@ Library
exposed-modules:
GHC.Boot.TH.Lib
GHC.Boot.TH.Syntax
+ GHC.Boot.TH.Monad
other-modules:
GHC.Internal.TH.Lib
GHC.Internal.TH.Syntax
+ GHC.Internal.TH.Monad
GHC.Internal.ForeignSrcLang
GHC.Internal.LanguageExtensions
GHC.Internal.Lexeme
@@ -74,4 +76,5 @@ Library
GHC.Boot.TH.Lib,
GHC.Boot.TH.Lift,
GHC.Boot.TH.Quote,
- GHC.Boot.TH.Syntax
+ GHC.Boot.TH.Syntax,
+ GHC.Boot.TH.Monad
=====================================
libraries/ghc-internal/ghc-internal.cabal.in
=====================================
@@ -298,6 +298,7 @@ Library
GHC.Internal.TH.Lib
GHC.Internal.TH.Lift
GHC.Internal.TH.Quote
+ GHC.Internal.TH.Monad
GHC.Internal.TopHandler
GHC.Internal.TypeError
GHC.Internal.TypeLits
=====================================
libraries/ghc-internal/src/GHC/Internal/Data/Data.hs
=====================================
@@ -143,6 +143,7 @@ import GHC.Internal.Arr -- So we can give Data instance for Array
import qualified GHC.Internal.Generics as Generics (Fixity(..))
import GHC.Internal.Generics hiding (Fixity(..))
-- So we can give Data instance for U1, V1, ...
+import qualified GHC.Internal.TH.Syntax as TH
------------------------------------------------------------------------------
--
@@ -1353,3 +1354,63 @@ deriving instance Data DecidedStrictness
-- | @since base-4.12.0.0
deriving instance Data a => Data (Down a)
+
+----------------------------------------------------------------------------
+-- Data instances for GHC.Internal.TH.Syntax
+
+deriving instance Data TH.AnnLookup
+deriving instance Data TH.AnnTarget
+deriving instance Data TH.Bang
+deriving instance Data TH.BndrVis
+deriving instance Data TH.Body
+deriving instance Data TH.Bytes
+deriving instance Data TH.Callconv
+deriving instance Data TH.Clause
+deriving instance Data TH.Con
+deriving instance Data TH.Dec
+deriving instance Data TH.DecidedStrictness
+deriving instance Data TH.DerivClause
+deriving instance Data TH.DerivStrategy
+deriving instance Data TH.DocLoc
+deriving instance Data TH.Exp
+deriving instance Data TH.FamilyResultSig
+deriving instance Data TH.Fixity
+deriving instance Data TH.FixityDirection
+deriving instance Data TH.Foreign
+deriving instance Data TH.FunDep
+deriving instance Data TH.Guard
+deriving instance Data TH.Info
+deriving instance Data TH.InjectivityAnn
+deriving instance Data TH.Inline
+deriving instance Data TH.Lit
+deriving instance Data TH.Loc
+deriving instance Data TH.Match
+deriving instance Data TH.ModName
+deriving instance Data TH.Module
+deriving instance Data TH.ModuleInfo
+deriving instance Data TH.Name
+deriving instance Data TH.NameFlavour
+deriving instance Data TH.NameSpace
+deriving instance Data TH.NamespaceSpecifier
+deriving instance Data TH.OccName
+deriving instance Data TH.Overlap
+deriving instance Data TH.Pat
+deriving instance Data TH.PatSynArgs
+deriving instance Data TH.PatSynDir
+deriving instance Data TH.Phases
+deriving instance Data TH.PkgName
+deriving instance Data TH.Pragma
+deriving instance Data TH.Range
+deriving instance Data TH.Role
+deriving instance Data TH.RuleBndr
+deriving instance Data TH.RuleMatch
+deriving instance Data TH.Safety
+deriving instance Data TH.SourceStrictness
+deriving instance Data TH.SourceUnpackedness
+deriving instance Data TH.Specificity
+deriving instance Data TH.Stmt
+deriving instance Data TH.TyLit
+deriving instance Data TH.TySynEqn
+deriving instance Data TH.Type
+deriving instance Data TH.TypeFamilyHead
+deriving instance Data flag => Data (TH.TyVarBndr flag)
=====================================
libraries/ghc-internal/src/GHC/Internal/TH/Lib.hs
=====================================
@@ -21,6 +21,7 @@
module GHC.Internal.TH.Lib where
import GHC.Internal.TH.Syntax hiding (Role, InjectivityAnn)
+import GHC.Internal.TH.Monad
import qualified GHC.Internal.TH.Syntax as TH
#ifdef BOOTSTRAP_TH
=====================================
libraries/ghc-internal/src/GHC/Internal/TH/Lift.hs
=====================================
@@ -30,6 +30,7 @@ module GHC.Internal.TH.Lift
where
import GHC.Internal.TH.Syntax
+import GHC.Internal.TH.Monad
import qualified GHC.Internal.TH.Lib as Lib (litE) -- See wrinkle (W4) of Note [Tracking dependencies on primitives]
import GHC.Internal.Data.Either
=====================================
libraries/ghc-internal/src/GHC/Internal/TH/Monad.hs
=====================================
@@ -0,0 +1,971 @@
+{-# OPTIONS_HADDOCK not-home #-} -- we want users to import Language.Haskell.TH.Syntax instead
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs#-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE RoleAnnotations #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE StandaloneKindSignatures #-}
+{-# LANGUAGE Trustworthy #-}
+{-# LANGUAGE UnboxedSums #-}
+
+-- | This module is used internally in GHC's integration with Template Haskell
+-- and defines the Monads of Template Haskell, and associated definitions.
+--
+-- This is not a part of the public API, and as such, there are no API
+-- guarantees for this module from version to version.
+--
+-- Import "Language.Haskell.TH" or "Language.Haskell.TH.Syntax" instead!
+module GHC.Internal.TH.Monad
+ ( module GHC.Internal.TH.Monad
+ ) where
+
+#ifdef BOOTSTRAP_TH
+import Prelude
+import Data.Data hiding (Fixity(..))
+import Data.IORef
+import System.IO.Unsafe ( unsafePerformIO )
+import Control.Monad.IO.Class (MonadIO (..))
+import Control.Monad.Fix (MonadFix (..))
+import Control.Exception (BlockedIndefinitelyOnMVar (..), catch, throwIO)
+import Control.Exception.Base (FixIOException (..))
+import Control.Concurrent.MVar (newEmptyMVar, readMVar, putMVar)
+import System.IO ( hPutStrLn, stderr )
+import qualified Data.Kind as Kind (Type)
+import GHC.IO.Unsafe ( unsafeDupableInterleaveIO )
+import GHC.Types (TYPE, RuntimeRep(..))
+#else
+import GHC.Internal.Base hiding (NonEmpty(..),Type, Module, sequence)
+import GHC.Internal.Data.Data hiding (Fixity(..))
+import GHC.Internal.Data.Traversable
+import GHC.Internal.IORef
+import GHC.Internal.System.IO
+import GHC.Internal.Data.Foldable
+import GHC.Internal.Data.Typeable
+import GHC.Internal.Control.Monad.IO.Class
+import GHC.Internal.Control.Monad.Fail
+import GHC.Internal.Control.Monad.Fix
+import GHC.Internal.Control.Exception
+import GHC.Internal.Num
+import GHC.Internal.IO.Unsafe
+import GHC.Internal.MVar
+import GHC.Internal.IO.Exception
+import qualified GHC.Internal.Types as Kind (Type)
+#endif
+import GHC.Internal.ForeignSrcLang
+import GHC.Internal.LanguageExtensions
+import GHC.Internal.TH.Syntax
+
+-----------------------------------------------------
+--
+-- The Quasi class
+--
+-----------------------------------------------------
+
+class (MonadIO m, MonadFail m) => Quasi m where
+ -- | Fresh names. See 'newName'.
+ qNewName :: String -> m Name
+
+ ------- Error reporting and recovery -------
+ -- | Report an error (True) or warning (False)
+ -- ...but carry on; use 'fail' to stop. See 'report'.
+ qReport :: Bool -> String -> m ()
+
+ -- | See 'recover'.
+ qRecover :: m a -- ^ the error handler
+ -> m a -- ^ action which may fail
+ -> m a -- ^ Recover from the monadic 'fail'
+
+ ------- Inspect the type-checker's environment -------
+ -- | True <=> type namespace, False <=> value namespace. See 'lookupName'.
+ qLookupName :: Bool -> String -> m (Maybe Name)
+ -- | See 'reify'.
+ qReify :: Name -> m Info
+ -- | See 'reifyFixity'.
+ qReifyFixity :: Name -> m (Maybe Fixity)
+ -- | See 'reifyType'.
+ qReifyType :: Name -> m Type
+ -- | Is (n tys) an instance? Returns list of matching instance Decs (with
+ -- empty sub-Decs) Works for classes and type functions. See 'reifyInstances'.
+ qReifyInstances :: Name -> [Type] -> m [Dec]
+ -- | See 'reifyRoles'.
+ qReifyRoles :: Name -> m [Role]
+ -- | See 'reifyAnnotations'.
+ qReifyAnnotations :: Data a => AnnLookup -> m [a]
+ -- | See 'reifyModule'.
+ qReifyModule :: Module -> m ModuleInfo
+ -- | See 'reifyConStrictness'.
+ qReifyConStrictness :: Name -> m [DecidedStrictness]
+
+ -- | See 'location'.
+ qLocation :: m Loc
+
+ -- | Input/output (dangerous). See 'runIO'.
+ qRunIO :: IO a -> m a
+ qRunIO = liftIO
+ -- | See 'getPackageRoot'.
+ qGetPackageRoot :: m FilePath
+
+ -- | See 'addDependentFile'.
+ qAddDependentFile :: FilePath -> m ()
+
+ -- | See 'addTempFile'.
+ qAddTempFile :: String -> m FilePath
+
+ -- | See 'addTopDecls'.
+ qAddTopDecls :: [Dec] -> m ()
+
+ -- | See 'addForeignFilePath'.
+ qAddForeignFilePath :: ForeignSrcLang -> String -> m ()
+
+ -- | See 'addModFinalizer'.
+ qAddModFinalizer :: Q () -> m ()
+
+ -- | See 'addCorePlugin'.
+ qAddCorePlugin :: String -> m ()
+
+ -- | See 'getQ'.
+ qGetQ :: Typeable a => m (Maybe a)
+
+ -- | See 'putQ'.
+ qPutQ :: Typeable a => a -> m ()
+
+ -- | See 'isExtEnabled'.
+ qIsExtEnabled :: Extension -> m Bool
+ -- | See 'extsEnabled'.
+ qExtsEnabled :: m [Extension]
+
+ -- | See 'putDoc'.
+ qPutDoc :: DocLoc -> String -> m ()
+ -- | See 'getDoc'.
+ qGetDoc :: DocLoc -> m (Maybe String)
+
+-----------------------------------------------------
+-- The IO instance of Quasi
+-----------------------------------------------------
+
+-- | This instance is used only when running a Q
+-- computation in the IO monad, usually just to
+-- print the result. There is no interesting
+-- type environment, so reification isn't going to
+-- work.
+instance Quasi IO where
+ qNewName = newNameIO
+
+ qReport True msg = hPutStrLn stderr ("Template Haskell error: " ++ msg)
+ qReport False msg = hPutStrLn stderr ("Template Haskell error: " ++ msg)
+
+ qLookupName _ _ = badIO "lookupName"
+ qReify _ = badIO "reify"
+ qReifyFixity _ = badIO "reifyFixity"
+ qReifyType _ = badIO "reifyFixity"
+ qReifyInstances _ _ = badIO "reifyInstances"
+ qReifyRoles _ = badIO "reifyRoles"
+ qReifyAnnotations _ = badIO "reifyAnnotations"
+ qReifyModule _ = badIO "reifyModule"
+ qReifyConStrictness _ = badIO "reifyConStrictness"
+ qLocation = badIO "currentLocation"
+ qRecover _ _ = badIO "recover" -- Maybe we could fix this?
+ qGetPackageRoot = badIO "getProjectRoot"
+ qAddDependentFile _ = badIO "addDependentFile"
+ qAddTempFile _ = badIO "addTempFile"
+ qAddTopDecls _ = badIO "addTopDecls"
+ qAddForeignFilePath _ _ = badIO "addForeignFilePath"
+ qAddModFinalizer _ = badIO "addModFinalizer"
+ qAddCorePlugin _ = badIO "addCorePlugin"
+ qGetQ = badIO "getQ"
+ qPutQ _ = badIO "putQ"
+ qIsExtEnabled _ = badIO "isExtEnabled"
+ qExtsEnabled = badIO "extsEnabled"
+ qPutDoc _ _ = badIO "putDoc"
+ qGetDoc _ = badIO "getDoc"
+
+instance Quote IO where
+ newName = newNameIO
+
+newNameIO :: String -> IO Name
+newNameIO s = do { n <- atomicModifyIORef' counter (\x -> (x + 1, x))
+ ; pure (mkNameU s n) }
+
+badIO :: String -> IO a
+badIO op = do { qReport True ("Can't do `" ++ op ++ "' in the IO monad")
+ ; fail "Template Haskell failure" }
+
+-- Global variable to generate unique symbols
+counter :: IORef Uniq
+{-# NOINLINE counter #-}
+counter = unsafePerformIO (newIORef 0)
+
+
+-----------------------------------------------------
+--
+-- The Q monad
+--
+-----------------------------------------------------
+
+-- | In short, 'Q' provides the 'Quasi' operations in one neat monad for the
+-- user.
+--
+-- The longer story, is that 'Q' wraps an arbitrary 'Quasi'-able monad.
+-- The perceptive reader notices that 'Quasi' has only two instances, 'Q'
+-- itself and 'IO', neither of which have concrete implementations.'Q' plays
+-- the trick of [dependency
+-- inversion](https://en.wikipedia.org/wiki/Dependency_inversion_principle),
+-- providing an abstract interface for the user which is later concretely
+-- fufilled by an concrete 'Quasi' instance, internal to GHC.
+newtype Q a = Q { unQ :: forall m. Quasi m => m a }
+
+-- | \"Runs\" the 'Q' monad. Normal users of Template Haskell
+-- should not need this function, as the splice brackets @$( ... )@
+-- are the usual way of running a 'Q' computation.
+--
+-- This function is primarily used in GHC internals, and for debugging
+-- splices by running them in 'IO'.
+--
+-- Note that many functions in 'Q', such as 'reify' and other compiler
+-- queries, are not supported when running 'Q' in 'IO'; these operations
+-- simply fail at runtime. Indeed, the only operations guaranteed to succeed
+-- are 'newName', 'runIO', 'reportError' and 'reportWarning'.
+runQ :: Quasi m => Q a -> m a
+runQ (Q m) = m
+
+instance Monad Q where
+ Q m >>= k = Q (m >>= \x -> unQ (k x))
+ (>>) = (*>)
+
+instance MonadFail Q where
+ fail s = report True s >> Q (fail "Q monad failure")
+
+instance Functor Q where
+ fmap f (Q x) = Q (fmap f x)
+
+instance Applicative Q where
+ pure x = Q (pure x)
+ Q f <*> Q x = Q (f <*> x)
+ Q m *> Q n = Q (m *> n)
+
+-- | @since 2.17.0.0
+instance Semigroup a => Semigroup (Q a) where
+ (<>) = liftA2 (<>)
+
+-- | @since 2.17.0.0
+instance Monoid a => Monoid (Q a) where
+ mempty = pure mempty
+
+-- | If the function passed to 'mfix' inspects its argument,
+-- the resulting action will throw a 'FixIOException'.
+--
+-- @since 2.17.0.0
+instance MonadFix Q where
+ -- We use the same blackholing approach as in fixIO.
+ -- See Note [Blackholing in fixIO] in System.IO in base.
+ mfix k = do
+ m <- runIO newEmptyMVar
+ ans <- runIO (unsafeDupableInterleaveIO
+ (readMVar m `catch` \BlockedIndefinitelyOnMVar ->
+ throwIO FixIOException))
+ result <- k ans
+ runIO (putMVar m result)
+ return result
+
+
+-----------------------------------------------------
+--
+-- The Quote class
+--
+-----------------------------------------------------
+
+
+
+-- | The 'Quote' class implements the minimal interface which is necessary for
+-- desugaring quotations.
+--
+-- * The @Monad m@ superclass is needed to stitch together the different
+-- AST fragments.
+-- * 'newName' is used when desugaring binding structures such as lambdas
+-- to generate fresh names.
+--
+-- Therefore the type of an untyped quotation in GHC is `Quote m => m Exp`
+--
+-- For many years the type of a quotation was fixed to be `Q Exp` but by
+-- more precisely specifying the minimal interface it enables the `Exp` to
+-- be extracted purely from the quotation without interacting with `Q`.
+class Monad m => Quote m where
+ {- |
+ Generate a fresh name, which cannot be captured.
+
+ For example, this:
+
+ @f = $(do
+ nm1 <- newName \"x\"
+ let nm2 = 'mkName' \"x\"
+ return ('LamE' ['VarP' nm1] (LamE [VarP nm2] ('VarE' nm1)))
+ )@
+
+ will produce the splice
+
+ >f = \x0 -> \x -> x0
+
+ In particular, the occurrence @VarE nm1@ refers to the binding @VarP nm1@,
+ and is not captured by the binding @VarP nm2@.
+
+ Although names generated by @newName@ cannot /be captured/, they can
+ /capture/ other names. For example, this:
+
+ >g = $(do
+ > nm1 <- newName "x"
+ > let nm2 = mkName "x"
+ > return (LamE [VarP nm2] (LamE [VarP nm1] (VarE nm2)))
+ > )
+
+ will produce the splice
+
+ >g = \x -> \x0 -> x0
+
+ since the occurrence @VarE nm2@ is captured by the innermost binding
+ of @x@, namely @VarP nm1@.
+ -}
+ newName :: String -> m Name
+
+instance Quote Q where
+ newName s = Q (qNewName s)
+
+-----------------------------------------------------
+--
+-- The TExp type
+--
+-----------------------------------------------------
+
+type TExp :: TYPE r -> Kind.Type
+type role TExp nominal -- See Note [Role of TExp]
+newtype TExp a = TExp
+ { unType :: Exp -- ^ Underlying untyped Template Haskell expression
+ }
+-- ^ Typed wrapper around an 'Exp'.
+--
+-- This is the typed representation of terms produced by typed quotes.
+--
+-- Representation-polymorphic since /template-haskell-2.16.0.0/.
+
+-- | Discard the type annotation and produce a plain Template Haskell
+-- expression
+--
+-- Representation-polymorphic since /template-haskell-2.16.0.0/.
+unTypeQ :: forall (r :: RuntimeRep) (a :: TYPE r) m . Quote m => m (TExp a) -> m Exp
+unTypeQ m = do { TExp e <- m
+ ; return e }
+
+-- | Annotate the Template Haskell expression with a type
+--
+-- This is unsafe because GHC cannot check for you that the expression
+-- really does have the type you claim it has.
+--
+-- Representation-polymorphic since /template-haskell-2.16.0.0/.
+unsafeTExpCoerce :: forall (r :: RuntimeRep) (a :: TYPE r) m .
+ Quote m => m Exp -> m (TExp a)
+unsafeTExpCoerce m = do { e <- m
+ ; return (TExp e) }
+
+{- Note [Role of TExp]
+~~~~~~~~~~~~~~~~~~~~~~
+TExp's argument must have a nominal role, not phantom as would
+be inferred (#8459). Consider
+
+ e :: Code Q Age
+ e = [|| MkAge 3 ||]
+
+ foo = $(coerce e) + 4::Int
+
+The splice will evaluate to (MkAge 3) and you can't add that to
+4::Int. So you can't coerce a (Code Q Age) to a (Code Q Int). -}
+
+-- Code constructor
+#if __GLASGOW_HASKELL__ >= 909
+type Code :: (Kind.Type -> Kind.Type) -> forall r. TYPE r -> Kind.Type
+ -- See Note [Foralls to the right in Code]
+#else
+type Code :: (Kind.Type -> Kind.Type) -> TYPE r -> Kind.Type
+#endif
+type role Code representational nominal -- See Note [Role of TExp]
+newtype Code m a = Code
+ { examineCode :: m (TExp a) -- ^ Underlying monadic value
+ }
+-- ^ Represents an expression which has type @a@, built in monadic context @m@. Built on top of 'TExp', typed
+-- expressions allow for type-safe splicing via:
+--
+-- - typed quotes, written as @[|| ... ||]@ where @...@ is an expression; if
+-- that expression has type @a@, then the quotation has type
+-- @Quote m => Code m a@
+--
+-- - typed splices inside of typed quotes, written as @$$(...)@ where @...@
+-- is an arbitrary expression of type @Quote m => Code m a@
+--
+-- Traditional expression quotes and splices let us construct ill-typed
+-- expressions:
+--
+-- >>> fmap ppr $ runQ (unTypeCode [| True == $( [| "foo" |] ) |])
+-- GHC.Internal.Types.True GHC.Internal.Classes.== "foo"
+-- >>> GHC.Internal.Types.True GHC.Internal.Classes.== "foo"
+-- <interactive> error:
+-- • Couldn't match expected type ‘Bool’ with actual type ‘[Char]’
+-- • In the second argument of ‘(==)’, namely ‘"foo"’
+-- In the expression: True == "foo"
+-- In an equation for ‘it’: it = True == "foo"
+--
+-- With typed expressions, the type error occurs when /constructing/ the
+-- Template Haskell expression:
+--
+-- >>> fmap ppr $ runQ (unTypeCode [|| True == $$( [|| "foo" ||] ) ||])
+-- <interactive> error:
+-- • Couldn't match type ‘[Char]’ with ‘Bool’
+-- Expected type: Code Q Bool
+-- Actual type: Code Q [Char]
+-- • In the Template Haskell quotation [|| "foo" ||]
+-- In the expression: [|| "foo" ||]
+-- In the Template Haskell splice $$([|| "foo" ||])
+
+
+{- Note [Foralls to the right in Code]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Code has the following type signature:
+ type Code :: (Kind.Type -> Kind.Type) -> forall r. TYPE r -> Kind.Type
+
+This allows us to write
+ data T (f :: forall r . (TYPE r) -> Type) = MkT (f Int) (f Int#)
+
+ tcodeq :: T (Code Q)
+ tcodeq = MkT [||5||] [||5#||]
+
+If we used the slightly more straightforward signature
+ type Code :: foral r. (Kind.Type -> Kind.Type) -> TYPE r -> Kind.Type
+
+then the example above would become ill-typed. (See #23592 for some discussion.)
+-}
+
+-- | Unsafely convert an untyped code representation into a typed code
+-- representation.
+unsafeCodeCoerce :: forall (r :: RuntimeRep) (a :: TYPE r) m .
+ Quote m => m Exp -> Code m a
+unsafeCodeCoerce m = Code (unsafeTExpCoerce m)
+
+-- | Lift a monadic action producing code into the typed 'Code'
+-- representation
+liftCode :: forall (r :: RuntimeRep) (a :: TYPE r) m . m (TExp a) -> Code m a
+liftCode = Code
+
+-- | Extract the untyped representation from the typed representation
+unTypeCode :: forall (r :: RuntimeRep) (a :: TYPE r) m . Quote m
+ => Code m a -> m Exp
+unTypeCode = unTypeQ . examineCode
+
+-- | Modify the ambient monad used during code generation. For example, you
+-- can use `hoistCode` to handle a state effect:
+-- @
+-- handleState :: Code (StateT Int Q) a -> Code Q a
+-- handleState = hoistCode (flip runState 0)
+-- @
+hoistCode :: forall m n (r :: RuntimeRep) (a :: TYPE r) . Monad m
+ => (forall x . m x -> n x) -> Code m a -> Code n a
+hoistCode f (Code a) = Code (f a)
+
+
+-- | Variant of '(>>=)' which allows effectful computations to be injected
+-- into code generation.
+bindCode :: forall m a (r :: RuntimeRep) (b :: TYPE r) . Monad m
+ => m a -> (a -> Code m b) -> Code m b
+bindCode q k = liftCode (q >>= examineCode . k)
+
+-- | Variant of '(>>)' which allows effectful computations to be injected
+-- into code generation.
+bindCode_ :: forall m a (r :: RuntimeRep) (b :: TYPE r) . Monad m
+ => m a -> Code m b -> Code m b
+bindCode_ q c = liftCode ( q >> examineCode c)
+
+-- | A useful combinator for embedding monadic actions into 'Code'
+-- @
+-- myCode :: ... => Code m a
+-- myCode = joinCode $ do
+-- x <- someSideEffect
+-- return (makeCodeWith x)
+-- @
+joinCode :: forall m (r :: RuntimeRep) (a :: TYPE r) . Monad m
+ => m (Code m a) -> Code m a
+joinCode = flip bindCode id
+
+----------------------------------------------------
+-- Packaged versions for the programmer, hiding the Quasi-ness
+
+
+-- | Report an error (True) or warning (False),
+-- but carry on; use 'fail' to stop.
+report :: Bool -> String -> Q ()
+report b s = Q (qReport b s)
+{-# DEPRECATED report "Use reportError or reportWarning instead" #-} -- deprecated in 7.6
+
+-- | Report an error to the user, but allow the current splice's computation to carry on. To abort the computation, use 'fail'.
+reportError :: String -> Q ()
+reportError = report True
+
+-- | Report a warning to the user, and carry on.
+reportWarning :: String -> Q ()
+reportWarning = report False
+
+-- | Recover from errors raised by 'reportError' or 'fail'.
+recover :: Q a -- ^ handler to invoke on failure
+ -> Q a -- ^ computation to run
+ -> Q a
+recover (Q r) (Q m) = Q (qRecover r m)
+
+-- We don't export lookupName; the Bool isn't a great API
+-- Instead we export lookupTypeName, lookupValueName
+lookupName :: Bool -> String -> Q (Maybe Name)
+lookupName ns s = Q (qLookupName ns s)
+
+-- | Look up the given name in the (type namespace of the) current splice's scope. See "Language.Haskell.TH.Syntax#namelookup" for more details.
+lookupTypeName :: String -> Q (Maybe Name)
+lookupTypeName s = Q (qLookupName True s)
+
+-- | Look up the given name in the (value namespace of the) current splice's scope. See "Language.Haskell.TH.Syntax#namelookup" for more details.
+lookupValueName :: String -> Q (Maybe Name)
+lookupValueName s = Q (qLookupName False s)
+
+{-
+Note [Name lookup]
+~~~~~~~~~~~~~~~~~~
+-}
+{- $namelookup #namelookup#
+The functions 'lookupTypeName' and 'lookupValueName' provide
+a way to query the current splice's context for what names
+are in scope. The function 'lookupTypeName' queries the type
+namespace, whereas 'lookupValueName' queries the value namespace,
+but the functions are otherwise identical.
+
+A call @lookupValueName s@ will check if there is a value
+with name @s@ in scope at the current splice's location. If
+there is, the @Name@ of this value is returned;
+if not, then @Nothing@ is returned.
+
+The returned name cannot be \"captured\".
+For example:
+
+> f = "global"
+> g = $( do
+> Just nm <- lookupValueName "f"
+> [| let f = "local" in $( varE nm ) |]
+
+In this case, @g = \"global\"@; the call to @lookupValueName@
+returned the global @f@, and this name was /not/ captured by
+the local definition of @f@.
+
+The lookup is performed in the context of the /top-level/ splice
+being run. For example:
+
+> f = "global"
+> g = $( [| let f = "local" in
+> $(do
+> Just nm <- lookupValueName "f"
+> varE nm
+> ) |] )
+
+Again in this example, @g = \"global\"@, because the call to
+@lookupValueName@ queries the context of the outer-most @$(...)@.
+
+Operators should be queried without any surrounding parentheses, like so:
+
+> lookupValueName "+"
+
+Qualified names are also supported, like so:
+
+> lookupValueName "Prelude.+"
+> lookupValueName "Prelude.map"
+
+-}
+
+
+{- | 'reify' looks up information about the 'Name'. It will fail with
+a compile error if the 'Name' is not visible. A 'Name' is visible if it is
+imported or defined in a prior top-level declaration group. See the
+documentation for 'newDeclarationGroup' for more details.
+
+It is sometimes useful to construct the argument name using 'lookupTypeName' or 'lookupValueName'
+to ensure that we are reifying from the right namespace. For instance, in this context:
+
+> data D = D
+
+which @D@ does @reify (mkName \"D\")@ return information about? (Answer: @D@-the-type, but don't rely on it.)
+To ensure we get information about @D@-the-value, use 'lookupValueName':
+
+> do
+> Just nm <- lookupValueName "D"
+> reify nm
+
+and to get information about @D@-the-type, use 'lookupTypeName'.
+-}
+reify :: Name -> Q Info
+reify v = Q (qReify v)
+
+{- | @reifyFixity nm@ attempts to find a fixity declaration for @nm@. For
+example, if the function @foo@ has the fixity declaration @infixr 7 foo@, then
+@reifyFixity 'foo@ would return @'Just' ('Fixity' 7 'InfixR')@. If the function
+@bar@ does not have a fixity declaration, then @reifyFixity 'bar@ returns
+'Nothing', so you may assume @bar@ has 'defaultFixity'.
+-}
+reifyFixity :: Name -> Q (Maybe Fixity)
+reifyFixity nm = Q (qReifyFixity nm)
+
+{- | @reifyType nm@ attempts to find the type or kind of @nm@. For example,
+@reifyType 'not@ returns @Bool -> Bool@, and
+@reifyType ''Bool@ returns @Type@.
+This works even if there's no explicit signature and the type or kind is inferred.
+-}
+reifyType :: Name -> Q Type
+reifyType nm = Q (qReifyType nm)
+
+{- | Template Haskell is capable of reifying information about types and
+terms defined in previous declaration groups. Top-level declaration splices break up
+declaration groups.
+
+For an example, consider this code block. We define a datatype @X@ and
+then try to call 'reify' on the datatype.
+
+@
+module Check where
+
+data X = X
+ deriving Eq
+
+$(do
+ info <- reify ''X
+ runIO $ print info
+ )
+@
+
+This code fails to compile, noting that @X@ is not available for reification at the site of 'reify'. We can fix this by creating a new declaration group using an empty top-level splice:
+
+@
+data X = X
+ deriving Eq
+
+$(pure [])
+
+$(do
+ info <- reify ''X
+ runIO $ print info
+ )
+@
+
+We provide 'newDeclarationGroup' as a means of documenting this behavior
+and providing a name for the pattern.
+
+Since top level splices infer the presence of the @$( ... )@ brackets, we can also write:
+
+@
+data X = X
+ deriving Eq
+
+newDeclarationGroup
+
+$(do
+ info <- reify ''X
+ runIO $ print info
+ )
+@
+
+-}
+newDeclarationGroup :: Q [Dec]
+newDeclarationGroup = pure []
+
+{- | @reifyInstances nm tys@ returns a list of all visible instances (see below for "visible")
+of @nm tys@. That is,
+if @nm@ is the name of a type class, then all instances of this class at the types @tys@
+are returned. Alternatively, if @nm@ is the name of a data family or type family,
+all instances of this family at the types @tys@ are returned.
+
+Note that this is a \"shallow\" test; the declarations returned merely have
+instance heads which unify with @nm tys@, they need not actually be satisfiable.
+
+ - @reifyInstances ''Eq [ 'TupleT' 2 \``AppT`\` 'ConT' ''A \``AppT`\` 'ConT' ''B ]@ contains
+ the @instance (Eq a, Eq b) => Eq (a, b)@ regardless of whether @A@ and
+ @B@ themselves implement 'Eq'
+
+ - @reifyInstances ''Show [ 'VarT' ('mkName' "a") ]@ produces every available
+ instance of 'Show'
+
+There is one edge case: @reifyInstances ''Typeable tys@ currently always
+produces an empty list (no matter what @tys@ are given).
+
+In principle, the *visible* instances are
+* all instances defined in a prior top-level declaration group
+ (see docs on @newDeclarationGroup@), or
+* all instances defined in any module transitively imported by the
+ module being compiled
+
+However, actually searching all modules transitively below the one being
+compiled is unreasonably expensive, so @reifyInstances@ will report only the
+instance for modules that GHC has had some cause to visit during this
+compilation. This is a shortcoming: @reifyInstances@ might fail to report
+instances for a type that is otherwise unusued, or instances defined in a
+different component. You can work around this shortcoming by explicitly importing the modules
+whose instances you want to be visible. GHC issue <https://gitlab.haskell.org/ghc/ghc/-/issues/20529#note_388980 #20529>
+has some discussion around this.
+
+-}
+reifyInstances :: Name -> [Type] -> Q [InstanceDec]
+reifyInstances cls tys = Q (qReifyInstances cls tys)
+
+{- | @reifyRoles nm@ returns the list of roles associated with the parameters
+(both visible and invisible) of
+the tycon @nm@. Fails if @nm@ cannot be found or is not a tycon.
+The returned list should never contain 'InferR'.
+
+An invisible parameter to a tycon is often a kind parameter. For example, if
+we have
+
+@
+type Proxy :: forall k. k -> Type
+data Proxy a = MkProxy
+@
+
+and @reifyRoles Proxy@, we will get @['NominalR', 'PhantomR']@. The 'NominalR' is
+the role of the invisible @k@ parameter. Kind parameters are always nominal.
+-}
+reifyRoles :: Name -> Q [Role]
+reifyRoles nm = Q (qReifyRoles nm)
+
+-- | @reifyAnnotations target@ returns the list of annotations
+-- associated with @target@. Only the annotations that are
+-- appropriately typed is returned. So if you have @Int@ and @String@
+-- annotations for the same target, you have to call this function twice.
+reifyAnnotations :: Data a => AnnLookup -> Q [a]
+reifyAnnotations an = Q (qReifyAnnotations an)
+
+-- | @reifyModule mod@ looks up information about module @mod@. To
+-- look up the current module, call this function with the return
+-- value of 'Language.Haskell.TH.Lib.thisModule'.
+reifyModule :: Module -> Q ModuleInfo
+reifyModule m = Q (qReifyModule m)
+
+-- | @reifyConStrictness nm@ looks up the strictness information for the fields
+-- of the constructor with the name @nm@. Note that the strictness information
+-- that 'reifyConStrictness' returns may not correspond to what is written in
+-- the source code. For example, in the following data declaration:
+--
+-- @
+-- data Pair a = Pair a a
+-- @
+--
+-- 'reifyConStrictness' would return @['DecidedLazy', DecidedLazy]@ under most
+-- circumstances, but it would return @['DecidedStrict', DecidedStrict]@ if the
+-- @-XStrictData@ language extension was enabled.
+reifyConStrictness :: Name -> Q [DecidedStrictness]
+reifyConStrictness n = Q (qReifyConStrictness n)
+
+-- | Is the list of instances returned by 'reifyInstances' nonempty?
+--
+-- If you're confused by an instance not being visible despite being
+-- defined in the same module and above the splice in question, see the
+-- docs for 'newDeclarationGroup' for a possible explanation.
+isInstance :: Name -> [Type] -> Q Bool
+isInstance nm tys = do { decs <- reifyInstances nm tys
+ ; return (not (null decs)) }
+
+-- | The location at which this computation is spliced.
+location :: Q Loc
+location = Q qLocation
+
+-- |The 'runIO' function lets you run an I\/O computation in the 'Q' monad.
+-- Take care: you are guaranteed the ordering of calls to 'runIO' within
+-- a single 'Q' computation, but not about the order in which splices are run.
+--
+-- Note: for various murky reasons, stdout and stderr handles are not
+-- necessarily flushed when the compiler finishes running, so you should
+-- flush them yourself.
+runIO :: IO a -> Q a
+runIO m = Q (qRunIO m)
+
+-- | Get the package root for the current package which is being compiled.
+-- This can be set explicitly with the -package-root flag but is normally
+-- just the current working directory.
+--
+-- The motivation for this flag is to provide a principled means to remove the
+-- assumption from splices that they will be executed in the directory where the
+-- cabal file resides. Projects such as haskell-language-server can't and don't
+-- change directory when compiling files but instead set the -package-root flag
+-- appropriately.
+getPackageRoot :: Q FilePath
+getPackageRoot = Q qGetPackageRoot
+
+
+
+-- | Record external files that runIO is using (dependent upon).
+-- The compiler can then recognize that it should re-compile the Haskell file
+-- when an external file changes.
+--
+-- Expects an absolute file path.
+--
+-- Notes:
+--
+-- * ghc -M does not know about these dependencies - it does not execute TH.
+--
+-- * The dependency is based on file content, not a modification time
+addDependentFile :: FilePath -> Q ()
+addDependentFile fp = Q (qAddDependentFile fp)
+
+-- | Obtain a temporary file path with the given suffix. The compiler will
+-- delete this file after compilation.
+addTempFile :: String -> Q FilePath
+addTempFile suffix = Q (qAddTempFile suffix)
+
+-- | Add additional top-level declarations. The added declarations will be type
+-- checked along with the current declaration group.
+addTopDecls :: [Dec] -> Q ()
+addTopDecls ds = Q (qAddTopDecls ds)
+
+
+-- | Emit a foreign file which will be compiled and linked to the object for
+-- the current module. Currently only languages that can be compiled with
+-- the C compiler are supported, and the flags passed as part of -optc will
+-- be also applied to the C compiler invocation that will compile them.
+--
+-- Note that for non-C languages (for example C++) @extern "C"@ directives
+-- must be used to get symbols that we can access from Haskell.
+--
+-- To get better errors, it is recommended to use #line pragmas when
+-- emitting C files, e.g.
+--
+-- > {-# LANGUAGE CPP #-}
+-- > ...
+-- > addForeignSource LangC $ unlines
+-- > [ "#line " ++ show (__LINE__ + 1) ++ " " ++ show __FILE__
+-- > , ...
+-- > ]
+addForeignSource :: ForeignSrcLang -> String -> Q ()
+addForeignSource lang src = do
+ let suffix = case lang of
+ LangC -> "c"
+ LangCxx -> "cpp"
+ LangObjc -> "m"
+ LangObjcxx -> "mm"
+ LangAsm -> "s"
+ LangJs -> "js"
+ RawObject -> "a"
+ path <- addTempFile suffix
+ runIO $ writeFile path src
+ addForeignFilePath lang path
+
+-- | Same as 'addForeignSource', but expects to receive a path pointing to the
+-- foreign file instead of a 'String' of its contents. Consider using this in
+-- conjunction with 'addTempFile'.
+--
+-- This is a good alternative to 'addForeignSource' when you are trying to
+-- directly link in an object file.
+addForeignFilePath :: ForeignSrcLang -> FilePath -> Q ()
+addForeignFilePath lang fp = Q (qAddForeignFilePath lang fp)
+
+-- | Add a finalizer that will run in the Q monad after the current module has
+-- been type checked. This only makes sense when run within a top-level splice.
+--
+-- The finalizer is given the local type environment at the splice point. Thus
+-- 'reify' is able to find the local definitions when executed inside the
+-- finalizer.
+addModFinalizer :: Q () -> Q ()
+addModFinalizer act = Q (qAddModFinalizer (unQ act))
+
+-- | Adds a core plugin to the compilation pipeline.
+--
+-- @addCorePlugin m@ has almost the same effect as passing @-fplugin=m@ to ghc
+-- in the command line. The major difference is that the plugin module @m@
+-- must not belong to the current package. When TH executes, it is too late
+-- to tell the compiler that we needed to compile first a plugin module in the
+-- current package.
+addCorePlugin :: String -> Q ()
+addCorePlugin plugin = Q (qAddCorePlugin plugin)
+
+-- | Get state from the 'Q' monad. Note that the state is local to the
+-- Haskell module in which the Template Haskell expression is executed.
+getQ :: Typeable a => Q (Maybe a)
+getQ = Q qGetQ
+
+-- | Replace the state in the 'Q' monad. Note that the state is local to the
+-- Haskell module in which the Template Haskell expression is executed.
+putQ :: Typeable a => a -> Q ()
+putQ x = Q (qPutQ x)
+
+-- | Determine whether the given language extension is enabled in the 'Q' monad.
+isExtEnabled :: Extension -> Q Bool
+isExtEnabled ext = Q (qIsExtEnabled ext)
+
+-- | List all enabled language extensions.
+extsEnabled :: Q [Extension]
+extsEnabled = Q qExtsEnabled
+
+-- | Add Haddock documentation to the specified location. This will overwrite
+-- any documentation at the location if it already exists. This will reify the
+-- specified name, so it must be in scope when you call it. If you want to add
+-- documentation to something that you are currently splicing, you can use
+-- 'addModFinalizer' e.g.
+--
+-- > do
+-- > let nm = mkName "x"
+-- > addModFinalizer $ putDoc (DeclDoc nm) "Hello"
+-- > [d| $(varP nm) = 42 |]
+--
+-- The helper functions 'withDecDoc' and 'withDecsDoc' will do this for you, as
+-- will the 'funD_doc' and other @_doc@ combinators.
+-- You most likely want to have the @-haddock@ flag turned on when using this.
+-- Adding documentation to anything outside of the current module will cause an
+-- error.
+putDoc :: DocLoc -> String -> Q ()
+putDoc t s = Q (qPutDoc t s)
+
+-- | Retrieves the Haddock documentation at the specified location, if one
+-- exists.
+-- It can be used to read documentation on things defined outside of the current
+-- module, provided that those modules were compiled with the @-haddock@ flag.
+getDoc :: DocLoc -> Q (Maybe String)
+getDoc n = Q (qGetDoc n)
+
+instance MonadIO Q where
+ liftIO = runIO
+
+instance Quasi Q where
+ qNewName = newName
+ qReport = report
+ qRecover = recover
+ qReify = reify
+ qReifyFixity = reifyFixity
+ qReifyType = reifyType
+ qReifyInstances = reifyInstances
+ qReifyRoles = reifyRoles
+ qReifyAnnotations = reifyAnnotations
+ qReifyModule = reifyModule
+ qReifyConStrictness = reifyConStrictness
+ qLookupName = lookupName
+ qLocation = location
+ qGetPackageRoot = getPackageRoot
+ qAddDependentFile = addDependentFile
+ qAddTempFile = addTempFile
+ qAddTopDecls = addTopDecls
+ qAddForeignFilePath = addForeignFilePath
+ qAddModFinalizer = addModFinalizer
+ qAddCorePlugin = addCorePlugin
+ qGetQ = getQ
+ qPutQ = putQ
+ qIsExtEnabled = isExtEnabled
+ qExtsEnabled = extsEnabled
+ qPutDoc = putDoc
+ qGetDoc = getDoc
+
+
+----------------------------------------------------
+-- The following operations are used solely in GHC.HsToCore.Quote when
+-- desugaring brackets. They are not necessary for the user, who can use
+-- ordinary return and (>>=) etc
+
+-- | This function is only used in 'GHC.HsToCore.Quote' when desugaring
+-- brackets. This is not necessary for the user, who can use the ordinary
+-- 'return' and '(>>=)' operations.
+sequenceQ :: forall m . Monad m => forall a . [m a] -> m [a]
+sequenceQ = sequence
=====================================
libraries/ghc-internal/src/GHC/Internal/TH/Quote.hs
=====================================
@@ -20,6 +20,7 @@ module GHC.Internal.TH.Quote(
) where
import GHC.Internal.TH.Syntax
+import GHC.Internal.TH.Monad
import GHC.Internal.Base hiding (Type)
=====================================
libraries/ghc-internal/src/GHC/Internal/TH/Syntax.hs
=====================================
@@ -1,14 +1,16 @@
{-# OPTIONS_HADDOCK not-home #-} -- we want users to import Language.Haskell.TH.Syntax instead
-{-# LANGUAGE CPP, DeriveDataTypeable,
- DeriveGeneric, FlexibleInstances, DefaultSignatures,
- RankNTypes, RoleAnnotations, ScopedTypeVariables,
- MagicHash, KindSignatures, PolyKinds, TypeApplications, DataKinds,
- GADTs, UnboxedTuples, UnboxedSums, TypeOperators,
- Trustworthy, DeriveFunctor, DeriveTraversable,
- BangPatterns, RecordWildCards, ImplicitParams #-}
-
-{-# LANGUAGE TemplateHaskellQuotes #-}
-{-# LANGUAGE StandaloneKindSignatures #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE DeriveTraversable #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE RoleAnnotations #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE Trustworthy #-}
+{-# LANGUAGE UnboxedTuples #-}
-- | This module is used internally in GHC's integration with Template Haskell
-- and defines the abstract syntax of Template Haskell.
@@ -26,971 +28,37 @@ module GHC.Internal.TH.Syntax
#ifdef BOOTSTRAP_TH
import Prelude
-import Data.Data hiding (Fixity(..))
-import Data.IORef
import System.IO.Unsafe ( unsafePerformIO )
-import Control.Monad.IO.Class (MonadIO (..))
-import Control.Monad.Fix (MonadFix (..))
-import Control.Exception (BlockedIndefinitelyOnMVar (..), catch, throwIO)
-import Control.Exception.Base (FixIOException (..))
-import Control.Concurrent.MVar (newEmptyMVar, readMVar, putMVar)
-import System.IO ( hPutStrLn, stderr )
import Data.Char ( isAlpha, isAlphaNum, isUpper )
import Data.List.NonEmpty ( NonEmpty(..) )
import Data.Word
-import qualified Data.Kind as Kind (Type)
import Foreign.ForeignPtr
import Foreign.C.String
import Foreign.C.Types
-import GHC.IO.Unsafe ( unsafeDupableInterleaveIO )
import GHC.Ptr ( Ptr, plusPtr )
import GHC.Generics ( Generic )
-import GHC.Types (TYPE, RuntimeRep(..))
#else
import GHC.Internal.Base hiding (NonEmpty(..),Type, Module, sequence)
-import GHC.Internal.Data.Data hiding (Fixity(..))
import GHC.Internal.Data.NonEmpty (NonEmpty(..))
import GHC.Internal.Data.Traversable
import GHC.Internal.Word
import GHC.Internal.Generics (Generic)
-import GHC.Internal.IORef
-import GHC.Internal.System.IO
import GHC.Internal.Show
import GHC.Internal.Integer
import GHC.Internal.Real
import GHC.Internal.Data.Foldable
import GHC.Internal.Foreign.Ptr
import GHC.Internal.ForeignPtr
-import GHC.Internal.Data.Typeable
-import GHC.Internal.Control.Monad.IO.Class
import GHC.Internal.Foreign.C.Types
import GHC.Internal.Foreign.C.String
-import GHC.Internal.Control.Monad.Fail
-import GHC.Internal.Control.Monad.Fix
-import GHC.Internal.Control.Exception
import GHC.Internal.Num
import GHC.Internal.IO.Unsafe
import GHC.Internal.List (dropWhile, break, replicate, reverse, last)
-import GHC.Internal.MVar
-import GHC.Internal.IO.Exception
import GHC.Internal.Unicode
-import qualified GHC.Internal.Types as Kind (Type)
#endif
import GHC.Internal.ForeignSrcLang
import GHC.Internal.LanguageExtensions
------------------------------------------------------
---
--- The Quasi class
---
------------------------------------------------------
-
-class (MonadIO m, MonadFail m) => Quasi m where
- -- | Fresh names. See 'newName'.
- qNewName :: String -> m Name
-
- ------- Error reporting and recovery -------
- -- | Report an error (True) or warning (False)
- -- ...but carry on; use 'fail' to stop. See 'report'.
- qReport :: Bool -> String -> m ()
-
- -- | See 'recover'.
- qRecover :: m a -- ^ the error handler
- -> m a -- ^ action which may fail
- -> m a -- ^ Recover from the monadic 'fail'
-
- ------- Inspect the type-checker's environment -------
- -- | True <=> type namespace, False <=> value namespace. See 'lookupName'.
- qLookupName :: Bool -> String -> m (Maybe Name)
- -- | See 'reify'.
- qReify :: Name -> m Info
- -- | See 'reifyFixity'.
- qReifyFixity :: Name -> m (Maybe Fixity)
- -- | See 'reifyType'.
- qReifyType :: Name -> m Type
- -- | Is (n tys) an instance? Returns list of matching instance Decs (with
- -- empty sub-Decs) Works for classes and type functions. See 'reifyInstances'.
- qReifyInstances :: Name -> [Type] -> m [Dec]
- -- | See 'reifyRoles'.
- qReifyRoles :: Name -> m [Role]
- -- | See 'reifyAnnotations'.
- qReifyAnnotations :: Data a => AnnLookup -> m [a]
- -- | See 'reifyModule'.
- qReifyModule :: Module -> m ModuleInfo
- -- | See 'reifyConStrictness'.
- qReifyConStrictness :: Name -> m [DecidedStrictness]
-
- -- | See 'location'.
- qLocation :: m Loc
-
- -- | Input/output (dangerous). See 'runIO'.
- qRunIO :: IO a -> m a
- qRunIO = liftIO
- -- | See 'getPackageRoot'.
- qGetPackageRoot :: m FilePath
-
- -- | See 'addDependentFile'.
- qAddDependentFile :: FilePath -> m ()
-
- -- | See 'addTempFile'.
- qAddTempFile :: String -> m FilePath
-
- -- | See 'addTopDecls'.
- qAddTopDecls :: [Dec] -> m ()
-
- -- | See 'addForeignFilePath'.
- qAddForeignFilePath :: ForeignSrcLang -> String -> m ()
-
- -- | See 'addModFinalizer'.
- qAddModFinalizer :: Q () -> m ()
-
- -- | See 'addCorePlugin'.
- qAddCorePlugin :: String -> m ()
-
- -- | See 'getQ'.
- qGetQ :: Typeable a => m (Maybe a)
-
- -- | See 'putQ'.
- qPutQ :: Typeable a => a -> m ()
-
- -- | See 'isExtEnabled'.
- qIsExtEnabled :: Extension -> m Bool
- -- | See 'extsEnabled'.
- qExtsEnabled :: m [Extension]
-
- -- | See 'putDoc'.
- qPutDoc :: DocLoc -> String -> m ()
- -- | See 'getDoc'.
- qGetDoc :: DocLoc -> m (Maybe String)
-
------------------------------------------------------
--- The IO instance of Quasi
------------------------------------------------------
-
--- | This instance is used only when running a Q
--- computation in the IO monad, usually just to
--- print the result. There is no interesting
--- type environment, so reification isn't going to
--- work.
-instance Quasi IO where
- qNewName = newNameIO
-
- qReport True msg = hPutStrLn stderr ("Template Haskell error: " ++ msg)
- qReport False msg = hPutStrLn stderr ("Template Haskell error: " ++ msg)
-
- qLookupName _ _ = badIO "lookupName"
- qReify _ = badIO "reify"
- qReifyFixity _ = badIO "reifyFixity"
- qReifyType _ = badIO "reifyFixity"
- qReifyInstances _ _ = badIO "reifyInstances"
- qReifyRoles _ = badIO "reifyRoles"
- qReifyAnnotations _ = badIO "reifyAnnotations"
- qReifyModule _ = badIO "reifyModule"
- qReifyConStrictness _ = badIO "reifyConStrictness"
- qLocation = badIO "currentLocation"
- qRecover _ _ = badIO "recover" -- Maybe we could fix this?
- qGetPackageRoot = badIO "getProjectRoot"
- qAddDependentFile _ = badIO "addDependentFile"
- qAddTempFile _ = badIO "addTempFile"
- qAddTopDecls _ = badIO "addTopDecls"
- qAddForeignFilePath _ _ = badIO "addForeignFilePath"
- qAddModFinalizer _ = badIO "addModFinalizer"
- qAddCorePlugin _ = badIO "addCorePlugin"
- qGetQ = badIO "getQ"
- qPutQ _ = badIO "putQ"
- qIsExtEnabled _ = badIO "isExtEnabled"
- qExtsEnabled = badIO "extsEnabled"
- qPutDoc _ _ = badIO "putDoc"
- qGetDoc _ = badIO "getDoc"
-
-instance Quote IO where
- newName = newNameIO
-
-newNameIO :: String -> IO Name
-newNameIO s = do { n <- atomicModifyIORef' counter (\x -> (x + 1, x))
- ; pure (mkNameU s n) }
-
-badIO :: String -> IO a
-badIO op = do { qReport True ("Can't do `" ++ op ++ "' in the IO monad")
- ; fail "Template Haskell failure" }
-
--- Global variable to generate unique symbols
-counter :: IORef Uniq
-{-# NOINLINE counter #-}
-counter = unsafePerformIO (newIORef 0)
-
-
------------------------------------------------------
---
--- The Q monad
---
------------------------------------------------------
-
--- | In short, 'Q' provides the 'Quasi' operations in one neat monad for the
--- user.
---
--- The longer story, is that 'Q' wraps an arbitrary 'Quasi'-able monad.
--- The perceptive reader notices that 'Quasi' has only two instances, 'Q'
--- itself and 'IO', neither of which have concrete implementations.'Q' plays
--- the trick of [dependency
--- inversion](https://en.wikipedia.org/wiki/Dependency_inversion_principle),
--- providing an abstract interface for the user which is later concretely
--- fufilled by an concrete 'Quasi' instance, internal to GHC.
-newtype Q a = Q { unQ :: forall m. Quasi m => m a }
-
--- | \"Runs\" the 'Q' monad. Normal users of Template Haskell
--- should not need this function, as the splice brackets @$( ... )@
--- are the usual way of running a 'Q' computation.
---
--- This function is primarily used in GHC internals, and for debugging
--- splices by running them in 'IO'.
---
--- Note that many functions in 'Q', such as 'reify' and other compiler
--- queries, are not supported when running 'Q' in 'IO'; these operations
--- simply fail at runtime. Indeed, the only operations guaranteed to succeed
--- are 'newName', 'runIO', 'reportError' and 'reportWarning'.
-runQ :: Quasi m => Q a -> m a
-runQ (Q m) = m
-
-instance Monad Q where
- Q m >>= k = Q (m >>= \x -> unQ (k x))
- (>>) = (*>)
-
-instance MonadFail Q where
- fail s = report True s >> Q (fail "Q monad failure")
-
-instance Functor Q where
- fmap f (Q x) = Q (fmap f x)
-
-instance Applicative Q where
- pure x = Q (pure x)
- Q f <*> Q x = Q (f <*> x)
- Q m *> Q n = Q (m *> n)
-
--- | @since 2.17.0.0
-instance Semigroup a => Semigroup (Q a) where
- (<>) = liftA2 (<>)
-
--- | @since 2.17.0.0
-instance Monoid a => Monoid (Q a) where
- mempty = pure mempty
-
--- | If the function passed to 'mfix' inspects its argument,
--- the resulting action will throw a 'FixIOException'.
---
--- @since 2.17.0.0
-instance MonadFix Q where
- -- We use the same blackholing approach as in fixIO.
- -- See Note [Blackholing in fixIO] in System.IO in base.
- mfix k = do
- m <- runIO newEmptyMVar
- ans <- runIO (unsafeDupableInterleaveIO
- (readMVar m `catch` \BlockedIndefinitelyOnMVar ->
- throwIO FixIOException))
- result <- k ans
- runIO (putMVar m result)
- return result
-
-
------------------------------------------------------
---
--- The Quote class
---
------------------------------------------------------
-
-
-
--- | The 'Quote' class implements the minimal interface which is necessary for
--- desugaring quotations.
---
--- * The @Monad m@ superclass is needed to stitch together the different
--- AST fragments.
--- * 'newName' is used when desugaring binding structures such as lambdas
--- to generate fresh names.
---
--- Therefore the type of an untyped quotation in GHC is `Quote m => m Exp`
---
--- For many years the type of a quotation was fixed to be `Q Exp` but by
--- more precisely specifying the minimal interface it enables the `Exp` to
--- be extracted purely from the quotation without interacting with `Q`.
-class Monad m => Quote m where
- {- |
- Generate a fresh name, which cannot be captured.
-
- For example, this:
-
- @f = $(do
- nm1 <- newName \"x\"
- let nm2 = 'mkName' \"x\"
- return ('LamE' ['VarP' nm1] (LamE [VarP nm2] ('VarE' nm1)))
- )@
-
- will produce the splice
-
- >f = \x0 -> \x -> x0
-
- In particular, the occurrence @VarE nm1@ refers to the binding @VarP nm1@,
- and is not captured by the binding @VarP nm2@.
-
- Although names generated by @newName@ cannot /be captured/, they can
- /capture/ other names. For example, this:
-
- >g = $(do
- > nm1 <- newName "x"
- > let nm2 = mkName "x"
- > return (LamE [VarP nm2] (LamE [VarP nm1] (VarE nm2)))
- > )
-
- will produce the splice
-
- >g = \x -> \x0 -> x0
-
- since the occurrence @VarE nm2@ is captured by the innermost binding
- of @x@, namely @VarP nm1@.
- -}
- newName :: String -> m Name
-
-instance Quote Q where
- newName s = Q (qNewName s)
-
------------------------------------------------------
---
--- The TExp type
---
------------------------------------------------------
-
-type TExp :: TYPE r -> Kind.Type
-type role TExp nominal -- See Note [Role of TExp]
-newtype TExp a = TExp
- { unType :: Exp -- ^ Underlying untyped Template Haskell expression
- }
--- ^ Typed wrapper around an 'Exp'.
---
--- This is the typed representation of terms produced by typed quotes.
---
--- Representation-polymorphic since /template-haskell-2.16.0.0/.
-
--- | Discard the type annotation and produce a plain Template Haskell
--- expression
---
--- Representation-polymorphic since /template-haskell-2.16.0.0/.
-unTypeQ :: forall (r :: RuntimeRep) (a :: TYPE r) m . Quote m => m (TExp a) -> m Exp
-unTypeQ m = do { TExp e <- m
- ; return e }
-
--- | Annotate the Template Haskell expression with a type
---
--- This is unsafe because GHC cannot check for you that the expression
--- really does have the type you claim it has.
---
--- Representation-polymorphic since /template-haskell-2.16.0.0/.
-unsafeTExpCoerce :: forall (r :: RuntimeRep) (a :: TYPE r) m .
- Quote m => m Exp -> m (TExp a)
-unsafeTExpCoerce m = do { e <- m
- ; return (TExp e) }
-
-{- Note [Role of TExp]
-~~~~~~~~~~~~~~~~~~~~~~
-TExp's argument must have a nominal role, not phantom as would
-be inferred (#8459). Consider
-
- e :: Code Q Age
- e = [|| MkAge 3 ||]
-
- foo = $(coerce e) + 4::Int
-
-The splice will evaluate to (MkAge 3) and you can't add that to
-4::Int. So you can't coerce a (Code Q Age) to a (Code Q Int). -}
-
--- Code constructor
-#if __GLASGOW_HASKELL__ >= 909
-type Code :: (Kind.Type -> Kind.Type) -> forall r. TYPE r -> Kind.Type
- -- See Note [Foralls to the right in Code]
-#else
-type Code :: (Kind.Type -> Kind.Type) -> TYPE r -> Kind.Type
-#endif
-type role Code representational nominal -- See Note [Role of TExp]
-newtype Code m a = Code
- { examineCode :: m (TExp a) -- ^ Underlying monadic value
- }
--- ^ Represents an expression which has type @a@, built in monadic context @m@. Built on top of 'TExp', typed
--- expressions allow for type-safe splicing via:
---
--- - typed quotes, written as @[|| ... ||]@ where @...@ is an expression; if
--- that expression has type @a@, then the quotation has type
--- @Quote m => Code m a@
---
--- - typed splices inside of typed quotes, written as @$$(...)@ where @...@
--- is an arbitrary expression of type @Quote m => Code m a@
---
--- Traditional expression quotes and splices let us construct ill-typed
--- expressions:
---
--- >>> fmap ppr $ runQ (unTypeCode [| True == $( [| "foo" |] ) |])
--- GHC.Internal.Types.True GHC.Internal.Classes.== "foo"
--- >>> GHC.Internal.Types.True GHC.Internal.Classes.== "foo"
--- <interactive> error:
--- • Couldn't match expected type ‘Bool’ with actual type ‘[Char]’
--- • In the second argument of ‘(==)’, namely ‘"foo"’
--- In the expression: True == "foo"
--- In an equation for ‘it’: it = True == "foo"
---
--- With typed expressions, the type error occurs when /constructing/ the
--- Template Haskell expression:
---
--- >>> fmap ppr $ runQ (unTypeCode [|| True == $$( [|| "foo" ||] ) ||])
--- <interactive> error:
--- • Couldn't match type ‘[Char]’ with ‘Bool’
--- Expected type: Code Q Bool
--- Actual type: Code Q [Char]
--- • In the Template Haskell quotation [|| "foo" ||]
--- In the expression: [|| "foo" ||]
--- In the Template Haskell splice $$([|| "foo" ||])
-
-
-{- Note [Foralls to the right in Code]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Code has the following type signature:
- type Code :: (Kind.Type -> Kind.Type) -> forall r. TYPE r -> Kind.Type
-
-This allows us to write
- data T (f :: forall r . (TYPE r) -> Type) = MkT (f Int) (f Int#)
-
- tcodeq :: T (Code Q)
- tcodeq = MkT [||5||] [||5#||]
-
-If we used the slightly more straightforward signature
- type Code :: foral r. (Kind.Type -> Kind.Type) -> TYPE r -> Kind.Type
-
-then the example above would become ill-typed. (See #23592 for some discussion.)
--}
-
--- | Unsafely convert an untyped code representation into a typed code
--- representation.
-unsafeCodeCoerce :: forall (r :: RuntimeRep) (a :: TYPE r) m .
- Quote m => m Exp -> Code m a
-unsafeCodeCoerce m = Code (unsafeTExpCoerce m)
-
--- | Lift a monadic action producing code into the typed 'Code'
--- representation
-liftCode :: forall (r :: RuntimeRep) (a :: TYPE r) m . m (TExp a) -> Code m a
-liftCode = Code
-
--- | Extract the untyped representation from the typed representation
-unTypeCode :: forall (r :: RuntimeRep) (a :: TYPE r) m . Quote m
- => Code m a -> m Exp
-unTypeCode = unTypeQ . examineCode
-
--- | Modify the ambient monad used during code generation. For example, you
--- can use `hoistCode` to handle a state effect:
--- @
--- handleState :: Code (StateT Int Q) a -> Code Q a
--- handleState = hoistCode (flip runState 0)
--- @
-hoistCode :: forall m n (r :: RuntimeRep) (a :: TYPE r) . Monad m
- => (forall x . m x -> n x) -> Code m a -> Code n a
-hoistCode f (Code a) = Code (f a)
-
-
--- | Variant of '(>>=)' which allows effectful computations to be injected
--- into code generation.
-bindCode :: forall m a (r :: RuntimeRep) (b :: TYPE r) . Monad m
- => m a -> (a -> Code m b) -> Code m b
-bindCode q k = liftCode (q >>= examineCode . k)
-
--- | Variant of '(>>)' which allows effectful computations to be injected
--- into code generation.
-bindCode_ :: forall m a (r :: RuntimeRep) (b :: TYPE r) . Monad m
- => m a -> Code m b -> Code m b
-bindCode_ q c = liftCode ( q >> examineCode c)
-
--- | A useful combinator for embedding monadic actions into 'Code'
--- @
--- myCode :: ... => Code m a
--- myCode = joinCode $ do
--- x <- someSideEffect
--- return (makeCodeWith x)
--- @
-joinCode :: forall m (r :: RuntimeRep) (a :: TYPE r) . Monad m
- => m (Code m a) -> Code m a
-joinCode = flip bindCode id
-
-----------------------------------------------------
--- Packaged versions for the programmer, hiding the Quasi-ness
-
-
--- | Report an error (True) or warning (False),
--- but carry on; use 'fail' to stop.
-report :: Bool -> String -> Q ()
-report b s = Q (qReport b s)
-{-# DEPRECATED report "Use reportError or reportWarning instead" #-} -- deprecated in 7.6
-
--- | Report an error to the user, but allow the current splice's computation to carry on. To abort the computation, use 'fail'.
-reportError :: String -> Q ()
-reportError = report True
-
--- | Report a warning to the user, and carry on.
-reportWarning :: String -> Q ()
-reportWarning = report False
-
--- | Recover from errors raised by 'reportError' or 'fail'.
-recover :: Q a -- ^ handler to invoke on failure
- -> Q a -- ^ computation to run
- -> Q a
-recover (Q r) (Q m) = Q (qRecover r m)
-
--- We don't export lookupName; the Bool isn't a great API
--- Instead we export lookupTypeName, lookupValueName
-lookupName :: Bool -> String -> Q (Maybe Name)
-lookupName ns s = Q (qLookupName ns s)
-
--- | Look up the given name in the (type namespace of the) current splice's scope. See "Language.Haskell.TH.Syntax#namelookup" for more details.
-lookupTypeName :: String -> Q (Maybe Name)
-lookupTypeName s = Q (qLookupName True s)
-
--- | Look up the given name in the (value namespace of the) current splice's scope. See "Language.Haskell.TH.Syntax#namelookup" for more details.
-lookupValueName :: String -> Q (Maybe Name)
-lookupValueName s = Q (qLookupName False s)
-
-{-
-Note [Name lookup]
-~~~~~~~~~~~~~~~~~~
--}
-{- $namelookup #namelookup#
-The functions 'lookupTypeName' and 'lookupValueName' provide
-a way to query the current splice's context for what names
-are in scope. The function 'lookupTypeName' queries the type
-namespace, whereas 'lookupValueName' queries the value namespace,
-but the functions are otherwise identical.
-
-A call @lookupValueName s@ will check if there is a value
-with name @s@ in scope at the current splice's location. If
-there is, the @Name@ of this value is returned;
-if not, then @Nothing@ is returned.
-
-The returned name cannot be \"captured\".
-For example:
-
-> f = "global"
-> g = $( do
-> Just nm <- lookupValueName "f"
-> [| let f = "local" in $( varE nm ) |]
-
-In this case, @g = \"global\"@; the call to @lookupValueName@
-returned the global @f@, and this name was /not/ captured by
-the local definition of @f@.
-
-The lookup is performed in the context of the /top-level/ splice
-being run. For example:
-
-> f = "global"
-> g = $( [| let f = "local" in
-> $(do
-> Just nm <- lookupValueName "f"
-> varE nm
-> ) |] )
-
-Again in this example, @g = \"global\"@, because the call to
-@lookupValueName@ queries the context of the outer-most @$(...)@.
-
-Operators should be queried without any surrounding parentheses, like so:
-
-> lookupValueName "+"
-
-Qualified names are also supported, like so:
-
-> lookupValueName "Prelude.+"
-> lookupValueName "Prelude.map"
-
--}
-
-
-{- | 'reify' looks up information about the 'Name'. It will fail with
-a compile error if the 'Name' is not visible. A 'Name' is visible if it is
-imported or defined in a prior top-level declaration group. See the
-documentation for 'newDeclarationGroup' for more details.
-
-It is sometimes useful to construct the argument name using 'lookupTypeName' or 'lookupValueName'
-to ensure that we are reifying from the right namespace. For instance, in this context:
-
-> data D = D
-
-which @D@ does @reify (mkName \"D\")@ return information about? (Answer: @D@-the-type, but don't rely on it.)
-To ensure we get information about @D@-the-value, use 'lookupValueName':
-
-> do
-> Just nm <- lookupValueName "D"
-> reify nm
-
-and to get information about @D@-the-type, use 'lookupTypeName'.
--}
-reify :: Name -> Q Info
-reify v = Q (qReify v)
-
-{- | @reifyFixity nm@ attempts to find a fixity declaration for @nm@. For
-example, if the function @foo@ has the fixity declaration @infixr 7 foo@, then
-@reifyFixity 'foo@ would return @'Just' ('Fixity' 7 'InfixR')@. If the function
-@bar@ does not have a fixity declaration, then @reifyFixity 'bar@ returns
-'Nothing', so you may assume @bar@ has 'defaultFixity'.
--}
-reifyFixity :: Name -> Q (Maybe Fixity)
-reifyFixity nm = Q (qReifyFixity nm)
-
-{- | @reifyType nm@ attempts to find the type or kind of @nm@. For example,
-@reifyType 'not@ returns @Bool -> Bool@, and
-@reifyType ''Bool@ returns @Type@.
-This works even if there's no explicit signature and the type or kind is inferred.
--}
-reifyType :: Name -> Q Type
-reifyType nm = Q (qReifyType nm)
-
-{- | Template Haskell is capable of reifying information about types and
-terms defined in previous declaration groups. Top-level declaration splices break up
-declaration groups.
-
-For an example, consider this code block. We define a datatype @X@ and
-then try to call 'reify' on the datatype.
-
-@
-module Check where
-
-data X = X
- deriving Eq
-
-$(do
- info <- reify ''X
- runIO $ print info
- )
-@
-
-This code fails to compile, noting that @X@ is not available for reification at the site of 'reify'. We can fix this by creating a new declaration group using an empty top-level splice:
-
-@
-data X = X
- deriving Eq
-
-$(pure [])
-
-$(do
- info <- reify ''X
- runIO $ print info
- )
-@
-
-We provide 'newDeclarationGroup' as a means of documenting this behavior
-and providing a name for the pattern.
-
-Since top level splices infer the presence of the @$( ... )@ brackets, we can also write:
-
-@
-data X = X
- deriving Eq
-
-newDeclarationGroup
-
-$(do
- info <- reify ''X
- runIO $ print info
- )
-@
-
--}
-newDeclarationGroup :: Q [Dec]
-newDeclarationGroup = pure []
-
-{- | @reifyInstances nm tys@ returns a list of all visible instances (see below for "visible")
-of @nm tys@. That is,
-if @nm@ is the name of a type class, then all instances of this class at the types @tys@
-are returned. Alternatively, if @nm@ is the name of a data family or type family,
-all instances of this family at the types @tys@ are returned.
-
-Note that this is a \"shallow\" test; the declarations returned merely have
-instance heads which unify with @nm tys@, they need not actually be satisfiable.
-
- - @reifyInstances ''Eq [ 'TupleT' 2 \``AppT`\` 'ConT' ''A \``AppT`\` 'ConT' ''B ]@ contains
- the @instance (Eq a, Eq b) => Eq (a, b)@ regardless of whether @A@ and
- @B@ themselves implement 'Eq'
-
- - @reifyInstances ''Show [ 'VarT' ('mkName' "a") ]@ produces every available
- instance of 'Show'
-
-There is one edge case: @reifyInstances ''Typeable tys@ currently always
-produces an empty list (no matter what @tys@ are given).
-
-In principle, the *visible* instances are
-* all instances defined in a prior top-level declaration group
- (see docs on @newDeclarationGroup@), or
-* all instances defined in any module transitively imported by the
- module being compiled
-
-However, actually searching all modules transitively below the one being
-compiled is unreasonably expensive, so @reifyInstances@ will report only the
-instance for modules that GHC has had some cause to visit during this
-compilation. This is a shortcoming: @reifyInstances@ might fail to report
-instances for a type that is otherwise unusued, or instances defined in a
-different component. You can work around this shortcoming by explicitly importing the modules
-whose instances you want to be visible. GHC issue <https://gitlab.haskell.org/ghc/ghc/-/issues/20529#note_388980 #20529>
-has some discussion around this.
-
--}
-reifyInstances :: Name -> [Type] -> Q [InstanceDec]
-reifyInstances cls tys = Q (qReifyInstances cls tys)
-
-{- | @reifyRoles nm@ returns the list of roles associated with the parameters
-(both visible and invisible) of
-the tycon @nm@. Fails if @nm@ cannot be found or is not a tycon.
-The returned list should never contain 'InferR'.
-
-An invisible parameter to a tycon is often a kind parameter. For example, if
-we have
-
-@
-type Proxy :: forall k. k -> Type
-data Proxy a = MkProxy
-@
-
-and @reifyRoles Proxy@, we will get @['NominalR', 'PhantomR']@. The 'NominalR' is
-the role of the invisible @k@ parameter. Kind parameters are always nominal.
--}
-reifyRoles :: Name -> Q [Role]
-reifyRoles nm = Q (qReifyRoles nm)
-
--- | @reifyAnnotations target@ returns the list of annotations
--- associated with @target@. Only the annotations that are
--- appropriately typed is returned. So if you have @Int@ and @String@
--- annotations for the same target, you have to call this function twice.
-reifyAnnotations :: Data a => AnnLookup -> Q [a]
-reifyAnnotations an = Q (qReifyAnnotations an)
-
--- | @reifyModule mod@ looks up information about module @mod@. To
--- look up the current module, call this function with the return
--- value of 'Language.Haskell.TH.Lib.thisModule'.
-reifyModule :: Module -> Q ModuleInfo
-reifyModule m = Q (qReifyModule m)
-
--- | @reifyConStrictness nm@ looks up the strictness information for the fields
--- of the constructor with the name @nm@. Note that the strictness information
--- that 'reifyConStrictness' returns may not correspond to what is written in
--- the source code. For example, in the following data declaration:
---
--- @
--- data Pair a = Pair a a
--- @
---
--- 'reifyConStrictness' would return @['DecidedLazy', DecidedLazy]@ under most
--- circumstances, but it would return @['DecidedStrict', DecidedStrict]@ if the
--- @-XStrictData@ language extension was enabled.
-reifyConStrictness :: Name -> Q [DecidedStrictness]
-reifyConStrictness n = Q (qReifyConStrictness n)
-
--- | Is the list of instances returned by 'reifyInstances' nonempty?
---
--- If you're confused by an instance not being visible despite being
--- defined in the same module and above the splice in question, see the
--- docs for 'newDeclarationGroup' for a possible explanation.
-isInstance :: Name -> [Type] -> Q Bool
-isInstance nm tys = do { decs <- reifyInstances nm tys
- ; return (not (null decs)) }
-
--- | The location at which this computation is spliced.
-location :: Q Loc
-location = Q qLocation
-
--- |The 'runIO' function lets you run an I\/O computation in the 'Q' monad.
--- Take care: you are guaranteed the ordering of calls to 'runIO' within
--- a single 'Q' computation, but not about the order in which splices are run.
---
--- Note: for various murky reasons, stdout and stderr handles are not
--- necessarily flushed when the compiler finishes running, so you should
--- flush them yourself.
-runIO :: IO a -> Q a
-runIO m = Q (qRunIO m)
-
--- | Get the package root for the current package which is being compiled.
--- This can be set explicitly with the -package-root flag but is normally
--- just the current working directory.
---
--- The motivation for this flag is to provide a principled means to remove the
--- assumption from splices that they will be executed in the directory where the
--- cabal file resides. Projects such as haskell-language-server can't and don't
--- change directory when compiling files but instead set the -package-root flag
--- appropriately.
-getPackageRoot :: Q FilePath
-getPackageRoot = Q qGetPackageRoot
-
-
-
--- | Record external files that runIO is using (dependent upon).
--- The compiler can then recognize that it should re-compile the Haskell file
--- when an external file changes.
---
--- Expects an absolute file path.
---
--- Notes:
---
--- * ghc -M does not know about these dependencies - it does not execute TH.
---
--- * The dependency is based on file content, not a modification time
-addDependentFile :: FilePath -> Q ()
-addDependentFile fp = Q (qAddDependentFile fp)
-
--- | Obtain a temporary file path with the given suffix. The compiler will
--- delete this file after compilation.
-addTempFile :: String -> Q FilePath
-addTempFile suffix = Q (qAddTempFile suffix)
-
--- | Add additional top-level declarations. The added declarations will be type
--- checked along with the current declaration group.
-addTopDecls :: [Dec] -> Q ()
-addTopDecls ds = Q (qAddTopDecls ds)
-
-
--- | Emit a foreign file which will be compiled and linked to the object for
--- the current module. Currently only languages that can be compiled with
--- the C compiler are supported, and the flags passed as part of -optc will
--- be also applied to the C compiler invocation that will compile them.
---
--- Note that for non-C languages (for example C++) @extern "C"@ directives
--- must be used to get symbols that we can access from Haskell.
---
--- To get better errors, it is recommended to use #line pragmas when
--- emitting C files, e.g.
---
--- > {-# LANGUAGE CPP #-}
--- > ...
--- > addForeignSource LangC $ unlines
--- > [ "#line " ++ show (__LINE__ + 1) ++ " " ++ show __FILE__
--- > , ...
--- > ]
-addForeignSource :: ForeignSrcLang -> String -> Q ()
-addForeignSource lang src = do
- let suffix = case lang of
- LangC -> "c"
- LangCxx -> "cpp"
- LangObjc -> "m"
- LangObjcxx -> "mm"
- LangAsm -> "s"
- LangJs -> "js"
- RawObject -> "a"
- path <- addTempFile suffix
- runIO $ writeFile path src
- addForeignFilePath lang path
-
--- | Same as 'addForeignSource', but expects to receive a path pointing to the
--- foreign file instead of a 'String' of its contents. Consider using this in
--- conjunction with 'addTempFile'.
---
--- This is a good alternative to 'addForeignSource' when you are trying to
--- directly link in an object file.
-addForeignFilePath :: ForeignSrcLang -> FilePath -> Q ()
-addForeignFilePath lang fp = Q (qAddForeignFilePath lang fp)
-
--- | Add a finalizer that will run in the Q monad after the current module has
--- been type checked. This only makes sense when run within a top-level splice.
---
--- The finalizer is given the local type environment at the splice point. Thus
--- 'reify' is able to find the local definitions when executed inside the
--- finalizer.
-addModFinalizer :: Q () -> Q ()
-addModFinalizer act = Q (qAddModFinalizer (unQ act))
-
--- | Adds a core plugin to the compilation pipeline.
---
--- @addCorePlugin m@ has almost the same effect as passing @-fplugin=m@ to ghc
--- in the command line. The major difference is that the plugin module @m@
--- must not belong to the current package. When TH executes, it is too late
--- to tell the compiler that we needed to compile first a plugin module in the
--- current package.
-addCorePlugin :: String -> Q ()
-addCorePlugin plugin = Q (qAddCorePlugin plugin)
-
--- | Get state from the 'Q' monad. Note that the state is local to the
--- Haskell module in which the Template Haskell expression is executed.
-getQ :: Typeable a => Q (Maybe a)
-getQ = Q qGetQ
-
--- | Replace the state in the 'Q' monad. Note that the state is local to the
--- Haskell module in which the Template Haskell expression is executed.
-putQ :: Typeable a => a -> Q ()
-putQ x = Q (qPutQ x)
-
--- | Determine whether the given language extension is enabled in the 'Q' monad.
-isExtEnabled :: Extension -> Q Bool
-isExtEnabled ext = Q (qIsExtEnabled ext)
-
--- | List all enabled language extensions.
-extsEnabled :: Q [Extension]
-extsEnabled = Q qExtsEnabled
-
--- | Add Haddock documentation to the specified location. This will overwrite
--- any documentation at the location if it already exists. This will reify the
--- specified name, so it must be in scope when you call it. If you want to add
--- documentation to something that you are currently splicing, you can use
--- 'addModFinalizer' e.g.
---
--- > do
--- > let nm = mkName "x"
--- > addModFinalizer $ putDoc (DeclDoc nm) "Hello"
--- > [d| $(varP nm) = 42 |]
---
--- The helper functions 'withDecDoc' and 'withDecsDoc' will do this for you, as
--- will the 'funD_doc' and other @_doc@ combinators.
--- You most likely want to have the @-haddock@ flag turned on when using this.
--- Adding documentation to anything outside of the current module will cause an
--- error.
-putDoc :: DocLoc -> String -> Q ()
-putDoc t s = Q (qPutDoc t s)
-
--- | Retrieves the Haddock documentation at the specified location, if one
--- exists.
--- It can be used to read documentation on things defined outside of the current
--- module, provided that those modules were compiled with the @-haddock@ flag.
-getDoc :: DocLoc -> Q (Maybe String)
-getDoc n = Q (qGetDoc n)
-
-instance MonadIO Q where
- liftIO = runIO
-
-instance Quasi Q where
- qNewName = newName
- qReport = report
- qRecover = recover
- qReify = reify
- qReifyFixity = reifyFixity
- qReifyType = reifyType
- qReifyInstances = reifyInstances
- qReifyRoles = reifyRoles
- qReifyAnnotations = reifyAnnotations
- qReifyModule = reifyModule
- qReifyConStrictness = reifyConStrictness
- qLookupName = lookupName
- qLocation = location
- qGetPackageRoot = getPackageRoot
- qAddDependentFile = addDependentFile
- qAddTempFile = addTempFile
- qAddTopDecls = addTopDecls
- qAddForeignFilePath = addForeignFilePath
- qAddModFinalizer = addModFinalizer
- qAddCorePlugin = addCorePlugin
- qGetQ = getQ
- qPutQ = putQ
- qIsExtEnabled = isExtEnabled
- qExtsEnabled = extsEnabled
- qPutDoc = putDoc
- qGetDoc = getDoc
-
-
-----------------------------------------------------
--- The following operations are used solely in GHC.HsToCore.Quote when
--- desugaring brackets. They are not necessary for the user, who can use
--- ordinary return and (>>=) etc
-
--- | This function is only used in 'GHC.HsToCore.Quote' when desugaring
--- brackets. This is not necessary for the user, who can use the ordinary
--- 'return' and '(>>=)' operations.
-sequenceQ :: forall m . Monad m => forall a . [m a] -> m [a]
-sequenceQ = sequence
-
oneName, manyName :: Name
-- | Synonym for @''GHC.Internal.Types.One'@, from @ghc-internal@.
oneName = mkNameG DataName "ghc-internal" "GHC.Internal.Types" "One"
@@ -1004,19 +72,19 @@ manyName = mkNameG DataName "ghc-internal" "GHC.Internal.Types" "Many"
-- | The name of a module.
newtype ModName = ModName String -- Module name
- deriving (Show,Eq,Ord,Data,Generic)
+ deriving (Show,Eq,Ord,Generic)
-- | The name of a package.
newtype PkgName = PkgName String -- package name
- deriving (Show,Eq,Ord,Data,Generic)
+ deriving (Show,Eq,Ord,Generic)
-- | Obtained from 'reifyModule' and 'Language.Haskell.TH.Lib.thisModule'.
data Module = Module PkgName ModName -- package qualified module name
- deriving (Show,Eq,Ord,Data,Generic)
+ deriving (Show,Eq,Ord,Generic)
-- | An "Occurence Name".
newtype OccName = OccName String
- deriving (Show,Eq,Ord,Data,Generic)
+ deriving (Show,Eq,Ord,Generic)
-- | Smart constructor for 'ModName'
mkModName :: String -> ModName
@@ -1132,7 +200,7 @@ Names constructed using @newName@ and @mkName@ may be used in bindings
(such as @let x = ...@ or @\x -> ...@), but names constructed using
@lookupValueName@, @lookupTypeName@, @'f@, @''T@ may not.
-}
-data Name = Name OccName NameFlavour deriving (Data, Eq, Generic)
+data Name = Name OccName NameFlavour deriving (Eq, Generic)
instance Ord Name where
-- check if unique is different before looking at strings
@@ -1148,7 +216,7 @@ data NameFlavour
-- An original name (occurrences only, not binders)
-- Need the namespace too to be sure which
-- thing we are naming
- deriving ( Data, Eq, Ord, Show, Generic )
+ deriving ( Eq, Ord, Show, Generic )
data NameSpace = VarName -- ^ Variables
| DataName -- ^ Data constructors
@@ -1162,7 +230,7 @@ data NameSpace = VarName -- ^ Variables
-- of the datatype (regardless of whether this constructor has this field).
-- - For a field of a pattern synonym, this is the name of the pattern synonym.
}
- deriving( Eq, Ord, Show, Data, Generic )
+ deriving( Eq, Ord, Show, Generic )
-- | @Uniq@ is used by GHC to distinguish names from each other.
type Uniq = Integer
@@ -1464,7 +532,7 @@ data Loc
, loc_module :: String
, loc_start :: CharPos
, loc_end :: CharPos }
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
type CharPos = (Int, Int) -- ^ Line and character position
@@ -1547,13 +615,13 @@ data Info
| TyVarI -- Scoped type variable
Name
Type -- What it is bound to
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | Obtained from 'reifyModule' in the 'Q' Monad.
data ModuleInfo =
-- | Contains the import list of the module.
ModuleInfo [Module]
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
{- |
In 'ClassOpI' and 'DataConI', name of the parent class or type
@@ -1591,11 +659,11 @@ type InstanceDec = Dec
-- | Fixity, as specified in a @infix[lr] n@ declaration.
data Fixity = Fixity Int FixityDirection
- deriving( Eq, Ord, Show, Data, Generic )
+ deriving( Eq, Ord, Show, Generic )
-- | The associativity of an operator, as in an @infix@ declaration.
data FixityDirection = InfixL | InfixR | InfixN
- deriving( Eq, Ord, Show, Data, Generic )
+ deriving( Eq, Ord, Show, Generic )
-- | Highest allowed operator precedence for 'Fixity' constructor (answer: 9)
maxPrecedence :: Int
@@ -1628,7 +696,7 @@ data Lit = CharL Char -- ^ @\'c\'@
| StringPrimL [Word8] -- ^ @"string"#@. A primitive C-style string, type 'Addr#'
| BytesPrimL Bytes -- ^ Some raw bytes, type 'Addr#':
| CharPrimL Char -- ^ @\'c\'#@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- We could add Int, Float, Double etc, as we do in HsLit,
-- but that could complicate the
@@ -1650,7 +718,7 @@ data Bytes = Bytes
-- , bytesInitialized :: Bool -- ^ False: only use `bytesSize` to allocate
-- -- an uninitialized region
}
- deriving (Data,Generic)
+ deriving (Generic)
-- We can't derive Show instance for Bytes because we don't want to show the
-- pointer value but the actual bytes (similarly to what ByteString does). See
@@ -1717,14 +785,14 @@ data Pat
| TypeP Type -- ^ @{ type p }@
| InvisP Type -- ^ @{ @p }@
| OrP (NonEmpty Pat) -- ^ @{ p1; p2 }@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | A (field name, pattern) pair. See 'RecP'.
type FieldPat = (Name,Pat)
-- | A @case@-alternative
data Match = Match Pat Body [Dec] -- ^ @case e of { pat -> body where decs }@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | A clause consists of patterns, guards, a body expression, and a list of
-- declarations under a @where@. Clauses are seen in equations for function
@@ -1732,7 +800,7 @@ data Match = Match Pat Body [Dec] -- ^ @case e of { pat -> body where decs }@
-- etc.
data Clause = Clause [Pat] Body [Dec]
-- ^ @f { p1 p2 = body where decs }@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | A Haskell expression.
data Exp
@@ -1827,7 +895,7 @@ data Exp
| ForallE [TyVarBndr Specificity] Exp -- ^ @forall \<vars\>. \<expr\>@
| ForallVisE [TyVarBndr ()] Exp -- ^ @forall \<vars\> -> \<expr\>@
| ConstrainedE [Exp] Exp -- ^ @\<ctxt\> => \<expr\>@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | A (field name, expression) pair. See 'RecConE' and 'RecUpdE'.
type FieldExp = (Name,Exp)
@@ -1841,13 +909,13 @@ data Body
-- | e3 = e4 }
-- where ds@
| NormalB Exp -- ^ @f p { = e } where ds@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | A single guard.
data Guard
= NormalG Exp -- ^ @f x { | odd x } = x@
| PatG [Stmt] -- ^ @f x { | Just y <- x, Just z <- y } = z@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | A single statement, as in @do@-notation.
data Stmt
@@ -1856,14 +924,14 @@ data Stmt
| NoBindS Exp -- ^ @e@
| ParS [[Stmt]] -- ^ @x <- e1 | s2, s3 | s4@ (in 'CompE')
| RecS [Stmt] -- ^ @rec { s1; s2 }@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | A list/enum range expression.
data Range = FromR Exp -- ^ @[n ..]@
| FromThenR Exp Exp -- ^ @[n, m ..]@
| FromToR Exp Exp -- ^ @[n .. m]@
| FromThenToR Exp Exp Exp -- ^ @[n, m .. k]@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | A single declaration.
data Dec
@@ -1950,7 +1018,7 @@ data Dec
--
-- Implicit parameter binding declaration. Can only be used in let
-- and where clauses which consist entirely of implicit bindings.
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | A way to specify a namespace to look in when GHC needs to find
-- a name's source
@@ -1962,7 +1030,7 @@ data NamespaceSpecifier
-- or type variable
| DataNamespaceSpecifier -- ^ Name should be a term-level entity, such as a
-- function, data constructor, or pattern synonym
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | Varieties of allowed instance overlap.
data Overlap = Overlappable -- ^ May be overlapped by more specific instances
@@ -1971,12 +1039,12 @@ data Overlap = Overlappable -- ^ May be overlapped by more specific instances
| Incoherent -- ^ Both 'Overlapping' and 'Overlappable', and
-- pick an arbitrary one if multiple choices are
-- available.
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | A single @deriving@ clause at the end of a datatype declaration.
data DerivClause = DerivClause (Maybe DerivStrategy) Cxt
-- ^ @{ deriving stock (Eq, Ord) }@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | What the user explicitly requests when deriving an instance with
-- @-XDerivingStrategies@.
@@ -1984,7 +1052,7 @@ data DerivStrategy = StockStrategy -- ^ @deriving {stock} C@
| AnyclassStrategy -- ^ @deriving {anyclass} C@, @-XDeriveAnyClass@
| NewtypeStrategy -- ^ @deriving {newtype} C@, @-XGeneralizedNewtypeDeriving@
| ViaStrategy Type -- ^ @deriving C {via T}@, @-XDerivingVia@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | A pattern synonym's type. Note that a pattern synonym's /fully/
-- specified type has a peculiar shape coming with two forall
@@ -2040,7 +1108,7 @@ type PatSynType = Type
-- between @type family@ and @where@.
data TypeFamilyHead =
TypeFamilyHead Name [TyVarBndr BndrVis] FamilyResultSig (Maybe InjectivityAnn)
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | One equation of a type family instance or closed type family. The
-- arguments are the left-hand-side type and the right-hand-side result.
@@ -2060,28 +1128,28 @@ data TypeFamilyHead =
-- ('VarT' a)
-- @
data TySynEqn = TySynEqn (Maybe [TyVarBndr ()]) Type Type
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | [Functional dependency](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/functio…
-- syntax, as in a class declaration.
data FunDep = FunDep [Name] [Name] -- ^ @class C a b {| a -> b}@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | A @foreign@ declaration.
data Foreign = ImportF Callconv Safety String Name Type
-- ^ @foreign import callconv safety "foreign_name" haskellName :: type@
| ExportF Callconv String Name Type
-- ^ @foreign export callconv "foreign_name" haskellName :: type@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- keep Callconv in sync with module ForeignCall in ghc/compiler/GHC/Types/ForeignCall.hs
-- | A calling convention identifier, as in a 'Foreign' declaration.
data Callconv = CCall | StdCall | CApi | Prim | JavaScript
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | A safety level, as in a 'Foreign' declaration.
data Safety = Unsafe | Safe | Interruptible
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
data Pragma = InlineP Name Inline RuleMatch Phases
-- ^ @{ {\-\# [inline] [rule match] [phases] [phases] name #-} }@. See
@@ -2106,7 +1174,7 @@ data Pragma = InlineP Name Inline RuleMatch Phases
-- ^ @{ {\-\# COMPLETE C_1, ..., C_i [ :: T ] \#-} }@
| SCCP Name (Maybe String)
-- ^ @{ {\-\# SCC fun "optional_name" \#-} }@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | An inline pragma.
data Inline = NoInline
@@ -2115,7 +1183,7 @@ data Inline = NoInline
-- ^ @{ {\-\# INLINE ... #-} }@
| Inlinable
-- ^ @{ {\-\# INLINABLE ... #-} }@
- deriving (Show, Eq, Ord, Data, Generic)
+ deriving (Show, Eq, Ord, Generic)
-- | A @CONLIKE@ modifier, as in one of the various inline pragmas, or lack
-- thereof ('FunLike').
@@ -2123,7 +1191,7 @@ data RuleMatch = ConLike
-- ^ @{ {\-\# CONLIKE [inline] ... #-} }@
| FunLike
-- ^ @{ {\-\# [inline] ... #-} }@
- deriving (Show, Eq, Ord, Data, Generic)
+ deriving (Show, Eq, Ord, Generic)
-- | Phase control syntax.
data Phases = AllPhases
@@ -2132,14 +1200,14 @@ data Phases = AllPhases
-- ^ @[n]@
| BeforePhase Int
-- ^ @[~n]@
- deriving (Show, Eq, Ord, Data, Generic)
+ deriving (Show, Eq, Ord, Generic)
-- | A binder found in the @forall@ of a @RULES@ pragma.
data RuleBndr = RuleVar Name
-- ^ @forall {a} ... .@
| TypedRuleVar Name Type
-- ^ @forall {(a :: t)} ... .@
- deriving (Show, Eq, Ord, Data, Generic)
+ deriving (Show, Eq, Ord, Generic)
-- | The target of an @ANN@ pragma
data AnnTarget = ModuleAnnotation
@@ -2148,7 +1216,7 @@ data AnnTarget = ModuleAnnotation
-- ^ @{\-\# ANN type {name} ... #-}@
| ValueAnnotation Name
-- ^ @{\-\# ANN {name} ... #-}@
- deriving (Show, Eq, Ord, Data, Generic)
+ deriving (Show, Eq, Ord, Generic)
-- | A context, as found on the left side of a @=>@ in a type.
type Cxt = [Pred] -- ^ @(Eq a, Ord b)@
@@ -2166,7 +1234,7 @@ data SourceUnpackedness
= NoSourceUnpackedness -- ^ @C a@
| SourceNoUnpack -- ^ @C { {\-\# NOUNPACK \#-\} } a@
| SourceUnpack -- ^ @C { {\-\# UNPACK \#-\} } a@
- deriving (Show, Eq, Ord, Data, Generic)
+ deriving (Show, Eq, Ord, Generic)
-- | 'SourceStrictness' corresponds to strictness annotations found in the source code.
--
@@ -2175,7 +1243,7 @@ data SourceUnpackedness
data SourceStrictness = NoSourceStrictness -- ^ @C a@
| SourceLazy -- ^ @C {~}a@
| SourceStrict -- ^ @C {!}a@
- deriving (Show, Eq, Ord, Data, Generic)
+ deriving (Show, Eq, Ord, Generic)
-- | Unlike 'SourceStrictness' and 'SourceUnpackedness', 'DecidedStrictness'
-- refers to the strictness annotations that the compiler chooses for a data constructor
@@ -2188,7 +1256,7 @@ data SourceStrictness = NoSourceStrictness -- ^ @C a@
data DecidedStrictness = DecidedLazy -- ^ Field inferred to not have a bang.
| DecidedStrict -- ^ Field inferred to have a bang.
| DecidedUnpack -- ^ Field inferred to be unpacked.
- deriving (Show, Eq, Ord, Data, Generic)
+ deriving (Show, Eq, Ord, Generic)
-- | A data constructor.
--
@@ -2253,7 +1321,7 @@ data Con =
-- Invariant: the list must be non-empty.
[VarBangType] -- ^ The constructor arguments
Type -- ^ See Note [GADT return type]
- deriving (Show, Eq, Ord, Data, Generic)
+ deriving (Show, Eq, Ord, Generic)
-- Note [GADT return type]
-- ~~~~~~~~~~~~~~~~~~~~~~~
@@ -2285,7 +1353,7 @@ data Con =
-- | Strictness information in a data constructor's argument.
data Bang = Bang SourceUnpackedness SourceStrictness
-- ^ @C { {\-\# UNPACK \#-\} !}a@
- deriving (Show, Eq, Ord, Data, Generic)
+ deriving (Show, Eq, Ord, Generic)
-- | A type with a strictness annotation, as in data constructors. See 'Con'.
type BangType = (Bang, Type)
@@ -2309,14 +1377,14 @@ data PatSynDir
= Unidir -- ^ @pattern P x {<-} p@
| ImplBidir -- ^ @pattern P x {=} p@
| ExplBidir [Clause] -- ^ @pattern P x {<-} p where P x = e@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | A pattern synonym's argument type.
data PatSynArgs
= PrefixPatSyn [Name] -- ^ @pattern P {x y z} = p@
| InfixPatSyn Name Name -- ^ @pattern {x P y} = p@
| RecordPatSyn [Name] -- ^ @pattern P { {x,y,z} } = p@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | A Haskell type.
data Type = ForallT [TyVarBndr Specificity] Cxt Type -- ^ @forall \<vars\>. \<ctxt\> => \<type\>@
@@ -2355,12 +1423,12 @@ data Type = ForallT [TyVarBndr Specificity] Cxt Type -- ^ @forall \<vars\>. \<ct
| LitT TyLit -- ^ @0@, @1@, @2@, etc.
| WildCardT -- ^ @_@
| ImplicitParamT String Type -- ^ @?x :: t@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | The specificity of a type variable in a @forall ...@.
data Specificity = SpecifiedSpec -- ^ @a@
| InferredSpec -- ^ @{a}@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | The @flag@ type parameter is instantiated to one of the following types:
--
@@ -2370,40 +1438,40 @@ data Specificity = SpecifiedSpec -- ^ @a@
--
data TyVarBndr flag = PlainTV Name flag -- ^ @a@
| KindedTV Name flag Kind -- ^ @(a :: k)@
- deriving( Show, Eq, Ord, Data, Generic, Functor, Foldable, Traversable )
+ deriving( Show, Eq, Ord, Generic, Functor, Foldable, Traversable )
-- | Visibility of a type variable. See [Inferred vs. specified type variables](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/type_app….
data BndrVis = BndrReq -- ^ @a@
| BndrInvis -- ^ @\@a@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | Type family result signature
data FamilyResultSig = NoSig -- ^ no signature
| KindSig Kind -- ^ @k@
| TyVarSig (TyVarBndr ()) -- ^ @= r, = (r :: k)@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | Injectivity annotation as in an [injective type family](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/type_famili…
data InjectivityAnn = InjectivityAnn Name [Name]
- deriving ( Show, Eq, Ord, Data, Generic )
+ deriving ( Show, Eq, Ord, Generic )
-- | Type-level literals.
data TyLit = NumTyLit Integer -- ^ @2@
| StrTyLit String -- ^ @\"Hello\"@
| CharTyLit Char -- ^ @\'C\'@, @since 4.16.0.0
- deriving ( Show, Eq, Ord, Data, Generic )
+ deriving ( Show, Eq, Ord, Generic )
-- | Role annotations
data Role = NominalR -- ^ @nominal@
| RepresentationalR -- ^ @representational@
| PhantomR -- ^ @phantom@
| InferR -- ^ @_@
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | Annotation target for reifyAnnotations
data AnnLookup = AnnLookupModule Module
| AnnLookupName Name
- deriving( Show, Eq, Ord, Data, Generic )
+ deriving( Show, Eq, Ord, Generic )
-- | To avoid duplication between kinds and types, they
-- are defined to be the same. Naturally, you would never
@@ -2454,7 +1522,7 @@ data DocLoc
| ArgDoc Name Int -- ^ At a specific argument of a function, indexed by its
-- position.
| InstDoc Type -- ^ At a class or family instance.
- deriving ( Show, Eq, Ord, Data, Generic )
+ deriving ( Show, Eq, Ord, Generic )
-----------------------------------------------------
-- Internal helper functions
=====================================
libraries/ghci/GHCi/Message.hs
=====================================
@@ -63,6 +63,7 @@ import Foreign
import GHC.Generics
import GHC.Stack.CCS
import qualified GHC.Boot.TH.Syntax as TH
+import qualified GHC.Boot.TH.Monad as TH
import System.Exit
import System.IO
import System.IO.Error
=====================================
libraries/ghci/GHCi/TH.hs
=====================================
@@ -114,6 +114,7 @@ import qualified Data.Map as M
import Data.Maybe
import GHC.Desugar (AnnotationWrapper(..))
import qualified GHC.Boot.TH.Syntax as TH
+import qualified GHC.Boot.TH.Monad as TH
import Unsafe.Coerce
-- | Create a new instance of 'QState'
=====================================
libraries/template-haskell/Language/Haskell/TH/Quote.hs
=====================================
@@ -22,7 +22,7 @@ module Language.Haskell.TH.Quote
, dataToQa, dataToExpQ, dataToPatQ
) where
-import GHC.Boot.TH.Syntax
+import GHC.Boot.TH.Monad
import GHC.Boot.TH.Quote
import Language.Haskell.TH.Syntax (dataToQa, dataToExpQ, dataToPatQ)
=====================================
libraries/template-haskell/Language/Haskell/TH/Syntax.hs
=====================================
@@ -200,6 +200,7 @@ where
import GHC.Boot.TH.Lift
import GHC.Boot.TH.Syntax
+import GHC.Boot.TH.Monad
import System.FilePath
import Data.Data hiding (Fixity(..))
import Data.List.NonEmpty (NonEmpty(..))
=====================================
testsuite/tests/th/T11452.stderr
=====================================
@@ -7,10 +7,10 @@ T11452.hs:6:12: error: [GHC-94642]
T11452.hs:6:14: error: [GHC-91028]
• Couldn't match type ‘p0’ with ‘forall a. a -> a’
- Expected: GHC.Internal.TH.Syntax.Code
- GHC.Internal.TH.Syntax.Q ((forall a. a -> a) -> ())
- Actual: GHC.Internal.TH.Syntax.Code
- GHC.Internal.TH.Syntax.Q (p0 -> ())
+ Expected: GHC.Internal.TH.Monad.Code
+ GHC.Internal.TH.Monad.Q ((forall a. a -> a) -> ())
+ Actual: GHC.Internal.TH.Monad.Code
+ GHC.Internal.TH.Monad.Q (p0 -> ())
Cannot instantiate unification variable ‘p0’
with a type involving polytypes: forall a. a -> a
• In the Template Haskell typed quotation: [|| \ _ -> () ||]
=====================================
testsuite/tests/th/T15321.stderr
=====================================
@@ -6,7 +6,7 @@ T15321.hs:9:9: error: [GHC-88464]
fail :: forall (m :: * -> *) a.
(MonadFail m, GHC.Internal.Stack.Types.HasCallStack) =>
String -> m a
- with fail @GHC.Internal.TH.Syntax.Q @GHC.Internal.TH.Syntax.Exp
+ with fail @GHC.Internal.TH.Monad.Q @GHC.Internal.TH.Syntax.Exp
(imported from ‘Prelude’ at T15321.hs:3:8-13
(and originally defined in ‘GHC.Internal.Control.Monad.Fail’))
=====================================
testsuite/tests/th/T7276.stderr
=====================================
@@ -4,7 +4,7 @@ T7276.hs:6:5: error: [GHC-87897]
• Couldn't match type ‘[GHC.Internal.TH.Syntax.Dec]’
with ‘GHC.Internal.TH.Syntax.Exp’
Expected: GHC.Internal.TH.Lib.ExpQ
- Actual: GHC.Internal.TH.Syntax.Q GHC.Internal.TH.Lib.Decs
+ Actual: GHC.Internal.TH.Monad.Q GHC.Internal.TH.Lib.Decs
• In the expression: [d| y = 3 |]
In the untyped splice: $([d| y = 3 |])
(deferred type error)
=====================================
testsuite/tests/th/TH_NestedSplicesFail3.stderr
=====================================
@@ -1,6 +1,6 @@
TH_NestedSplicesFail3.hs:4:12: error: [GHC-39999]
- • No instance for ‘GHC.Internal.TH.Syntax.Quote
- (GHC.Internal.TH.Syntax.Code GHC.Internal.TH.Syntax.Q)’
+ • No instance for ‘GHC.Internal.TH.Monad.Quote
+ (GHC.Internal.TH.Monad.Code GHC.Internal.TH.Monad.Q)’
arising from a quotation bracket
• In the expression: [| 'x' |]
In the typed Template Haskell splice: $$([| 'x' |])
=====================================
testsuite/tests/th/TH_NestedSplicesFail4.stderr
=====================================
@@ -1,8 +1,8 @@
TH_NestedSplicesFail4.hs:4:11: error: [GHC-83865]
- • Couldn't match type: GHC.Internal.TH.Syntax.Code m0 Char
- with: GHC.Internal.TH.Syntax.Q GHC.Internal.TH.Syntax.Exp
+ • Couldn't match type: GHC.Internal.TH.Monad.Code m0 Char
+ with: GHC.Internal.TH.Monad.Q GHC.Internal.TH.Syntax.Exp
Expected: GHC.Internal.TH.Lib.ExpQ
- Actual: GHC.Internal.TH.Syntax.Code m0 Char
+ Actual: GHC.Internal.TH.Monad.Code m0 Char
• In the Template Haskell typed quotation: [|| 'y' ||]
In the expression: [|| 'y' ||]
In the untyped splice: $([|| 'y' ||])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/59db903aada81a13c28f5e70e87443…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/59db903aada81a13c28f5e70e87443…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
Ben Gamari pushed new branch wip/backports-9.14 at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/wip/backports-9.14
You're receiving this email because of your account on gitlab.haskell.org.
1
0
Zubin pushed new tag ghc-9.10.3-rc4 at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/ghc-9.10.3-rc4
You're receiving this email because of your account on gitlab.haskell.org.
1
0