Commit 750271e6 authored by Simon Peyton Jones's avatar Simon Peyton Jones

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.
parent e94ed11a
......@@ -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
......@@ -811,55 +807,6 @@ tidyOccName env occ@(OccName occ_sp fs)
new_fs = mkFastString (base ++ show n)
\end{code}
%************************************************************************
%* *
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}
......
......@@ -1108,8 +1108,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
......@@ -1129,25 +1131,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
......
......@@ -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
......
......@@ -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
......@@ -473,10 +488,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}
......
......@@ -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,
......@@ -333,11 +333,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
......@@ -356,6 +356,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)
......@@ -388,7 +450,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
......
{-# LANGUAGE TemplateHaskell, MagicHash, UnboxedTuples #-}
module T8954 where
import Language.Haskell.TH
$( do _ <- reify '(##)
_ <- reify '(#,#)
_ <- reify ''(##)
_ <- reify ''(#,#)
_ <- reify '()
_ <- reify ''()
_ <- reify '[]
_ <- reify ''[]
return [] )
......@@ -322,4 +322,5 @@ test('T8759a', normal, compile_fail, ['-v0'])
test('T7021',
extra_clean(['T7021a.hi', 'T7021a.o']), multimod_compile, ['T7021','-v0'])
test('T8807', normal, compile, ['-v0'])
test('T8884', normal, compile, ['-v0'])
\ No newline at end of file
test('T8884', normal, compile, ['-v0'])
test('T8954', normal, compile, ['-v0'])
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment