{-
(c) The GRASP/AQUA Project, Glasgow University, 1992-1998

-}



-- | The @GHC.Builtin.Utils@ interface to the compiler's prelude knowledge.
--
-- This module serves as the central gathering point for names which the
-- compiler knows something about. This includes functions for,
--
--  * discerning whether a 'Name' is known-key
--
--  * given a 'Unique', looking up its corresponding known-key 'Name'
--
-- See Note [Known-key names] and Note [About wired-in things] for information
-- about the two types of prelude things in GHC.
--
module GHC.Builtin.Utils (
        -- * Known-key names
        isKnownKeyName,
        lookupKnownKeyName,
        lookupKnownNameInfo,

        -- ** Internal use
        -- | 'knownKeyNames' is exported to seed the original name cache only;
        -- if you find yourself wanting to look at it you might consider using
        -- 'lookupKnownKeyName' or 'isKnownKeyName'.
        knownKeyNames,

        -- * Miscellaneous
        wiredInIds, ghcPrimIds,

        ghcPrimExports,
        ghcPrimDeclDocs,

        -- * Random other things
        maybeCharLikeCon, maybeIntLikeCon,

        -- * Class categories
        isNumericClass, isStandardClass

    ) where

import GHC.Prelude

import GHC.Builtin.Uniques
import GHC.Builtin.PrimOps
import GHC.Builtin.PrimOps.Ids
import GHC.Builtin.Types
import GHC.Builtin.Types.Literals ( typeNatTyCons )
import GHC.Builtin.Types.Prim
import GHC.Builtin.Names.TH ( templateHaskellNames )
import GHC.Builtin.Names

import GHC.Core.ConLike ( ConLike(..) )
import GHC.Core.DataCon
import GHC.Core.Class
import GHC.Core.TyCon

import GHC.Types.Avail
import GHC.Types.Id
import GHC.Types.Name
import GHC.Types.Name.Env
import GHC.Types.Id.Make
import GHC.Types.Unique.FM
import GHC.Types.Unique.Map
import GHC.Types.TyThing
import GHC.Types.Unique ( isValidKnownKeyUnique )

import GHC.Utils.Outputable
import GHC.Utils.Misc as Utils
import GHC.Utils.Panic
import GHC.Utils.Constants (debugIsOn)
import GHC.Hs.Doc
import GHC.Unit.Module.ModIface (IfaceExport)

import GHC.Data.List.SetOps

import Control.Applicative ((<|>))
import Data.List        ( intercalate , find )
import Data.Maybe

{-
************************************************************************
*                                                                      *
\subsection[builtinNameInfo]{Lookup built-in names}
*                                                                      *
************************************************************************

Note [About wired-in things]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Wired-in things are Ids\/TyCons that are completely known to the compiler.
  They are global values in GHC, (e.g.  listTyCon :: TyCon).

* A wired-in Name contains the thing itself inside the Name:
        see Name.wiredInNameTyThing_maybe
  (E.g. listTyConName contains listTyCon.

* The name cache is initialised with (the names of) all wired-in things
  (except tuples and sums; see Note [Infinite families of known-key names])

* The type environment itself contains no wired in things. The type
  checker sees if the Name is wired in before looking up the name in
  the type environment.

* GHC.Iface.Make prunes out wired-in things before putting them in an interface file.
  So interface files never contain wired-in things.
-}


-- | This list is used to ensure that when you say "Prelude.map" in your source
-- code, or in an interface file, you get a Name with the correct known key (See
-- Note [Known-key names] in "GHC.Builtin.Names")
knownKeyNames :: [Name]
knownKeyNames :: [Name]
knownKeyNames
  | Bool
debugIsOn
  , Just String
badNamesStr <- [Name] -> Maybe String
knownKeyNamesOkay [Name]
all_names
  = forall a. HasCallStack => String -> a
panic (String
"badAllKnownKeyNames:\n" forall a. [a] -> [a] -> [a]
++ String
badNamesStr)
       -- NB: We can't use ppr here, because this is sometimes evaluated in a
       -- context where there are no DynFlags available, leading to a cryptic
       -- "<<details unavailable>>" error. (This seems to happen only in the
       -- stage 2 compiler, for reasons I [Richard] have no clue of.)
  | Bool
otherwise
  = [Name]
all_names
  where
    all_names :: [Name]
all_names =
      forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap TyCon -> [Name]
wired_tycon_kk_names [TyCon]
primTyCons
             , forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap TyCon -> [Name]
wired_tycon_kk_names [TyCon]
wiredInTyCons
             , forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap TyCon -> [Name]
wired_tycon_kk_names [TyCon]
typeNatTyCons
             , forall a b. (a -> b) -> [a] -> [b]
map Id -> Name
idName [Id]
wiredInIds
             , forall a b. (a -> b) -> [a] -> [b]
map Id -> Name
idName [Id]
allThePrimOpIds
             , forall a b. (a -> b) -> [a] -> [b]
map (Id -> Name
idName forall b c a. (b -> c) -> (a -> b) -> a -> c
. PrimOp -> Id
primOpWrapperId) [PrimOp]
allThePrimOps
             , [Name]
basicKnownKeyNames
             , [Name]
templateHaskellNames
             ]
    -- All of the names associated with a wired-in TyCon.
    -- This includes the TyCon itself, its DataCons and promoted TyCons.
    wired_tycon_kk_names :: TyCon -> [Name]
    wired_tycon_kk_names :: TyCon -> [Name]
wired_tycon_kk_names TyCon
tc =
        TyCon -> Name
tyConName TyCon
tc forall a. a -> [a] -> [a]
: (TyCon -> [Name]
rep_names TyCon
tc forall a. [a] -> [a] -> [a]
++ [Name]
implicits)
      where implicits :: [Name]
implicits = forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap TyThing -> [Name]
thing_kk_names (TyCon -> [TyThing]
implicitTyConThings TyCon
tc)

    wired_datacon_kk_names :: DataCon -> [Name]
    wired_datacon_kk_names :: DataCon -> [Name]
wired_datacon_kk_names DataCon
dc =
      DataCon -> Name
dataConName DataCon
dc forall a. a -> [a] -> [a]
: TyCon -> [Name]
rep_names (DataCon -> TyCon
promoteDataCon DataCon
dc)

    thing_kk_names :: TyThing -> [Name]
    thing_kk_names :: TyThing -> [Name]
thing_kk_names (ATyCon TyCon
tc)                 = TyCon -> [Name]
wired_tycon_kk_names TyCon
tc
    thing_kk_names (AConLike (RealDataCon DataCon
dc)) = DataCon -> [Name]
wired_datacon_kk_names DataCon
dc
    thing_kk_names TyThing
thing                       = [forall a. NamedThing a => a -> Name
getName TyThing
thing]

    -- The TyConRepName for a known-key TyCon has a known key,
    -- but isn't itself an implicit thing.  Yurgh.
    -- NB: if any of the wired-in TyCons had record fields, the record
    --     field names would be in a similar situation.  Ditto class ops.
    --     But it happens that there aren't any
    rep_names :: TyCon -> [Name]
rep_names TyCon
tc = case TyCon -> Maybe Name
tyConRepName_maybe TyCon
tc of
                        Just Name
n  -> [Name
n]
                        Maybe Name
Nothing -> []

-- | Check the known-key names list of consistency.
knownKeyNamesOkay :: [Name] -> Maybe String
knownKeyNamesOkay :: [Name] -> Maybe String
knownKeyNamesOkay [Name]
all_names
  | ns :: [Name]
ns@(Name
_:[Name]
_) <- forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. Unique -> Bool
isValidKnownKeyUnique forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Uniquable a => a -> Unique
getUnique) [Name]
all_names
  = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ String
"    Out-of-range known-key uniques: ["
        forall a. [a] -> [a] -> [a]
++ forall a. [a] -> [[a]] -> [a]
intercalate String
", " (forall a b. (a -> b) -> [a] -> [b]
map (OccName -> String
occNameString forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> OccName
nameOccName) [Name]
ns) forall a. [a] -> [a] -> [a]
++
         String
"]"
  | forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(Unique, [Name])]
badNamesPairs
  = forall a. Maybe a
Nothing
  | Bool
otherwise
  = forall a. a -> Maybe a
Just String
badNamesStr
  where
    namesEnv :: NameEnv [Name]
namesEnv      = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (\NameEnv [Name]
m Name
n -> forall a b.
(a -> b -> b) -> (a -> b) -> NameEnv b -> Name -> a -> NameEnv b
extendNameEnv_Acc (:) forall a. a -> [a]
Utils.singleton NameEnv [Name]
m Name
n Name
n)
                           forall key elt. UniqFM key elt
emptyUFM [Name]
all_names
    badNamesEnv :: NameEnv [Name]
badNamesEnv   = forall elt. (elt -> Bool) -> NameEnv elt -> NameEnv elt
filterNameEnv (\[Name]
ns -> [Name]
ns forall a. [a] -> Int -> Bool
`lengthExceeds` Int
1) NameEnv [Name]
namesEnv
    badNamesPairs :: [(Unique, [Name])]
badNamesPairs = forall key elt. UniqFM key elt -> [(Unique, elt)]
nonDetUFMToList NameEnv [Name]
badNamesEnv
      -- It's OK to use nonDetUFMToList here because the ordering only affects
      -- the message when we get a panic
    badNamesStrs :: [String]
badNamesStrs  = forall a b. (a -> b) -> [a] -> [b]
map forall {a}. Show a => (a, [Name]) -> String
pairToStr [(Unique, [Name])]
badNamesPairs
    badNamesStr :: String
badNamesStr   = [String] -> String
unlines [String]
badNamesStrs

    pairToStr :: (a, [Name]) -> String
pairToStr (a
uniq, [Name]
ns) = String
"        " forall a. [a] -> [a] -> [a]
++
                           forall a. Show a => a -> String
show a
uniq forall a. [a] -> [a] -> [a]
++
                           String
": [" forall a. [a] -> [a] -> [a]
++
                           forall a. [a] -> [[a]] -> [a]
intercalate String
", " (forall a b. (a -> b) -> [a] -> [b]
map (OccName -> String
occNameString forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> OccName
nameOccName) [Name]
ns) forall a. [a] -> [a] -> [a]
++
                           String
"]"

-- | Given a 'Unique' lookup its associated 'Name' if it corresponds to a
-- known-key thing.
lookupKnownKeyName :: Unique -> Maybe Name
lookupKnownKeyName :: Unique -> Maybe Name
lookupKnownKeyName Unique
u =
    Unique -> Maybe Name
knownUniqueName Unique
u forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall key elt. UniqFM key elt -> Unique -> Maybe elt
lookupUFM_Directly UniqFM Name Name
knownKeysMap Unique
u

-- | Is a 'Name' known-key?
isKnownKeyName :: Name -> Bool
isKnownKeyName :: Name -> Bool
isKnownKeyName Name
n =
    forall a. Maybe a -> Bool
isJust (Unique -> Maybe Name
knownUniqueName forall a b. (a -> b) -> a -> b
$ Name -> Unique
nameUnique Name
n) Bool -> Bool -> Bool
|| forall key elt. Uniquable key => key -> UniqFM key elt -> Bool
elemUFM Name
n UniqFM Name Name
knownKeysMap

-- | Maps 'Unique's to known-key names.
--
-- The type is @UniqFM Name Name@ to denote that the 'Unique's used
-- in the domain are 'Unique's associated with 'Name's (as opposed
-- to some other namespace of 'Unique's).
knownKeysMap :: UniqFM Name Name
knownKeysMap :: UniqFM Name Name
knownKeysMap = forall key. Uniquable key => [key] -> UniqFM key key
listToIdentityUFM [Name]
knownKeyNames

-- | Given a 'Unique' lookup any associated arbitrary SDoc's to be displayed by
-- GHCi's ':info' command.
lookupKnownNameInfo :: Name -> SDoc
lookupKnownNameInfo :: Name -> SDoc
lookupKnownNameInfo Name
name = case forall a. NameEnv a -> Name -> Maybe a
lookupNameEnv NameEnv SDoc
knownNamesInfo Name
name of
    -- If we do find a doc, we add comment delimiters to make the output
    -- of ':info' valid Haskell.
    Maybe SDoc
Nothing  -> forall doc. IsOutput doc => doc
empty
    Just SDoc
doc -> forall doc. IsDoc doc => [doc] -> doc
vcat [forall doc. IsLine doc => String -> doc
text String
"{-", SDoc
doc, forall doc. IsLine doc => String -> doc
text String
"-}"]

-- A map from Uniques to SDocs, used in GHCi's ':info' command. (#12390)
knownNamesInfo :: NameEnv SDoc
knownNamesInfo :: NameEnv SDoc
knownNamesInfo = forall a. Name -> a -> NameEnv a
unitNameEnv Name
coercibleTyConName forall a b. (a -> b) -> a -> b
$
    forall doc. IsDoc doc => [doc] -> doc
vcat [ forall doc. IsLine doc => String -> doc
text String
"Coercible is a special constraint with custom solving rules."
         , forall doc. IsLine doc => String -> doc
text String
"It is not a class."
         , forall doc. IsLine doc => String -> doc
text String
"Please see section `The Coercible constraint`"
         , forall doc. IsLine doc => String -> doc
text String
"of the user's guide for details." ]

{-
We let a lot of "non-standard" values be visible, so that we can make
sense of them in interface pragmas. It's cool, though they all have
"non-standard" names, so they won't get past the parser in user code.
-}

{-
************************************************************************
*                                                                      *
            Export lists for pseudo-modules (GHC.Prim)
*                                                                      *
************************************************************************
-}

ghcPrimExports :: [IfaceExport]
ghcPrimExports :: [IfaceExport]
ghcPrimExports
 = forall a b. (a -> b) -> [a] -> [b]
map (Name -> IfaceExport
avail forall b c a. (b -> c) -> (a -> b) -> a -> c
. Id -> Name
idName) [Id]
ghcPrimIds forall a. [a] -> [a] -> [a]
++
   forall a b. (a -> b) -> [a] -> [b]
map (Name -> IfaceExport
avail forall b c a. (b -> c) -> (a -> b) -> a -> c
. Id -> Name
idName) [Id]
allThePrimOpIds forall a. [a] -> [a] -> [a]
++
   [ Name -> [Name] -> [FieldLabel] -> IfaceExport
availTC Name
n [Name
n] []
   | TyCon
tc <- [TyCon]
exposedPrimTyCons, let n :: Name
n = TyCon -> Name
tyConName TyCon
tc  ]

ghcPrimDeclDocs :: Docs
ghcPrimDeclDocs :: Docs
ghcPrimDeclDocs = Docs
emptyDocs { docs_decls :: UniqMap Name [HsDoc GhcRn]
docs_decls = forall k a. Uniquable k => [(k, a)] -> UniqMap k a
listToUniqMap forall a b. (a -> b) -> a -> b
$ forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe forall {pass}.
(String, String)
-> Maybe (Name, [WithHsDocIdentifiers HsDocString pass])
findName [(String, String)]
primOpDocs }
  where
    names :: [Name]
names = forall a b. (a -> b) -> [a] -> [b]
map Id -> Name
idName [Id]
ghcPrimIds forall a. [a] -> [a] -> [a]
++
            forall a b. (a -> b) -> [a] -> [b]
map Id -> Name
idName [Id]
allThePrimOpIds forall a. [a] -> [a] -> [a]
++
            forall a b. (a -> b) -> [a] -> [b]
map TyCon -> Name
tyConName [TyCon]
exposedPrimTyCons
    findName :: (String, String)
-> Maybe (Name, [WithHsDocIdentifiers HsDocString pass])
findName (String
nameStr, String
doc)
      | Just Name
name <- forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find ((String
nameStr forall a. Eq a => a -> a -> Bool
==) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. NamedThing a => a -> String
getOccString) [Name]
names
      = forall a. a -> Maybe a
Just (Name
name, [forall a pass.
a -> [Located (IdP pass)] -> WithHsDocIdentifiers a pass
WithHsDocIdentifiers (String -> HsDocString
mkGeneratedHsDocString String
doc) []])
      | Bool
otherwise = forall a. Maybe a
Nothing

{-
************************************************************************
*                                                                      *
            Built-in keys
*                                                                      *
************************************************************************

ToDo: make it do the ``like'' part properly (as in 0.26 and before).
-}

maybeCharLikeCon, maybeIntLikeCon :: DataCon -> Bool
maybeCharLikeCon :: DataCon -> Bool
maybeCharLikeCon DataCon
con = DataCon
con forall a. Uniquable a => a -> Unique -> Bool
`hasKey` Unique
charDataConKey
maybeIntLikeCon :: DataCon -> Bool
maybeIntLikeCon  DataCon
con = DataCon
con forall a. Uniquable a => a -> Unique -> Bool
`hasKey` Unique
intDataConKey

{-
************************************************************************
*                                                                      *
            Class predicates
*                                                                      *
************************************************************************
-}

isNumericClass, isStandardClass :: Class -> Bool

isNumericClass :: Class -> Bool
isNumericClass     Class
clas = Class -> Unique
classKey Class
clas forall a. Eq a => a -> [a] -> Bool
`is_elem` [Unique]
numericClassKeys
isStandardClass :: Class -> Bool
isStandardClass    Class
clas = Class -> Unique
classKey Class
clas forall a. Eq a => a -> [a] -> Bool
`is_elem` [Unique]
standardClassKeys

is_elem :: Eq a => a -> [a] -> Bool
is_elem :: forall a. Eq a => a -> [a] -> Bool
is_elem = forall a. Eq a => String -> a -> [a] -> Bool
isIn String
"is_X_Class"