Add ASSERTs to all calls of nameModule
[ghc-hetmet.git] / compiler / basicTypes / RdrName.lhs
index 8729f47..6b28786 100644 (file)
@@ -1,54 +1,72 @@
 %
+% (c) The University of Glasgow 2006
 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
 
-\section[RdrName]{@RdrName@}
-
 \begin{code}
+
+-- |
+-- #name_types#
+-- GHC uses several kinds of name internally:
+--
+-- * 'OccName.OccName': see "OccName#name_types"
+--
+-- * 'RdrName.RdrName' is the type of names that come directly from the parser. They
+--   have not yet had their scoping and binding resolved by the renamer and can be
+--   thought of to a first approximation as an 'OccName.OccName' with an optional module
+--   qualifier
+--
+-- * 'Name.Name': see "Name#name_types"
+--
+-- * 'Id.Id': see "Id#name_types"
+--
+-- * 'Var.Var': see "Var#name_types"
 module RdrName (
+        -- * The main type
        RdrName(..),    -- Constructors exported only to BinIface
 
-       -- Construction
+       -- ** Construction
        mkRdrUnqual, mkRdrQual, 
        mkUnqual, mkVarUnqual, mkQual, mkOrig,
        nameRdrName, getRdrName, 
        mkDerivedRdrName, 
 
-       -- Destruction
-       rdrNameOcc, setRdrNameSpace,
+       -- ** Destruction
+       rdrNameOcc, rdrNameSpace, setRdrNameSpace,
        isRdrDataCon, isRdrTyVar, isRdrTc, isQual, isQual_maybe, isUnqual, 
        isOrig, isOrig_maybe, isExact, isExact_maybe, isSrcRdrName,
 
-       -- Printing;    instance Outputable RdrName
+       -- ** Printing
+       showRdrName,
 
-       -- LocalRdrEnv
+       -- * Local mapping of 'RdrName' to 'Name.Name'
        LocalRdrEnv, emptyLocalRdrEnv, extendLocalRdrEnv,
-       lookupLocalRdrEnv, elemLocalRdrEnv,
+       lookupLocalRdrEnv, lookupLocalRdrOcc, elemLocalRdrEnv,
 
-       -- GlobalRdrEnv
+       -- * Global mapping of 'RdrName' to 'GlobalRdrElt's
        GlobalRdrEnv, emptyGlobalRdrEnv, mkGlobalRdrEnv, plusGlobalRdrEnv, 
        lookupGlobalRdrEnv, extendGlobalRdrEnv,
        pprGlobalRdrEnv, globalRdrEnvElts,
-       lookupGRE_RdrName, lookupGRE_Name, hideSomeUnquals,
+       lookupGRE_RdrName, lookupGRE_Name, getGRE_NameQualifier_maybes,
+        hideSomeUnquals, findLocalDupsRdrEnv,
 
-       -- GlobalRdrElt, Provenance, ImportSpec
-       GlobalRdrElt(..), isLocalGRE, unQualOK, 
+       -- ** Global 'RdrName' mapping elements: 'GlobalRdrElt', 'Provenance', 'ImportSpec'
+       GlobalRdrElt(..), isLocalGRE, unQualOK, qualSpecOK, unQualSpecOK,
        Provenance(..), pprNameProvenance,
+       Parent(..), 
        ImportSpec(..), ImpDeclSpec(..), ImpItemSpec(..), 
-       importSpecLoc, importSpecModule
+       importSpecLoc, importSpecModule, isExplicitItem
   ) where 
 
 #include "HsVersions.h"
 
-import OccName
-import Module   ( ModuleName, mkModuleNameFS, Module, moduleName )
-import Name    ( Name, NamedThing(getName), nameModule, nameParent_maybe,
-                 nameOccName, isExternalName, nameSrcLoc )
-import Maybes  ( mapCatMaybes )
-import SrcLoc  ( isGoodSrcLoc, isGoodSrcSpan, srcLocSpan, SrcSpan )
-import FastString ( FastString )
+import Module
+import Name
+import Maybes
+import SrcLoc
+import FastString
 import Outputable
-import Util    ( thenCmp )
+import Util
 \end{code}
 
 %************************************************************************
@@ -58,30 +76,37 @@ import Util ( thenCmp )
 %************************************************************************
 
 \begin{code}
-data RdrName 
+-- | Do not use the data constructors of RdrName directly: prefer the family
+-- of functions that creates them, such as 'mkRdrUnqual'
+data RdrName
   = Unqual OccName
-       -- Used for ordinary, unqualified occurrences 
+       -- ^ Used for ordinary, unqualified occurrences, e.g. @x@, @y@ or @Foo@.
+       -- Create such a 'RdrName' with 'mkRdrUnqual'
 
   | Qual ModuleName OccName
-       -- A qualified name written by the user in 
-       --  *source* code.  The module isn't necessarily 
+       -- ^ A qualified name written by the user in 
+       -- /source/ code.  The module isn't necessarily 
        -- the module where the thing is defined; 
-       -- just the one from which it is imported
+       -- just the one from which it is imported.
+       -- Examples are @Bar.x@, @Bar.y@ or @Bar.Foo@.
+       -- Create such a 'RdrName' with 'mkRdrQual'
 
   | Orig Module OccName
-       -- An original name; the module is the *defining* module.
+       -- ^ An original name; the module is the /defining/ module.
        -- This is used when GHC generates code that will be fed
        -- into the renamer (e.g. from deriving clauses), but where
-       -- we want to say "Use Prelude.map dammit".  
+       -- we want to say \"Use Prelude.map dammit\". One of these
+       -- can be created with 'mkOrig'
  
   | Exact Name
-       -- 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
+       -- ^ We know exactly the 'Name'. This is used:
+       --
+       --  (1) When the parser parses built-in syntax like @[]@
+       --      and @(,)@, but wants a 'RdrName' from it
+       --
+       --  (2) By Template Haskell, when TH has generated a unique name
+       --
+       -- Such a 'RdrName' can be created by using 'getRdrName' on a 'Name'
 \end{code}
 
 
@@ -98,19 +123,28 @@ rdrNameOcc (Unqual occ) = occ
 rdrNameOcc (Orig _ occ) = occ
 rdrNameOcc (Exact name) = nameOccName name
 
+rdrNameSpace :: RdrName -> NameSpace
+rdrNameSpace = occNameSpace . rdrNameOcc
+
 setRdrNameSpace :: RdrName -> NameSpace -> RdrName
--- This rather gruesome function is used mainly by the parser
--- When parsing                data T a = T | T1 Int
--- we parse the data constructors as *types* because of parser ambiguities,
--- so then we need to change the *type constr* to a *data constr*
+-- ^ This rather gruesome function is used mainly by the parser.
+-- When parsing:
+--
+-- > data T a = T | T1 Int
 --
--- The original-name case *can* occur when parsing
---             data [] a = [] | a : [a]
--- For the orig-name case we return an unqualified name.
+-- we parse the data constructors as /types/ because of parser ambiguities,
+-- so then we need to change the /type constr/ to a /data constr/
+--
+-- The exact-name case /can/ occur when parsing:
+--
+-- > data [] a = [] | a : [a]
+--
+-- For the exact-name case we return an original name.
 setRdrNameSpace (Unqual occ) ns = Unqual (setOccNameSpace ns occ)
 setRdrNameSpace (Qual m occ) ns = Qual m (setOccNameSpace ns occ)
 setRdrNameSpace (Orig m occ) ns = Orig m (setOccNameSpace ns occ)
-setRdrNameSpace (Exact n)    ns = Orig (nameModule n)
+setRdrNameSpace (Exact n)    ns = ASSERT( isExternalName n ) 
+                                 Orig (nameModule n)
                                       (setOccNameSpace ns (nameOccName n))
 \end{code}
 
@@ -126,9 +160,12 @@ mkOrig :: Module -> OccName -> RdrName
 mkOrig mod occ = Orig mod occ
 
 ---------------
-mkDerivedRdrName :: Name -> (OccName -> OccName) -> (RdrName)
+-- | Produce an original 'RdrName' whose module that of a parent 'Name' but its 'OccName'
+-- is derived from that of it's parent using the supplied function
+mkDerivedRdrName :: Name -> (OccName -> OccName) -> RdrName
 mkDerivedRdrName parent mk_occ
-  = mkOrig (nameModule parent) (mk_occ (nameOccName parent))
+  = ASSERT2( isExternalName parent, ppr parent )
+    mkOrig (nameModule parent) (mk_occ (nameOccName parent))
 
 ---------------
        -- These two are used when parsing source files
@@ -139,6 +176,8 @@ mkUnqual sp n = Unqual (mkOccNameFS sp n)
 mkVarUnqual :: FastString -> RdrName
 mkVarUnqual n = Unqual (mkVarOccFS n)
 
+-- | Make a qualified 'RdrName' in the given namespace and where the 'ModuleName' and
+-- the 'OccName' are taken from the first and second elements of the tuple respectively
 mkQual :: NameSpace -> (FastString, FastString) -> RdrName
 mkQual sp (m, n) = Qual (mkModuleNameFS m) (mkOccNameFS sp n)
 
@@ -158,34 +197,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}
 
 
@@ -207,6 +258,9 @@ instance OutputableBndr RdrName where
        | isTvOcc (rdrNameOcc n) = char '@' <+> ppr n
        | otherwise              = ppr n
 
+showRdrName :: RdrName -> String
+showRdrName r = showSDoc (ppr r)
+
 instance Eq RdrName where
     (Exact n1)           == (Exact n2)    = n1==n2
        -- Convert exact to orig
@@ -216,7 +270,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 }
@@ -233,7 +287,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
@@ -248,20 +302,18 @@ instance Ord RdrName where
     compare (Orig _ _)   _           = GT
 \end{code}
 
-
-
 %************************************************************************
 %*                                                                     *
                        LocalRdrEnv
 %*                                                                     *
 %************************************************************************
 
-A LocalRdrEnv is used for local bindings (let, where, lambda, case)
-It is keyed by OccName, because we never use it for qualified names.
-
 \begin{code}
+-- | This environment is used to store local bindings (@let@, @where@, lambda, @case@).
+-- It is keyed by OccName, because we never use it for qualified names
 type LocalRdrEnv = OccEnv Name
 
+emptyLocalRdrEnv :: LocalRdrEnv
 emptyLocalRdrEnv = emptyOccEnv
 
 extendLocalRdrEnv :: LocalRdrEnv -> [Name] -> LocalRdrEnv
@@ -269,9 +321,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 
@@ -279,7 +334,6 @@ elemLocalRdrEnv rdr_name env
   | otherwise        = False
 \end{code}
 
-
 %************************************************************************
 %*                                                                     *
                        GlobalRdrEnv
@@ -288,35 +342,59 @@ elemLocalRdrEnv rdr_name env
 
 \begin{code}
 type GlobalRdrEnv = OccEnv [GlobalRdrElt]
-       -- Keyed by OccName; when looking up a qualified name
-       -- we look up the OccName part, and then check the Provenance
-       -- to see if the appropriate qualification is valid.  This
-       -- saves routinely doubling the size of the env by adding both
-       -- qualified and unqualified names to the domain.
-       --
-       -- The list in the range is reqd because there may be name clashes
-       -- These only get reported on lookup, not on construction
+-- ^ Keyed by 'OccName'; when looking up a qualified name
+-- we look up the 'OccName' part, and then check the 'Provenance'
+-- to see if the appropriate qualification is valid.  This
+-- saves routinely doubling the size of the env by adding both
+-- qualified and unqualified names to the domain.
+--
+-- The list in the codomain is required because there may be name clashes
+-- These only get reported on lookup, not on construction
+--
+-- INVARIANT: All the members of the list have distinct 
+--           'gre_name' fields; that is, no duplicate Names
 
-       -- INVARIANT: All the members of the list have distinct 
-       --            gre_name fields; that is, no duplicate Names
+-- | An element of the 'GlobalRdrEnv'
+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
@@ -329,7 +407,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
 
@@ -350,22 +428,31 @@ 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
+-- ^ Take a list of GREs which have the right OccName
 -- Pick those GREs that are suitable for this RdrName
 -- And for those, keep only only the Provenances that are suitable
 -- 
--- Consider
+-- Consider:
+--
+-- @
 --      module A ( f ) where
 --      import qualified Foo( f )
 --      import Baz( f )
 --      f = undefined
--- Let's suppose that Foo.f and Baz.f are the same entity really.
--- The export of f is ambiguous because it's in scope from the local def
--- and the import.  The lookup of (Unqual f) should return a GRE for
--- the locally-defined f, and a GRE for the imported f, with a *single* 
--- provenance, namely the one for Baz(f).
+-- @
+--
+-- Let's suppose that @Foo.f@ and @Baz.f@ are the same entity really.
+-- The export of @f@ is ambiguous because it's in scope from the local def
+-- and the import.  The lookup of @Unqual f@ should return a GRE for
+-- the locally-defined @f@, and a GRE for the imported @f@, with a /single/ 
+-- provenance, namely the one for @Baz(f)@.
 pickGREs rdr_name gres
   = mapCatMaybes pick gres
   where
@@ -397,12 +484,12 @@ pickGREs rdr_name gres
 
 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
+-- ^ Test if an unqualifed version of this thing would be 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
 
 plusGlobalRdrEnv :: GlobalRdrEnv -> GlobalRdrEnv -> GlobalRdrEnv
 plusGlobalRdrEnv env1 env2 = plusOccEnv_C (foldr insertGRE) env1 env2
@@ -415,6 +502,27 @@ mkGlobalRdrEnv gres
                                 (nameOccName (gre_name gre)) 
                                 [gre]
 
+findLocalDupsRdrEnv :: GlobalRdrEnv -> [OccName] -> (GlobalRdrEnv, [[Name]])
+-- ^ For each 'OccName', see if there are multiple local 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)
@@ -427,15 +535,19 @@ 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
+-- ^ 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
+--
+-- > [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 module must certainly still be available
+
 --     Seems like 5 times as much work as it deserves!
 hideSomeUnquals rdr_env occs
   = foldr hide rdr_env occs
@@ -444,9 +556,9 @@ hideSomeUnquals rdr_env occs
        | 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_name = name, gre_prov = Imported [imp_spec] }
+       = gre { gre_prov = Imported [imp_spec] }
        where   -- Local defs get transfomed to (fake) imported things
-         mod = moduleName (nameModule name)
+         mod = ASSERT2( isExternalName name, ppr name) 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, 
@@ -459,53 +571,66 @@ hideSomeUnquals rdr_env occs
        = spec { is_decl = decl_spec { is_qual = True } }
 \end{code}
 
-
 %************************************************************************
 %*                                                                     *
                        Provenance
 %*                                                                     *
 %************************************************************************
 
-The "provenance" of something says how it came to be in scope.
-It's quite elaborate so that we can give accurate unused-name warnings.
-
 \begin{code}
+-- | The 'Provenance' of something says how it came to be in scope.
+-- It's quite elaborate so that we can give accurate unused-name warnings.
 data Provenance
-  = LocalDef           -- Defined locally
-  | Imported           -- Imported
-       [ImportSpec]    -- INVARIANT: non-empty
+  = LocalDef           -- ^ The thing was defined locally
+  | Imported           
+       [ImportSpec]    -- ^ The thing was imported.
+                       -- 
+                       -- INVARIANT: the list of 'ImportSpec' is non-empty
 
 data ImportSpec = ImpSpec { is_decl :: ImpDeclSpec,
                            is_item ::  ImpItemSpec }
                deriving( Eq, Ord )
 
-data ImpDeclSpec       -- Describes a particular import declaration
-                       -- Shared among all the Provenaces for that decl
+-- | Describes a particular import declaration and is
+-- shared among all the 'Provenance's for that decl
+data ImpDeclSpec
   = ImpDeclSpec {
-       is_mod      :: ModuleName, -- 'import Muggle'
-                               -- Note the Muggle may well not be 
-                               -- the defining module for this thing!
-                                -- 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
+       is_mod      :: ModuleName, -- ^ Module imported, e.g. @import Muggle@
+                                  -- Note the @Muggle@ may well not be 
+                                  -- the defining module for this thing!
+
+                                   -- TODO: either should be Module, or there
+                                   -- should be a Maybe PackageId here too.
+       is_as       :: ModuleName, -- ^ Import alias, e.g. from @as M@ (or @Muggle@ if there is no @as@ clause)
+       is_qual     :: Bool,       -- ^ Was this import qualified?
+       is_dloc     :: SrcSpan     -- ^ The location of the import declaration
     }
 
-data ImpItemSpec  -- Describes import info a particular Name
-  = ImpAll             -- The import had no import list, 
-                       -- or  had a hiding list
+-- | Describes import info a particular Name
+data ImpItemSpec
+  = ImpAll             -- ^ The import had no import list, 
+                       -- or had a hiding list
 
-  | ImpSome {          -- The import had an import list
+  | ImpSome {
        is_explicit :: Bool,
        is_iloc     :: SrcSpan  -- Location of the import item
-    }
-       -- The is_explicit field is True iff the thing was named 
-       -- *explicitly* in the import specs rather 
-       -- than being imported as part of a "..." group 
-       -- e.g.         import C( T(..) )
-       -- Here the constructors of T are not named explicitly; 
-       -- only T is named explicitly.
+    }   -- ^ The import had an import list.
+       -- The 'is_explicit' field is @True@ iff the thing was named 
+       -- /explicitly/ in the import specs rather
+       -- than being imported as part of a "..." group. Consider:
+       --
+       -- > import C( T(..) )
+       --
+       -- Here the constructors of @T@ are not named explicitly; 
+       -- only @T@ is named explicitly.
+
+unQualSpecOK :: ImportSpec -> Bool
+-- ^ Is in scope unqualified?
+unQualSpecOK is = not (is_qual (is_decl is))
+
+qualSpecOK :: ModuleName -> ImportSpec -> Bool
+-- ^ Is in scope qualified with the given module?
+qualSpecOK mod is = mod == is_as (is_decl is)
 
 importSpecLoc :: ImportSpec -> SrcSpan
 importSpecLoc (ImpSpec decl ImpAll) = is_dloc decl
@@ -514,6 +639,10 @@ importSpecLoc (ImpSpec _    item)   = is_iloc item
 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)
@@ -549,29 +678,30 @@ 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
+-- ^ Print out the place where the name was imported
 pprNameProvenance (GRE {gre_name = name, gre_prov = LocalDef})
-  = ptext SLIT("defined at") <+> ppr (nameSrcLoc name)
+  = ptext (sLit "defined at") <+> ppr (nameSrcLoc name)
 pprNameProvenance (GRE {gre_name = name, gre_prov = Imported whys})
   = case whys of
-       (why:whys) -> sep [ppr why, nest 2 (ppr_defn (nameSrcLoc name))]
+       (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
-     = ptext SLIT("imported from") <+> ppr (importSpecModule imp_spec) 
-       <+> if isGoodSrcSpan loc then ptext SLIT("at") <+> ppr loc
+     = ptext (sLit "imported from") <+> ppr (importSpecModule imp_spec) 
+       <+> if isGoodSrcSpan loc then ptext (sLit "at") <+> ppr loc
                                 else empty
      where
        loc = importSpecLoc imp_spec