+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}
+data Provenance
+ = LocalDef -- Defined locally
+ | Imported -- Imported
+ [ImportSpec] -- INVARIANT: 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
+ = ImpDeclSpec {
+ is_mod :: Module, -- '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)
+ is_qual :: Bool, -- True <=> qualified (only)
+ is_dloc :: SrcSpan -- Location of import declaration
+ }
+
+data ImpItemSpec -- Describes import info a particular Name
+ = ImpAll -- The import had no import list,
+ -- or had a hiding list
+
+ | ImpSome { -- The import had an import list
+ 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.
+
+importSpecLoc :: ImportSpec -> SrcSpan
+importSpecLoc (ImpSpec decl ImpAll) = is_dloc decl
+importSpecLoc (ImpSpec _ item) = is_iloc item
+
+importSpecModule :: ImportSpec -> Module
+importSpecModule is = is_mod (is_decl is)
+
+-- Note [Comparing provenance]
+-- Comparison of provenance is just used for grouping
+-- error messages (in RnEnv.warnUnusedBinds)
+instance Eq Provenance where
+ p1 == p2 = case p1 `compare` p2 of EQ -> True; _ -> False
+
+instance Eq ImpDeclSpec where
+ p1 == p2 = case p1 `compare` p2 of EQ -> True; _ -> False
+
+instance Eq ImpItemSpec where
+ p1 == p2 = case p1 `compare` p2 of EQ -> True; _ -> False
+
+instance Ord Provenance where
+ compare LocalDef LocalDef = EQ
+ compare LocalDef (Imported _) = LT
+ compare (Imported _ ) LocalDef = GT
+ compare (Imported is1) (Imported is2) = compare (head is1)
+ {- See Note [Comparing provenance] -} (head is2)
+
+instance Ord ImpDeclSpec where
+ compare is1 is2 = (is_mod is1 `compare` is_mod is2) `thenCmp`
+ (is_dloc is1 `compare` is_dloc is2)
+
+instance Ord ImpItemSpec where
+ compare is1 is2 = is_iloc is1 `compare` is_iloc is2
+\end{code}
+
+\begin{code}
+plusProv :: Provenance -> Provenance -> Provenance
+-- Choose LocalDef over Imported
+-- There is an obscure bug lurking here; in the presence
+-- of recursive modules, something can be imported *and* locally
+-- 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 (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))]
+
+-- 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)
+ | 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)
+\end{code}