summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Peyton Jones <simonpj@microsoft.com>2014-04-04 08:41:35 +0100
committerAustin Seipp <austin@well-typed.com>2014-04-22 01:22:37 -0500
commit6e207dead24fc783f78ae7c786150cb9e7cd7022 (patch)
treede1ba973e8c999b0ef2b3c5158ae97b6290a63dd
parent7dc927d8c3b0bd68cdf2186702309e36dc223ec1 (diff)
downloadhaskell-6e207dead24fc783f78ae7c786150cb9e7cd7022.tar.gz
Simplify and tidy up the handling of tuple names
This fixes Trac #8954. There were actually three places where tuple occ-names were parsed: - IfaceEnv.lookupOrigNameCache - Convert.isBuiltInOcc - OccName.isTupleOcc_maybe I combined all three into TysWiredIn.isBuiltInOcc_maybe Much nicer. (cherry picked from commit 750271e61bdbaad50c19176406512e79abe404a8) Conflicts: testsuite/tests/th/all.T
-rw-r--r--compiler/basicTypes/OccName.lhs53
-rw-r--r--compiler/hsSyn/Convert.lhs25
-rw-r--r--compiler/iface/IfaceEnv.lhs40
-rw-r--r--compiler/prelude/PrelNames.lhs97
-rw-r--r--compiler/prelude/TysWiredIn.lhs70
-rw-r--r--testsuite/tests/th/T8954.hs15
-rw-r--r--testsuite/tests/th/all.T1
7 files changed, 166 insertions, 135 deletions
diff --git a/compiler/basicTypes/OccName.lhs b/compiler/basicTypes/OccName.lhs
index 81f7e5dee2..e870c46d7f 100644
--- a/compiler/basicTypes/OccName.lhs
+++ b/compiler/basicTypes/OccName.lhs
@@ -51,7 +51,6 @@ module OccName (
mkTcOcc, mkTcOccFS,
mkClsOcc, mkClsOccFS,
mkDFunOcc,
- mkTupleOcc,
setOccNameSpace,
demoteOccName,
HasOccName(..),
@@ -82,8 +81,6 @@ module OccName (
isTcClsNameSpace, isTvNameSpace, isDataConNameSpace, isVarNameSpace, isValNameSpace,
- isTupleOcc_maybe,
-
-- * The 'OccEnv' type
OccEnv, emptyOccEnv, unitOccEnv, extendOccEnv, mapOccEnv,
lookupOccEnv, mkOccEnv, mkOccEnv_C, extendOccEnvList, elemOccEnv,
@@ -108,7 +105,6 @@ module OccName (
import Util
import Unique
-import BasicTypes
import DynFlags
import UniqFM
import UniqSet
@@ -812,55 +808,6 @@ tidyOccName env occ@(OccName occ_sp fs)
%************************************************************************
%* *
- Stuff for dealing with tuples
-%* *
-%************************************************************************
-
-\begin{code}
-mkTupleOcc :: NameSpace -> TupleSort -> Arity -> OccName
-mkTupleOcc ns sort ar = OccName ns (mkFastString str)
- where
- -- no need to cache these, the caching is done in the caller
- -- (TysWiredIn.mk_tuple)
- str = case sort of
- UnboxedTuple -> '(' : '#' : commas ++ "#)"
- BoxedTuple -> '(' : commas ++ ")"
- ConstraintTuple -> '(' : commas ++ ")"
- -- Cute hack: reuse the standard tuple OccNames (and hence code)
- -- for fact tuples, but give them different Uniques so they are not equal.
- --
- -- You might think that this will go wrong because isTupleOcc_maybe won't
- -- be able to tell the difference between boxed tuples and fact tuples. BUT:
- -- 1. Fact tuples never occur directly in user code, so it doesn't matter
- -- that we can't detect them in Orig OccNames originating from the user
- -- programs (or those built by setRdrNameSpace used on an Exact tuple Name)
- -- 2. Interface files have a special representation for tuple *occurrences*
- -- in IfaceTyCons, their workers (in IfaceSyn) and their DataCons (in case
- -- alternatives). Thus we don't rely on the OccName to figure out what kind
- -- of tuple an occurrence was trying to use in these situations.
- -- 3. We *don't* represent tuple data type declarations specially, so those
- -- are still turned into wired-in names via isTupleOcc_maybe. But that's OK
- -- because we don't actually need to declare fact tuples thanks to this hack.
- --
- -- So basically any OccName like (,,) flowing to isTupleOcc_maybe will always
- -- refer to the standard boxed tuple. Cool :-)
-
- commas = take (ar-1) (repeat ',')
-
-isTupleOcc_maybe :: OccName -> Maybe (NameSpace, TupleSort, Arity)
--- Tuples are special, because there are so many of them!
-isTupleOcc_maybe (OccName ns fs)
- = case unpackFS fs of
- '(':'#':',':rest -> Just (ns, UnboxedTuple, 2 + count_commas rest)
- '(':',':rest -> Just (ns, BoxedTuple, 2 + count_commas rest)
- _other -> Nothing
- where
- count_commas (',':rest) = 1 + count_commas rest
- count_commas _ = 0
-\end{code}
-
-%************************************************************************
-%* *
\subsection{Lexical categories}
%* *
%************************************************************************
diff --git a/compiler/hsSyn/Convert.lhs b/compiler/hsSyn/Convert.lhs
index 9996e620f0..1a821e9485 100644
--- a/compiler/hsSyn/Convert.lhs
+++ b/compiler/hsSyn/Convert.lhs
@@ -1112,8 +1112,10 @@ thRdrName loc ctxt_ns th_occ th_name
TH.NameQ mod -> (mkRdrQual $! mk_mod mod) $! occ
TH.NameL uniq -> nameRdrName $! (((Name.mkInternalName $! mk_uniq uniq) $! occ) loc)
TH.NameU uniq -> nameRdrName $! (((Name.mkSystemNameAt $! mk_uniq uniq) $! occ) loc)
- TH.NameS | Just name <- isBuiltInOcc ctxt_ns th_occ -> nameRdrName $! name
- | otherwise -> mkRdrUnqual $! occ
+ TH.NameS | Just name <- isBuiltInOcc_maybe occ -> nameRdrName $! name
+ | otherwise -> mkRdrUnqual $! occ
+ -- We check for built-in syntax here, because the TH
+ -- user might have written a (NameS "(,,)"), for example
where
occ :: OccName.OccName
occ = mk_occ ctxt_ns th_occ
@@ -1133,25 +1135,6 @@ thRdrNameGuesses (TH.Name occ flavour)
| otherwise = [OccName.varName, OccName.tvName]
occ_str = TH.occString occ
-isBuiltInOcc :: OccName.NameSpace -> String -> Maybe Name.Name
--- Built in syntax isn't "in scope" so an Unqual RdrName won't do
--- We must generate an Exact name, just as the parser does
-isBuiltInOcc ctxt_ns occ
- = case occ of
- ":" -> Just (Name.getName consDataCon)
- "[]" -> Just (Name.getName nilDataCon)
- "()" -> Just (tup_name 0)
- '(' : ',' : rest -> go_tuple 2 rest
- _ -> Nothing
- where
- go_tuple n ")" = Just (tup_name n)
- go_tuple n (',' : rest) = go_tuple (n+1) rest
- go_tuple _ _ = Nothing
-
- tup_name n
- | OccName.isTcClsNameSpace ctxt_ns = Name.getName (tupleTyCon BoxedTuple n)
- | otherwise = Name.getName (tupleCon BoxedTuple n)
-
-- The packing and unpacking is rather turgid :-(
mk_occ :: OccName.NameSpace -> String -> OccName.OccName
mk_occ ns occ = OccName.mkOccName ns occ
diff --git a/compiler/iface/IfaceEnv.lhs b/compiler/iface/IfaceEnv.lhs
index 42c3e32605..4a00c91381 100644
--- a/compiler/iface/IfaceEnv.lhs
+++ b/compiler/iface/IfaceEnv.lhs
@@ -28,13 +28,10 @@ module IfaceEnv (
import TcRnMonad
import TysWiredIn
import HscTypes
-import TyCon
import Type
-import DataCon
import Var
import Name
import Avail
-import PrelNames
import Module
import UniqFM
import FastString
@@ -183,23 +180,34 @@ lookupOrig mod occ
See Note [The Name Cache] above.
+Note [Built-in syntax and the OrigNameCache]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+You might think that usin isBuiltInOcc_maybe in lookupOrigNameCache is
+unnecessary because tuple TyCon/DataCons are parsed as Exact RdrNames
+and *don't* appear as original names in interface files (because
+serialization gives them special treatment), so we will never look
+them up in the original name cache.
+
+However, there are two reasons why we might look up an Orig RdrName:
+
+ * If you use setRdrNameSpace on an Exact RdrName it may be
+ turned into an Orig RdrName.
+
+ * Template Haskell turns a BuiltInSyntax Name into a TH.NameG
+ (DsMeta.globalVar), and parses a NameG into an Orig RdrName
+ (Convert.thRdrName). So, eg $(do { reify '(,); ... }) will
+ go this route (Trac #8954).
+
\begin{code}
lookupOrigNameCache :: OrigNameCache -> Module -> OccName -> Maybe Name
-lookupOrigNameCache _ mod occ
- -- Don't need to mention gHC_UNIT here because it is explicitly
- -- included in TysWiredIn.wiredInTyCons
- | mod == gHC_TUPLE || mod == gHC_PRIM, -- Boxed tuples from one,
- Just tup_info <- isTupleOcc_maybe occ -- unboxed from the other
- = -- Special case for tuples; there are too many
+lookupOrigNameCache nc mod occ
+ | Just name <- isBuiltInOcc_maybe occ
+ = -- See Note [Known-key names], 3(c) in PrelNames
+ -- Special case for tuples; there are too many
-- of them to pre-populate the original-name cache
- Just (mk_tup_name tup_info)
- where
- mk_tup_name (ns, sort, arity)
- | ns == tcName = tyConName (tupleTyCon sort arity)
- | ns == dataName = dataConName (tupleCon sort arity)
- | otherwise = Var.varName (dataConWorkId (tupleCon sort arity))
+ Just name
-lookupOrigNameCache nc mod occ -- The normal case
+ | otherwise
= case lookupModuleEnv nc mod of
Nothing -> Nothing
Just occ_env -> lookupOccEnv occ_env occ
diff --git a/compiler/prelude/PrelNames.lhs b/compiler/prelude/PrelNames.lhs
index c0c1615daa..c586a7b9bd 100644
--- a/compiler/prelude/PrelNames.lhs
+++ b/compiler/prelude/PrelNames.lhs
@@ -37,55 +37,70 @@ Nota Bene: all Names defined in here should come from the base package
Note [Known-key names]
~~~~~~~~~~~~~~~~~~~~~~
+It is *very* important that the compiler gives wired-in things and
+things with "known-key" names the correct Uniques wherever they
+occur. We have to be careful about this in exactly two places:
-It is *very* important that the compiler gives wired-in things and things with "known-key" names
-the correct Uniques wherever they occur. We have to be careful about this in exactly two places:
+ 1. When we parse some source code, renaming the AST better yield an
+ AST whose Names have the correct uniques
- 1. When we parse some source code, renaming the AST better yield an AST whose Names have the
- correct uniques
-
- 2. When we read an interface file, the read-in gubbins better have the right uniques
+ 2. When we read an interface file, the read-in gubbins better have
+ the right uniques
This is accomplished through a combination of mechanisms:
- 1. When parsing source code, the RdrName-decorated AST has some RdrNames which are Exact. These are
- wired-in RdrNames where the we could directly tell from the parsed syntax what Name to use. For
- example, when we parse a [] in a type we can just insert an Exact RdrName Name with the listTyConKey.
-
- Currently, I believe this is just an optimisation: it would be equally valid to just output Orig
- RdrNames that correctly record the module etc we expect the final Name to come from. However,
- were we to eliminate isTupleOcc_maybe it would become essential (see point 3).
-
- 2. The knownKeyNames (which consist of the basicKnownKeyNames from the module, and those names reachable
- via the wired-in stuff from TysWiredIn) are used to initialise the "original name cache" in IfaceEnv.
- This initialization ensures that when the type checker or renamer (both of which use IfaceEnv) look up
- an original name (i.e. a pair of a Module and an OccName) for a known-key name they get the correct Unique.
+ 1. When parsing source code, the RdrName-decorated AST has some
+ RdrNames which are Exact. These are wired-in RdrNames where the
+ we could directly tell from the parsed syntax what Name to
+ use. For example, when we parse a [] in a type we can just insert
+ an Exact RdrName Name with the listTyConKey.
+
+ Currently, I believe this is just an optimisation: it would be
+ equally valid to just output Orig RdrNames that correctly record
+ the module etc we expect the final Name to come from. However,
+ were we to eliminate isBuiltInOcc_maybe it would become essential
+ (see point 3).
+
+ 2. The knownKeyNames (which consist of the basicKnownKeyNames from
+ the module, and those names reachable via the wired-in stuff from
+ TysWiredIn) are used to initialise the "OrigNameCache" in
+ IfaceEnv. This initialization ensures that when the type checker
+ or renamer (both of which use IfaceEnv) look up an original name
+ (i.e. a pair of a Module and an OccName) for a known-key name
+ they get the correct Unique.
+
+ This is the most important mechanism for ensuring that known-key
+ stuff gets the right Unique, and is why it is so important to
+ place your known-key names in the appropriate lists.
+
+ 3. For "infinite families" of known-key names (i.e. tuples), we have
+ to be extra careful. Because there are an infinite number of
+ these things, we cannot add them to the list of known-key names
+ used to initialise the OrigNameCache. Instead, we have to
+ rely on never having to look them up in that cache.
- This is the most important mechanism for ensuring that known-key stuff gets the right Unique, and is why
- it is so important to place your known-key names in the appropriate lists.
+ This is accomplished through a variety of mechanisms:
- 3. For "infinite families" of known-key names (i.e. tuples, Any tycons and implicit parameter TyCons), we
- have to be extra careful. Because there are an infinite number of these things, we cannot add them to
- the list of known-key names used to initialise the original name cache. Instead, we have to rely on
- never having to look them up in that cache.
+ a) The parser recognises them specially and generates an
+ Exact Name (hence not looked up in the orig-name cache)
- This is accomplished through a variety of mechanisms:
+ b) The known infinite families of names are specially
+ serialised by BinIface.putName, with that special treatment
+ detected when we read back to ensure that we get back to the
+ correct uniques.
- a) The known infinite families of names are specially serialised by BinIface.putName, with that special treatment
- detected when we read back to ensure that we get back to the correct uniques.
+ Most of the infinite families cannot occur in source code,
+ so mechanisms (a,b) sufficies to ensure that they always have
+ the right Unique. In particular, implicit param TyCon names,
+ constraint tuples and Any TyCons cannot be mentioned by the
+ user.
- b) Most of the infinite families cannot occur in source code, so mechanism a) sufficies to ensure that they
- always have the right Unique. In particular, implicit param TyCon names, constraint tuples and Any TyCons
- cannot be mentioned by the user.
+ c) IfaceEnv.lookupOrigNameCache uses isBuiltInOcc_maybe to map
+ built-in syntax directly onto the corresponding name, rather
+ than trying to find it in the original-name cache.
- c) Tuple TyCon/DataCon names have a special hack (isTupleOcc_maybe) that is used by the original name cache
- lookup routine to detect tuple names and give them the right Unique. You might think that this is unnecessary
- because tuple TyCon/DataCons are parsed as Exact RdrNames and *don't* appear as original names in interface files
- (because serialization gives them special treatment), so we will never look them up in the original name cache.
+ See also Note [Built-in syntax and the OrigNameCache]
- However, there is a subtle reason why this is not the case: if you use setRdrNameSpace on an Exact RdrName
- it may be turned into an Orig RdrName. So if the original name was an Exact tuple Name we might end up with
- an Orig instead, which *will* lead to an original name cache query.
\begin{code}
module PrelNames (
Unique, Uniquable(..), hasKey, -- Re-exported for convenience
@@ -474,10 +489,10 @@ mkMainModule_ m = mkModule mainPackageId m
%************************************************************************
\begin{code}
-mkTupleModule :: TupleSort -> Arity -> Module
-mkTupleModule BoxedTuple _ = gHC_TUPLE
-mkTupleModule ConstraintTuple _ = gHC_TUPLE
-mkTupleModule UnboxedTuple _ = gHC_PRIM
+mkTupleModule :: TupleSort -> Module
+mkTupleModule BoxedTuple = gHC_TUPLE
+mkTupleModule ConstraintTuple = gHC_TUPLE
+mkTupleModule UnboxedTuple = gHC_PRIM
\end{code}
diff --git a/compiler/prelude/TysWiredIn.lhs b/compiler/prelude/TysWiredIn.lhs
index aa1b169c0c..de0713a640 100644
--- a/compiler/prelude/TysWiredIn.lhs
+++ b/compiler/prelude/TysWiredIn.lhs
@@ -8,7 +8,7 @@
-- must be wired into the compiler nonetheless. C.f module TysPrim
module TysWiredIn (
-- * All wired in things
- wiredInTyCons,
+ wiredInTyCons, isBuiltInOcc_maybe,
-- * Bool
boolTy, boolTyCon, boolTyCon_RDR, boolTyConName,
@@ -331,11 +331,11 @@ typeSymbolKind = TyConApp (promoteTyCon typeSymbolKindCon) []
%************************************************************************
%* *
-\subsection[TysWiredIn-tuples]{The tuple types}
+ Stuff for dealing with tuples
%* *
%************************************************************************
-Note [How tuples work]
+Note [How tuples work] See also Note [Known-key names] in PrelNames
~~~~~~~~~~~~~~~~~~~~~~
* There are three families of tuple TyCons and corresponding
DataCons, (boxed, unboxed, and constraint tuples), expressed by the
@@ -354,6 +354,68 @@ Note [How tuples work]
are not serialised into interface files using OccNames at all.
\begin{code}
+isBuiltInOcc_maybe :: OccName -> Maybe Name
+-- Built in syntax isn't "in scope" so these OccNames
+-- map to wired-in Names with BuiltInSyntax
+isBuiltInOcc_maybe occ
+ = case occNameString occ of
+ "[]" -> choose_ns listTyCon nilDataCon
+ ":" -> Just consDataConName
+ "[::]" -> Just parrTyConName
+ "(##)" -> choose_ns unboxedUnitTyCon unboxedUnitDataCon
+ "()" -> choose_ns unitTyCon unitDataCon
+ '(':'#':',':rest -> parse_tuple UnboxedTuple 2 rest
+ '(':',':rest -> parse_tuple BoxedTuple 2 rest
+ _other -> Nothing
+ where
+ ns = occNameSpace occ
+
+ parse_tuple sort n rest
+ | (',' : rest2) <- rest = parse_tuple sort (n+1) rest2
+ | tail_matches sort rest = choose_ns (tupleTyCon sort n)
+ (tupleCon sort n)
+ | otherwise = Nothing
+
+ tail_matches BoxedTuple ")" = True
+ tail_matches UnboxedTuple "#)" = True
+ tail_matches _ _ = False
+
+ choose_ns tc dc
+ | isTcClsNameSpace ns = Just (getName tc)
+ | isDataConNameSpace ns = Just (getName dc)
+ | otherwise = Just (getName (dataConWorkId dc))
+
+mkTupleOcc :: NameSpace -> TupleSort -> Arity -> OccName
+mkTupleOcc ns sort ar = mkOccName ns str
+ where
+ -- No need to cache these, the caching is done in mk_tuple
+ str = case sort of
+ UnboxedTuple -> '(' : '#' : commas ++ "#)"
+ BoxedTuple -> '(' : commas ++ ")"
+ ConstraintTuple -> '(' : commas ++ ")"
+
+ commas = take (ar-1) (repeat ',')
+
+ -- Cute hack: we reuse the standard tuple OccNames (and hence code)
+ -- for fact tuples, but give them different Uniques so they are not equal.
+ --
+ -- You might think that this will go wrong because isBuiltInOcc_maybe won't
+ -- be able to tell the difference between boxed tuples and constraint tuples. BUT:
+ -- 1. Constraint tuples never occur directly in user code, so it doesn't matter
+ -- that we can't detect them in Orig OccNames originating from the user
+ -- programs (or those built by setRdrNameSpace used on an Exact tuple Name)
+ -- 2. Interface files have a special representation for tuple *occurrences*
+ -- in IfaceTyCons, their workers (in IfaceSyn) and their DataCons (in case
+ -- alternatives). Thus we don't rely on the OccName to figure out what kind
+ -- of tuple an occurrence was trying to use in these situations.
+ -- 3. We *don't* represent tuple data type declarations specially, so those
+ -- are still turned into wired-in names via isBuiltInOcc_maybe. But that's OK
+ -- because we don't actually need to declare constraint tuples thanks to this hack.
+ --
+ -- So basically any OccName like (,,) flowing to isBuiltInOcc_maybe will always
+ -- refer to the standard boxed tuple. Cool :-)
+
+
tupleTyCon :: TupleSort -> Arity -> TyCon
tupleTyCon sort i | i > mAX_TUPLE_SIZE = fst (mk_tuple sort i) -- Build one specially
tupleTyCon BoxedTuple i = fst (boxedTupleArr ! i)
@@ -386,7 +448,7 @@ mk_tuple sort arity = (tycon, tuple_con)
UnboxedTuple -> Nothing
ConstraintTuple -> Nothing
- modu = mkTupleModule sort arity
+ modu = mkTupleModule sort
tc_name = mkWiredInName modu (mkTupleOcc tcName sort arity) tc_uniq
(ATyCon tycon) BuiltInSyntax
tc_kind = mkArrowKinds (map tyVarKind tyvars) res_kind
diff --git a/testsuite/tests/th/T8954.hs b/testsuite/tests/th/T8954.hs
new file mode 100644
index 0000000000..4aa3081358
--- /dev/null
+++ b/testsuite/tests/th/T8954.hs
@@ -0,0 +1,15 @@
+{-# LANGUAGE TemplateHaskell, MagicHash, UnboxedTuples #-}
+
+module T8954 where
+
+import Language.Haskell.TH
+
+$( do _ <- reify '(##)
+ _ <- reify '(#,#)
+ _ <- reify ''(##)
+ _ <- reify ''(#,#)
+ _ <- reify '()
+ _ <- reify ''()
+ _ <- reify '[]
+ _ <- reify ''[]
+ return [] )
diff --git a/testsuite/tests/th/all.T b/testsuite/tests/th/all.T
index 4117cf1138..cbe08ad29d 100644
--- a/testsuite/tests/th/all.T
+++ b/testsuite/tests/th/all.T
@@ -321,3 +321,4 @@ test('T8759', normal, compile_fail, ['-v0'])
test('T8759a', normal, compile_fail, ['-v0'])
test('T8884', normal, compile, ['-v0'])
test('T8932', normal, compile_fail, ['-v0'])
+test('T8954', normal, compile, ['-v0'])