Fix Trac #2293: improve error reporting for duplicate declarations
[ghc-hetmet.git] / compiler / basicTypes / RdrName.lhs
index 030aa1f..5e18497 100644 (file)
@@ -1,9 +1,8 @@
 %
+% (c) The University of Glasgow 2006
 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
 
-\section[RdrName]{@RdrName@}
-
 \begin{code}
 module RdrName (
        RdrName(..),    -- Constructors exported only to BinIface
@@ -15,40 +14,40 @@ module RdrName (
        mkDerivedRdrName, 
 
        -- Destruction
-       rdrNameModule, rdrNameOcc, setRdrNameSpace,
-       isRdrDataCon, isRdrTyVar, isRdrTc, isQual, isUnqual, 
+       rdrNameOcc, setRdrNameSpace,
+       isRdrDataCon, isRdrTyVar, isRdrTc, isQual, isQual_maybe, isUnqual, 
        isOrig, isOrig_maybe, isExact, isExact_maybe, isSrcRdrName,
 
        -- Printing;    instance Outputable RdrName
 
        -- LocalRdrEnv
        LocalRdrEnv, emptyLocalRdrEnv, extendLocalRdrEnv,
-       lookupLocalRdrEnv, elemLocalRdrEnv,
+       lookupLocalRdrEnv, lookupLocalRdrOcc, elemLocalRdrEnv,
 
        -- GlobalRdrEnv
        GlobalRdrEnv, emptyGlobalRdrEnv, mkGlobalRdrEnv, plusGlobalRdrEnv, 
        lookupGlobalRdrEnv, extendGlobalRdrEnv,
        pprGlobalRdrEnv, globalRdrEnvElts,
-       lookupGRE_RdrName, lookupGRE_Name,
+       lookupGRE_RdrName, lookupGRE_Name, getGRE_NameQualifier_maybes,
+        hideSomeUnquals, findLocalDupsRdrEnv,
 
        -- GlobalRdrElt, Provenance, ImportSpec
-       GlobalRdrElt(..), isLocalGRE, unQualOK, 
+       GlobalRdrElt(..), isLocalGRE, unQualOK, qualSpecOK, unQualSpecOK,
        Provenance(..), pprNameProvenance,
+       Parent(..), 
        ImportSpec(..), ImpDeclSpec(..), ImpItemSpec(..), 
-       importSpecLoc, importSpecModule
+       importSpecLoc, importSpecModule, isExplicitItem
   ) where 
 
 #include "HsVersions.h"
 
-import OccName
-import Module   ( Module, mkModuleFS )
-import Name    ( Name, NamedThing(getName), nameModule, nameParent_maybe,
-                 nameOccName, isExternalName, nameSrcLoc )
-import Maybes  ( mapCatMaybes )
-import SrcLoc  ( isGoodSrcLoc, SrcSpan )
-import FastString ( FastString )
+import Module
+import Name
+import Maybes
+import SrcLoc
+import FastString
 import Outputable
-import Util    ( thenCmp )
+import Util
 \end{code}
 
 %************************************************************************
@@ -62,7 +61,7 @@ data RdrName
   = Unqual OccName
        -- Used for ordinary, unqualified occurrences 
 
-  | Qual Module OccName
+  | Qual ModuleName OccName
        -- A qualified name written by the user in 
        --  *source* code.  The module isn't necessarily 
        -- the module where the thing is defined; 
@@ -78,10 +77,7 @@ data RdrName
        -- We know exactly the Name. This is used 
        --  (a) when the parser parses built-in syntax like "[]" 
        --      and "(,)", but wants a RdrName from it
-       --  (b) when converting names to the RdrNames in IfaceTypes
-       --      Here an Exact RdrName always contains an External Name
-       --      (Internal Names are converted to simple Unquals)
-       --  (c) by Template Haskell, when TH has generated a unique name
+       --  (b) by Template Haskell, when TH has generated a unique name
 \end{code}
 
 
@@ -92,12 +88,6 @@ data RdrName
 %************************************************************************
 
 \begin{code}
-rdrNameModule :: RdrName -> Module
-rdrNameModule (Qual m _) = m
-rdrNameModule (Orig m _) = m
-rdrNameModule (Exact n)  = nameModule n
-rdrNameModule (Unqual n) = pprPanic "rdrNameModule" (ppr n)
-
 rdrNameOcc :: RdrName -> OccName
 rdrNameOcc (Qual _ occ) = occ
 rdrNameOcc (Unqual occ) = occ
@@ -125,7 +115,7 @@ setRdrNameSpace (Exact n)    ns = Orig (nameModule n)
 mkRdrUnqual :: OccName -> RdrName
 mkRdrUnqual occ = Unqual occ
 
-mkRdrQual :: Module -> OccName -> RdrName
+mkRdrQual :: ModuleName -> OccName -> RdrName
 mkRdrQual mod occ = Qual mod occ
 
 mkOrig :: Module -> OccName -> RdrName
@@ -146,7 +136,7 @@ mkVarUnqual :: FastString -> RdrName
 mkVarUnqual n = Unqual (mkVarOccFS n)
 
 mkQual :: NameSpace -> (FastString, FastString) -> RdrName
-mkQual sp (m, n) = Qual (mkModuleFS m) (mkOccNameFS sp n)
+mkQual sp (m, n) = Qual (mkModuleNameFS m) (mkOccNameFS sp n)
 
 getRdrName :: NamedThing thing => thing -> RdrName
 getRdrName name = nameRdrName (getName name)
@@ -164,31 +154,46 @@ nukeExact n
 \end{code}
 
 \begin{code}
+isRdrDataCon :: RdrName -> Bool
+isRdrTyVar   :: RdrName -> Bool
+isRdrTc      :: RdrName -> Bool
+
 isRdrDataCon rn = isDataOcc (rdrNameOcc rn)
 isRdrTyVar   rn = isTvOcc   (rdrNameOcc rn)
 isRdrTc      rn = isTcOcc   (rdrNameOcc rn)
 
+isSrcRdrName :: RdrName -> Bool
 isSrcRdrName (Unqual _) = True
 isSrcRdrName (Qual _ _) = True
 isSrcRdrName _         = False
 
+isUnqual :: RdrName -> Bool
 isUnqual (Unqual _) = True
-isUnqual other     = False
+isUnqual _          = False
 
+isQual :: RdrName -> Bool
 isQual (Qual _ _) = True
 isQual _         = False
 
+isQual_maybe :: RdrName -> Maybe (ModuleName, OccName)
+isQual_maybe (Qual m n) = Just (m,n)
+isQual_maybe _         = Nothing
+
+isOrig :: RdrName -> Bool
 isOrig (Orig _ _) = True
 isOrig _         = False
 
+isOrig_maybe :: RdrName -> Maybe (Module, OccName)
 isOrig_maybe (Orig m n) = Just (m,n)
 isOrig_maybe _         = Nothing
 
+isExact :: RdrName -> Bool
 isExact (Exact _) = True
-isExact other  = False
+isExact _         = False
 
+isExact_maybe :: RdrName -> Maybe Name
 isExact_maybe (Exact n) = Just n
-isExact_maybe other    = Nothing
+isExact_maybe _         = Nothing
 \end{code}
 
 
@@ -201,11 +206,9 @@ isExact_maybe other        = Nothing
 \begin{code}
 instance Outputable RdrName where
     ppr (Exact name)   = ppr name
-    ppr (Unqual occ)   = ppr occ <+> ppr_name_space occ
-    ppr (Qual mod occ) = ppr mod <> dot <> ppr occ <+> ppr_name_space occ
-    ppr (Orig mod occ) = ppr mod <> dot <> ppr occ <+> ppr_name_space occ
-
-ppr_name_space occ = ifPprDebug (parens (pprNonVarNameSpace (occNameSpace occ)))
+    ppr (Unqual occ)   = ppr occ
+    ppr (Qual mod occ) = ppr mod <> dot <> ppr occ
+    ppr (Orig mod occ) = ppr mod <> dot <> ppr occ
 
 instance OutputableBndr RdrName where
     pprBndr _ n 
@@ -221,7 +224,7 @@ instance Eq RdrName where
     (Orig m1 o1)  == (Orig m2 o2)  = m1==m2 && o1==o2
     (Qual m1 o1)  == (Qual m2 o2)  = m1==m2 && o1==o2
     (Unqual o1)   == (Unqual o2)   = o1==o2
-    r1 == r2 = False
+    _             == _             = False
 
 instance Ord RdrName where
     a <= b = case (a `compare` b) of { LT -> True;  EQ -> True;  GT -> False }
@@ -238,7 +241,7 @@ instance Ord RdrName where
        --           <decl involving n1,n2> }
        --      I think we can do without this conversion
     compare (Exact n1) (Exact n2) = n1 `compare` n2
-    compare (Exact n1) n2        = LT
+    compare (Exact _)  _          = LT
 
     compare (Unqual _)   (Exact _)    = GT
     compare (Unqual o1)  (Unqual  o2) = o1 `compare` o2
@@ -267,6 +270,7 @@ It is keyed by OccName, because we never use it for qualified names.
 \begin{code}
 type LocalRdrEnv = OccEnv Name
 
+emptyLocalRdrEnv :: LocalRdrEnv
 emptyLocalRdrEnv = emptyOccEnv
 
 extendLocalRdrEnv :: LocalRdrEnv -> [Name] -> LocalRdrEnv
@@ -274,9 +278,12 @@ extendLocalRdrEnv env names
   = extendOccEnvList env [(nameOccName n, n) | n <- names]
 
 lookupLocalRdrEnv :: LocalRdrEnv -> RdrName -> Maybe Name
-lookupLocalRdrEnv env (Exact name) = Just name
+lookupLocalRdrEnv _   (Exact name) = Just name
 lookupLocalRdrEnv env (Unqual occ) = lookupOccEnv env occ
-lookupLocalRdrEnv env other       = Nothing
+lookupLocalRdrEnv _   _            = Nothing
+
+lookupLocalRdrOcc :: LocalRdrEnv -> OccName -> Maybe Name
+lookupLocalRdrOcc env occ = lookupOccEnv env occ
 
 elemLocalRdrEnv :: RdrName -> LocalRdrEnv -> Bool
 elemLocalRdrEnv rdr_name env 
@@ -305,23 +312,46 @@ type GlobalRdrEnv = OccEnv [GlobalRdrElt]
        -- INVARIANT: All the members of the list have distinct 
        --            gre_name fields; that is, no duplicate Names
 
+data GlobalRdrElt 
+  = GRE { gre_name :: Name,
+         gre_par  :: Parent,
+         gre_prov :: Provenance        -- Why it's in scope
+    }
+
+data Parent = NoParent | ParentIs Name
+             deriving (Eq)
+
+instance Outputable Parent where
+   ppr NoParent     = empty
+   ppr (ParentIs n) = ptext (sLit "parent:") <> ppr n
+   
+
+plusParent :: Parent -> Parent -> Parent
+plusParent p1 p2 = ASSERT2( p1 == p2, parens (ppr p1) <+> parens (ppr p2) )
+                   p1
+
+{- Why so complicated? -=chak
+plusParent :: Parent -> Parent -> Parent
+plusParent NoParent     rel = 
+  ASSERT2( case rel of { NoParent -> True; other -> False }, 
+          ptext (sLit "plusParent[NoParent]: ") <+> ppr rel )    
+  NoParent
+plusParent (ParentIs n) rel = 
+  ASSERT2( case rel of { ParentIs m -> n==m;  other -> False }, 
+          ptext (sLit "plusParent[ParentIs]:") <+> ppr n <> comma <+> ppr rel )
+  ParentIs n
+ -}
+
+emptyGlobalRdrEnv :: GlobalRdrEnv
 emptyGlobalRdrEnv = emptyOccEnv
 
 globalRdrEnvElts :: GlobalRdrEnv -> [GlobalRdrElt]
 globalRdrEnvElts env = foldOccEnv (++) [] env
 
-data GlobalRdrElt 
-  = GRE { gre_name   :: Name,
-         gre_prov   :: Provenance      -- Why it's in scope
-    }
-
 instance Outputable GlobalRdrElt where
-  ppr gre = ppr name <+> pp_parent (nameParent_maybe name)
-               <+> parens (pprNameProvenance gre)
+  ppr gre = ppr name <+> parens (ppr (gre_par gre) <+> pprNameProvenance gre)
          where
            name = gre_name gre
-           pp_parent (Just p) = brackets (text "parent:" <+> ppr p)
-           pp_parent Nothing  = empty
 
 pprGlobalRdrEnv :: GlobalRdrEnv -> SDoc
 pprGlobalRdrEnv env
@@ -334,7 +364,7 @@ pprGlobalRdrEnv env
 
 \begin{code}
 lookupGlobalRdrEnv :: GlobalRdrEnv -> OccName -> [GlobalRdrElt]
-lookupGlobalRdrEnv env rdr_name = case lookupOccEnv env rdr_name of
+lookupGlobalRdrEnv env occ_name = case lookupOccEnv env occ_name of
                                        Nothing   -> []
                                        Just gres -> gres
 
@@ -355,6 +385,11 @@ lookupGRE_Name env name
   = [ gre | gre <- lookupGlobalRdrEnv env (nameOccName name),
            gre_name gre == name ]
 
+getGRE_NameQualifier_maybes :: GlobalRdrEnv -> Name -> [Maybe [ModuleName]]
+getGRE_NameQualifier_maybes env
+  = map qualifier_maybe . map gre_prov . lookupGRE_Name env
+  where qualifier_maybe LocalDef       = Nothing
+        qualifier_maybe (Imported iss) = Just $ map (is_as . is_decl) iss 
 
 pickGREs :: RdrName -> [GlobalRdrElt] -> [GlobalRdrElt]
 -- Take a list of GREs which have the right OccName
@@ -374,33 +409,48 @@ pickGREs :: RdrName -> [GlobalRdrElt] -> [GlobalRdrElt]
 pickGREs rdr_name gres
   = mapCatMaybes pick gres
   where
-    is_unqual = isUnqual rdr_name
-    mod              = rdrNameModule rdr_name
+    rdr_is_unqual = isUnqual rdr_name
+    rdr_is_qual   = isQual_maybe rdr_name
 
     pick :: GlobalRdrElt -> Maybe GlobalRdrElt
     pick gre@(GRE {gre_prov = LocalDef, gre_name = n})         -- Local def
-       | is_unqual || nameModule n == mod = Just gre
-       | otherwise                        = Nothing
+       | rdr_is_unqual                         = Just gre
+       | Just (mod,_) <- rdr_is_qual, 
+         mod == moduleName (nameModule n)      = Just gre
+       | otherwise                             = Nothing
     pick gre@(GRE {gre_prov = Imported [is]})  -- Single import (efficiency)
-       | is_unqual     = if not (is_qual (is_decl is)) then Just gre
-                                                       else Nothing
-       | otherwise     = if mod == is_as (is_decl is)  then Just gre
-                                                       else Nothing
+       | rdr_is_unqual,
+         not (is_qual (is_decl is))            = Just gre
+       | Just (mod,_) <- rdr_is_qual, 
+         mod == is_as (is_decl is)             = Just gre
+       | otherwise                             = Nothing
     pick gre@(GRE {gre_prov = Imported is})    -- Multiple import
        | null filtered_is = Nothing
        | otherwise        = Just (gre {gre_prov = Imported filtered_is})
        where
-         filtered_is | is_unqual = filter (not . is_qual    . is_decl) is
-                     | otherwise = filter ((== mod) . is_as . is_decl) is
+         filtered_is | rdr_is_unqual
+                     = filter (not . is_qual    . is_decl) is
+                     | Just (mod,_) <- rdr_is_qual 
+                     = filter ((== mod) . is_as . is_decl) is
+                     | otherwise
+                     = []
 
 isLocalGRE :: GlobalRdrElt -> Bool
 isLocalGRE (GRE {gre_prov = LocalDef}) = True
-isLocalGRE other                      = False
+isLocalGRE _                           = False
 
 unQualOK :: GlobalRdrElt -> Bool
 -- An unqualifed version of this thing is in scope
 unQualOK (GRE {gre_prov = LocalDef})    = True
-unQualOK (GRE {gre_prov = Imported is}) = not (all (is_qual . is_decl) is)
+unQualOK (GRE {gre_prov = Imported is}) = any unQualSpecOK is
+
+unQualSpecOK :: ImportSpec -> Bool
+-- In scope unqualified
+unQualSpecOK is = not (is_qual (is_decl is))
+
+qualSpecOK :: ModuleName -> ImportSpec -> Bool
+-- In scope qualified with M
+qualSpecOK mod is = mod == is_as (is_decl is)
 
 plusGlobalRdrEnv :: GlobalRdrEnv -> GlobalRdrEnv -> GlobalRdrEnv
 plusGlobalRdrEnv env1 env2 = plusOccEnv_C (foldr insertGRE) env1 env2
@@ -413,6 +463,27 @@ mkGlobalRdrEnv gres
                                 (nameOccName (gre_name gre)) 
                                 [gre]
 
+findLocalDupsRdrEnv :: GlobalRdrEnv -> [OccName] -> (GlobalRdrEnv, [[Name]])
+-- For each OccName, see if there are multiple LocalDef definitions
+-- for it.  If so, remove all but one (to suppress subsequent error messages)
+-- and return a list of the duplicate bindings
+findLocalDupsRdrEnv rdr_env occs 
+  = go rdr_env [] occs
+  where
+    go rdr_env dups [] = (rdr_env, dups)
+    go rdr_env dups (occ:occs)
+      = case filter isLocalGRE gres of
+         []       -> WARN( True, ppr occ <+> ppr rdr_env ) 
+                     go rdr_env dups occs      -- Weird!  No binding for occ
+         [_]      -> go rdr_env dups occs      -- The common case
+         dup_gres -> go (extendOccEnv rdr_env occ (head dup_gres : nonlocal_gres))
+                        (map gre_name dup_gres : dups)
+                        occs
+      where
+        gres = lookupOccEnv rdr_env occ `orElse` []
+       nonlocal_gres = filterOut isLocalGRE gres
+
+
 insertGRE :: GlobalRdrElt -> [GlobalRdrElt] -> [GlobalRdrElt]
 insertGRE new_g [] = [new_g]
 insertGRE new_g (old_g : old_gs)
@@ -425,7 +496,37 @@ plusGRE :: GlobalRdrElt -> GlobalRdrElt -> GlobalRdrElt
 -- Used when the gre_name fields match
 plusGRE g1 g2
   = GRE { gre_name = gre_name g1,
-         gre_prov = gre_prov g1 `plusProv` gre_prov g2 }
+         gre_prov = gre_prov g1 `plusProv`   gre_prov g2,
+         gre_par  = gre_par  g1 `plusParent` gre_par  g2 }
+
+hideSomeUnquals :: GlobalRdrEnv -> [OccName] -> GlobalRdrEnv
+-- Hide any unqualified bindings for the specified OccNames
+-- This is used in TH, when renaming a declaration bracket
+--     [d| foo = ... |]
+-- We want unqualified 'foo' in "..." to mean this foo, not
+-- the one from the enclosing module.  But the *qualified* name
+-- from the enclosing moudule must certainly still be avaialable
+--     Seems like 5 times as much work as it deserves!
+hideSomeUnquals rdr_env occs
+  = foldr hide rdr_env occs
+  where
+    hide occ env 
+       | Just gres <- lookupOccEnv env occ = extendOccEnv env occ (map qual_gre gres)
+       | otherwise                         = env
+    qual_gre gre@(GRE { gre_name = name, gre_prov = LocalDef })
+       = gre { gre_prov = Imported [imp_spec] }
+       where   -- Local defs get transfomed to (fake) imported things
+         mod = moduleName (nameModule name)
+         imp_spec = ImpSpec { is_item = ImpAll, is_decl = decl_spec }
+         decl_spec = ImpDeclSpec { is_mod = mod, is_as = mod, 
+                                   is_qual = True, 
+                                   is_dloc = srcLocSpan (nameSrcLoc name) }
+
+    qual_gre gre@(GRE { gre_prov = Imported specs })
+       = gre { gre_prov = Imported (map qual_spec specs) }
+
+    qual_spec spec@(ImpSpec { is_decl = decl_spec })
+       = spec { is_decl = decl_spec { is_qual = True } }
 \end{code}
 
 
@@ -451,10 +552,12 @@ data ImportSpec = ImpSpec { is_decl :: ImpDeclSpec,
 data ImpDeclSpec       -- Describes a particular import declaration
                        -- Shared among all the Provenaces for that decl
   = ImpDeclSpec {
-       is_mod      :: Module,  -- 'import Muggle'
+       is_mod      :: ModuleName, -- 'import Muggle'
                                -- Note the Muggle may well not be 
                                -- the defining module for this thing!
-       is_as       :: Module,  -- 'as M' (or 'Muggle' if there is no 'as' clause)
+                                -- TODO: either should be Module, or there
+                                -- should be a Maybe PackageId here too.
+       is_as       :: ModuleName, -- 'as M' (or 'Muggle' if there is no 'as' clause)
        is_qual     :: Bool,    -- True <=> qualified (only)
        is_dloc     :: SrcSpan  -- Location of import declaration
     }
@@ -478,9 +581,13 @@ importSpecLoc :: ImportSpec -> SrcSpan
 importSpecLoc (ImpSpec decl ImpAll) = is_dloc decl
 importSpecLoc (ImpSpec _    item)   = is_iloc item
 
-importSpecModule :: ImportSpec -> Module
+importSpecModule :: ImportSpec -> ModuleName
 importSpecModule is = is_mod (is_decl is)
 
+isExplicitItem :: ImpItemSpec -> Bool
+isExplicitItem ImpAll                       = False
+isExplicitItem (ImpSome {is_explicit = exp}) = exp
+
 -- Note [Comparing provenance]
 -- Comparison of provenance is just used for grouping 
 -- error messages (in RnEnv.warnUnusedBinds)
@@ -516,25 +623,31 @@ plusProv :: Provenance -> Provenance -> Provenance
 -- defined, and one might refer to it with a qualified name from
 -- the import -- but I'm going to ignore that because it makes
 -- the isLocalGRE predicate so much nicer this way
-plusProv LocalDef       LocalDef        = panic "plusProv"
-plusProv LocalDef       p2              = LocalDef
-plusProv p1             LocalDef        = LocalDef
+plusProv LocalDef        LocalDef        = panic "plusProv"
+plusProv LocalDef        _               = LocalDef
+plusProv _               LocalDef        = LocalDef
 plusProv (Imported is1)  (Imported is2)  = Imported (is1++is2)
 
 pprNameProvenance :: GlobalRdrElt -> SDoc
 -- Print out the place where the name was imported
 pprNameProvenance (GRE {gre_name = name, gre_prov = LocalDef})
-  = ptext SLIT("defined at") <+> ppr (nameSrcLoc name)
-pprNameProvenance (GRE {gre_name = name, gre_prov = Imported (why:whys)})
-  = sep [ppr why, nest 2 (ppr_defn (nameSrcLoc name))]
+  = ptext (sLit "defined at") <+> ppr (nameSrcLoc name)
+pprNameProvenance (GRE {gre_name = name, gre_prov = Imported whys})
+  = case whys of
+       (why:_) -> sep [ppr why, nest 2 (ppr_defn (nameSrcLoc name))]
+       [] -> panic "pprNameProvenance"
 
 -- If we know the exact definition point (which we may do with GHCi)
 -- then show that too.  But not if it's just "imported from X".
-ppr_defn loc | isGoodSrcLoc loc = parens (ptext SLIT("defined at") <+> ppr loc)
+ppr_defn :: SrcLoc -> SDoc
+ppr_defn loc | isGoodSrcLoc loc = parens (ptext (sLit "defined at") <+> ppr loc)
             | otherwise        = empty
 
 instance Outputable ImportSpec where
-   ppr imp_spec@(ImpSpec imp_decl _)
-     = ptext SLIT("imported from") <+> ppr (is_mod imp_decl) 
-       <+> ptext SLIT("at") <+> ppr (importSpecLoc imp_spec)
+   ppr imp_spec
+     = ptext (sLit "imported from") <+> ppr (importSpecModule imp_spec) 
+       <+> if isGoodSrcSpan loc then ptext (sLit "at") <+> ppr loc
+                                else empty
+     where
+       loc = importSpecLoc imp_spec
 \end{code}