summaryrefslogtreecommitdiff
path: root/compiler/basicTypes/RdrName.lhs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/basicTypes/RdrName.lhs')
-rw-r--r--compiler/basicTypes/RdrName.lhs152
1 files changed, 121 insertions, 31 deletions
diff --git a/compiler/basicTypes/RdrName.lhs b/compiler/basicTypes/RdrName.lhs
index d4afaf10fc..268f50e015 100644
--- a/compiler/basicTypes/RdrName.lhs
+++ b/compiler/basicTypes/RdrName.lhs
@@ -45,16 +45,17 @@ module RdrName (
-- * Global mapping of 'RdrName' to 'GlobalRdrElt's
GlobalRdrEnv, emptyGlobalRdrEnv, mkGlobalRdrEnv, plusGlobalRdrEnv,
- lookupGlobalRdrEnv, extendGlobalRdrEnv,
+ lookupGlobalRdrEnv, extendGlobalRdrEnv, greOccName,
pprGlobalRdrEnv, globalRdrEnvElts,
- lookupGRE_RdrName, lookupGRE_Name, getGRE_NameQualifier_maybes,
+ lookupGRE_RdrName, lookupGRE_Name, lookupGRE_Field_Name, getGRE_NameQualifier_maybes,
transformGREs, findLocalDupsRdrEnv, pickGREs,
-- * GlobalRdrElts
gresFromAvails, gresFromAvail,
-- ** Global 'RdrName' mapping elements: 'GlobalRdrElt', 'Provenance', 'ImportSpec'
- GlobalRdrElt(..), isLocalGRE, unQualOK, qualSpecOK, unQualSpecOK,
+ GlobalRdrElt(..), isLocalGRE, isRecFldGRE, isOverloadedRecFldGRE, greLabel,
+ unQualOK, qualSpecOK, unQualSpecOK,
Provenance(..), pprNameProvenance,
Parent(..),
ImportSpec(..), ImpDeclSpec(..), ImpItemSpec(..),
@@ -70,6 +71,7 @@ import NameSet
import Maybes
import SrcLoc
import FastString
+import FieldLabel
import Outputable
import Unique
import Util
@@ -431,25 +433,40 @@ data GlobalRdrElt
-- | The children of a Name are the things that are abbreviated by the ".."
-- notation in export lists. See Note [Parents]
-data Parent = NoParent | ParentIs Name
- deriving (Eq)
+data Parent = NoParent
+ | ParentIs { par_is :: Name }
+ | FldParent { par_is :: Name, par_lbl :: Maybe FieldLabelString }
+ -- ^ See Note [Parents for record fields]
+ deriving (Eq)
instance Outputable Parent where
- ppr NoParent = empty
- ppr (ParentIs n) = ptext (sLit "parent:") <> ppr n
+ ppr NoParent = empty
+ ppr (ParentIs n) = ptext (sLit "parent:") <> ppr n
+ ppr (FldParent n f) = ptext (sLit "fldparent:")
+ <> ppr n <> colon <> ppr f
plusParent :: Parent -> Parent -> Parent
-- See Note [Combining parents]
-plusParent (ParentIs n) p2 = hasParent n p2
-plusParent p1 (ParentIs n) = hasParent n p1
-plusParent _ _ = NoParent
+plusParent (ParentIs n) p2 = hasParentIs n p2
+plusParent (FldParent n f) p2 = hasFldParent n f p2
+plusParent p1 (ParentIs n) = hasParentIs n p1
+plusParent p1 (FldParent n f) = hasFldParent n f p1
+plusParent NoParent NoParent = NoParent
-hasParent :: Name -> Parent -> Parent
+hasParentIs :: Name -> Parent -> Parent
#ifdef DEBUG
-hasParent n (ParentIs n')
- | n /= n' = pprPanic "hasParent" (ppr n <+> ppr n') -- Parents should agree
+hasParentIs n (ParentIs n')
+ | n /= n' = pprPanic "hasParentIs" (ppr n <+> ppr n') -- Parents should agree
#endif
-hasParent n _ = ParentIs n
+hasParentIs n _ = ParentIs n
+
+hasFldParent :: Name -> Maybe FieldLabelString -> Parent -> Parent
+#ifdef DEBUG
+hasFldParent n f (FldParent n' f')
+ | n /= n' || f /= f' -- Parents should agree
+ = pprPanic "hasFldParent" (ppr n <+> ppr f <+> ppr n' <+> ppr f')
+#endif
+hasFldParent n f _ = FldParent n f
\end{code}
Note [Parents]
@@ -465,6 +482,34 @@ Note [Parents]
class C Class operations
Associated type constructors
+
+Note [Parents for record fields]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For record fields, in addition to the Name of the type constructor
+(stored in par_is), we use FldParent to store the field label. This
+extra information is used for identifying overloaded record fields
+during renaming.
+
+In a definition arising from a normal module (without
+-XOverloadedRecordFields), par_lbl will be Nothing, meaning that the
+field's label is the same as the OccName of the selector's Name. The
+GlobalRdrEnv will contain an entry like this:
+
+ "x" |-> GRE x (FldParent T Nothing) LocalDef
+
+When -XOverloadedRecordFields is enabled for the module that contains
+T, the selector's Name will be mangled (see comments in FieldLabel).
+Thus we store the actual field label in par_lbl, and the GlobalRdrEnv
+entry looks like this:
+
+ "x" |-> GRE $sel:x:T (FldParent T (Just "x")) LocalDef
+
+Note that the OccName used when adding a GRE to the environment
+(greOccName) now depends on the parent field: for FldParent it is the
+field label, if present, rather than the selector name.
+
+
Note [Combining parents]
~~~~~~~~~~~~~~~~~~~~~~~~
With an associated type we might have
@@ -492,27 +537,36 @@ those. For T that will mean we have
one GRE with NoParent
That's why plusParent picks the "best" case.
-
\begin{code}
-- | make a 'GlobalRdrEnv' where all the elements point to the same
-- Provenance (useful for "hiding" imports, or imports with
-- no details).
gresFromAvails :: Provenance -> [AvailInfo] -> [GlobalRdrElt]
gresFromAvails prov avails
- = concatMap (gresFromAvail (const prov)) avails
-
-gresFromAvail :: (Name -> Provenance) -> AvailInfo -> [GlobalRdrElt]
-gresFromAvail prov_fn avail
- = [ GRE {gre_name = n,
- gre_par = mkParent n avail,
- gre_prov = prov_fn n}
- | n <- availNames avail ]
+ = concatMap (gresFromAvail (const prov) prov) avails
+
+gresFromAvail :: (Name -> Provenance) -> Provenance
+ -> AvailInfo -> [GlobalRdrElt]
+gresFromAvail prov_fn prov_fld avail = xs ++ ys
where
+ parent _ (Avail _) = NoParent
+ parent n (AvailTC m _ _) | n == m = NoParent
+ | otherwise = ParentIs m
+
+ xs = map greFromFld (availFlds avail)
+ ys = map greFromNonFld (availNonFldNames avail)
+
+ greFromNonFld n = GRE { gre_name = n, gre_par = parent n avail, gre_prov = prov_fn n}
+
+ greFromFld (n, mb_lbl)
+ = GRE { gre_name = n
+ , gre_par = FldParent (availName avail) mb_lbl
+ , gre_prov = prov_fld }
mkParent :: Name -> AvailInfo -> Parent
-mkParent _ (Avail _) = NoParent
-mkParent n (AvailTC m _) | n == m = NoParent
- | otherwise = ParentIs m
+mkParent _ (Avail _) = NoParent
+mkParent n (AvailTC m _ _) | n == m = NoParent
+ | otherwise = ParentIs m
emptyGlobalRdrEnv :: GlobalRdrEnv
emptyGlobalRdrEnv = emptyOccEnv
@@ -546,6 +600,10 @@ lookupGlobalRdrEnv env occ_name = case lookupOccEnv env occ_name of
Nothing -> []
Just gres -> gres
+greOccName :: GlobalRdrElt -> OccName
+greOccName (GRE{gre_par = FldParent{par_lbl = Just lbl}}) = mkVarOccFS lbl
+greOccName gre = nameOccName (gre_name gre)
+
lookupGRE_RdrName :: RdrName -> GlobalRdrEnv -> [GlobalRdrElt]
lookupGRE_RdrName rdr_name env
= case lookupOccEnv env (rdrNameOcc rdr_name) of
@@ -557,6 +615,14 @@ lookupGRE_Name env name
= [ gre | gre <- lookupGlobalRdrEnv env (nameOccName name),
gre_name gre == name ]
+lookupGRE_Field_Name :: GlobalRdrEnv -> Name -> FastString -> [GlobalRdrElt]
+-- Used when looking up record fields, where the selector name and
+-- field label are different: the GlobalRdrEnv is keyed on the label
+lookupGRE_Field_Name env sel_name lbl
+ = [ gre | gre <- lookupGlobalRdrEnv env (mkVarOccFS lbl),
+ gre_name gre == sel_name ]
+
+
getGRE_NameQualifier_maybes :: GlobalRdrEnv -> Name -> [Maybe [ModuleName]]
-- Returns all the qualifiers by which 'x' is in scope
-- Nothing means "the unqualified version is in scope"
@@ -571,6 +637,21 @@ isLocalGRE :: GlobalRdrElt -> Bool
isLocalGRE (GRE {gre_prov = LocalDef}) = True
isLocalGRE _ = False
+isRecFldGRE :: GlobalRdrElt -> Bool
+isRecFldGRE (GRE {gre_par = FldParent{}}) = True
+isRecFldGRE _ = False
+
+isOverloadedRecFldGRE :: GlobalRdrElt -> Bool
+isOverloadedRecFldGRE (GRE {gre_par = FldParent{par_lbl = Just _}})
+ = True
+isOverloadedRecFldGRE _ = False
+
+-- Returns the field label of this GRE, if it has one
+greLabel :: GlobalRdrElt -> Maybe FieldLabelString
+greLabel (GRE{gre_par = FldParent{par_lbl = Just lbl}}) = Just lbl
+greLabel (GRE{gre_name = n, gre_par = FldParent{}}) = Just (occNameFS (nameOccName n))
+greLabel _ = Nothing
+
unQualOK :: GlobalRdrElt -> Bool
-- ^ Test if an unqualifed version of this thing would be in scope
unQualOK (GRE {gre_prov = LocalDef}) = True
@@ -650,7 +731,7 @@ mkGlobalRdrEnv gres
= foldr add emptyGlobalRdrEnv gres
where
add gre env = extendOccEnv_Acc insertGRE singleton env
- (nameOccName (gre_name gre))
+ (greOccName gre)
gre
insertGRE :: GlobalRdrElt -> [GlobalRdrElt] -> [GlobalRdrElt]
@@ -707,14 +788,23 @@ extendGlobalRdrEnv do_shadowing env avails
-- don't shadow each other; that would conceal genuine errors
-- E.g. in GHCi data T = A | A
- add_avail env avail = foldl (add_name avail) env (availNames avail)
+ add_avail env avail = foldl (add_fld_name avail)
+ (foldl (add_name avail) env (availNonFldNames avail))
+ (availFlds avail)
+
+ add_name avail env name = add_name' env name (nameOccName name) (mkParent name avail)
+
+ add_fld_name (AvailTC par_name _ _) env (name, mb_fld) =
+ add_name' env name lbl (FldParent par_name mb_fld)
+ where
+ lbl = maybe (nameOccName name) mkVarOccFS mb_fld
+ add_fld_name (Avail _) _ _ = error "Field made available without its parent"
- add_name avail env name
+ add_name' env name occ par
= extendOccEnv_Acc (:) singleton env occ gre
where
- occ = nameOccName name
gre = GRE { gre_name = name
- , gre_par = mkParent name avail
+ , gre_par = par
, gre_prov = LocalDef }
shadow_name :: GlobalRdrEnv -> Name -> GlobalRdrEnv