import RnNames ( getGlobalNames )
import RnSource ( rnSourceDecls, rnDecl )
import RnIfaces ( getImportedInstDecls, importDecl, getImportVersions,
- getImportedRules, loadHomeInterface, getSlurped
+ getImportedRules, loadHomeInterface, getSlurped, removeContext
)
import RnEnv ( availName, availNames, availsToNameSet,
- warnUnusedTopNames, mapFvRn,
+ warnUnusedTopNames, mapFvRn, lookupImplicitOccRn,
FreeVars, plusFVs, plusFV, unitFV, emptyFVs, isEmptyFVs
)
import Module ( Module, ModuleName, pprModule, mkSearchPath, mkThisModule )
import Name ( Name, isLocallyDefined,
NamedThing(..), ImportReason(..), Provenance(..),
pprOccName, nameOccName,
- getNameProvenance, occNameUserString,
+ getNameProvenance,
maybeWiredInTyConName, maybeWiredInIdName, isWiredInName
)
import Id ( idType )
import NameSet
import PrelMods ( mAIN_Name, pREL_MAIN_Name )
import TysWiredIn ( unitTyCon, intTyCon, doubleTyCon, boolTyCon )
-import PrelInfo ( ioTyCon_NAME, thinAirIdNames )
+import PrelInfo ( ioTyCon_NAME, numClass_RDR, thinAirIdNames, derivingOccurrences )
import Type ( namesOfType, funTyCon )
-import ErrUtils ( pprBagOfErrors, pprBagOfWarnings,
- doIfSet, dumpIfSet, ghcExit
- )
+import ErrUtils ( printErrorsAndWarnings, dumpIfSet, ghcExit )
import BasicTypes ( NewOrData(..) )
import Bag ( isEmptyBag, bagToList )
import FiniteMap ( fmToList, delListFromFM, addToFM, sizeFM, eltsFM )
import UniqSupply ( UniqSupply )
+import UniqFM ( lookupUFM )
import Util ( equivClasses )
import Maybes ( maybeToBool )
import Outputable
\ (maybe_rn_stuff, rn_errs_bag, rn_warns_bag) ->
-- Check for warnings
- doIfSet (not (isEmptyBag rn_warns_bag))
- (printErrs (pprBagOfWarnings rn_warns_bag)) >>
-
- -- Check for errors; exit if so
- doIfSet (not (isEmptyBag rn_errs_bag))
- (printErrs (pprBagOfErrors rn_errs_bag) >>
- ghcExit 1
- ) >>
+ printErrorsAndWarnings rn_errs_bag rn_warns_bag >>
-- Dump output, if any
(case maybe_rn_stuff of
) >>
-- Return results
- return maybe_rn_stuff
+ if not (isEmptyBag rn_errs_bag) then
+ ghcExit 1 >> return Nothing
+ else
+ return maybe_rn_stuff
\end{code}
) `thenRn` \ (rn_local_decls, source_fvs) ->
-- SLURP IN ALL THE NEEDED DECLARATIONS
+ implicitFVs mod_name rn_local_decls `thenRn` \ implicit_fvs ->
let
- real_source_fvs = implicitFVs mod_name `plusFV` source_fvs
+ real_source_fvs = implicit_fvs `plusFV` source_fvs
-- It's important to do the "plus" this way round, so that
-- when compiling the prelude, locally-defined (), Bool, etc
-- override the implicit ones.
mentioned explicitly, but which might be needed by the type checker.
\begin{code}
-implicitFVs mod_name
- = implicit_main `plusFV`
- mkNameSet default_tys `plusFV`
- mkNameSet thinAirIdNames
+implicitFVs mod_name decls
+ = mapRn lookupImplicitOccRn implicit_occs `thenRn` \ implicit_names ->
+ returnRn (implicit_main `plusFV`
+ mkNameSet default_tys `plusFV`
+ mkNameSet thinAirIdNames `plusFV`
+ mkNameSet implicit_names)
+
where
-- Add occurrences for Int, Double, and (), because they
-- are the types to which ambigious type variables may be defaulted by
implicit_main | mod_name == mAIN_Name
|| mod_name == pREL_MAIN_Name = unitFV ioTyCon_NAME
| otherwise = emptyFVs
+
+ -- Now add extra "occurrences" for things that
+ -- the deriving mechanism, or defaulting, will later need in order to
+ -- generate code
+ implicit_occs = foldr ((++) . get) [] decls
+
+ get (DefD _) = [numClass_RDR]
+ get (TyClD (TyData _ _ _ _ _ (Just deriv_classes) _ _))
+ = concat (map get_deriv deriv_classes)
+ get other = []
+
+ get_deriv cls = case lookupUFM derivingOccurrences cls of
+ Nothing -> []
+ Just occs -> occs
\end{code}
\begin{code}
isOrphanDecl (InstD (InstDecl inst_ty _ _ _ _))
- = not (foldNameSet ((||) . isLocallyDefined) False (extractHsTyNames inst_ty))
+ = not (foldNameSet ((||) . isLocallyDefined) False (extractHsTyNames (removeContext inst_ty)))
+ -- The 'removeContext' is because of
+ -- instance Foo a => Baz T where ...
+ -- The decl is an orphan if Baz and T are both not locally defined,
+ -- even if Foo *is* locally defined
+
isOrphanDecl (RuleD (RuleDecl _ _ _ lhs _ _))
= check lhs
where
-------------------------------------------------------
slurpImpDecls source_fvs
= traceRn (text "slurpImp" <+> fsep (map ppr (nameSetToList source_fvs))) `thenRn_`
+
-- The current slurped-set records all local things
- getSlurped `thenRn` \ local_binders ->
+ getSlurped `thenRn` \ source_binders ->
+ slurpSourceRefs source_binders source_fvs `thenRn` \ (decls, needed) ->
- slurpSourceRefs source_fvs `thenRn` \ (decls1, needed1, wired_in) ->
- let
- inst_gates1 = foldr (plusFV . getWiredInGates) source_fvs wired_in
- inst_gates2 = foldr (plusFV . getGates source_fvs) inst_gates1 decls1
- in
- -- Do this first slurpDecls before the getImportedInstDecls,
- -- so that the home modules of all the inst_gates will be sure to be loaded
- slurpDecls decls1 needed1 `thenRn` \ (decls2, needed2) ->
- mapRn_ (load_home local_binders) wired_in `thenRn_`
-
- -- Now we can get the instance decls
- getImportedInstDecls inst_gates2 `thenRn` \ inst_decls ->
- rnIfaceDecls decls2 needed2 inst_decls `thenRn` \ (decls3, needed3) ->
- closeDecls decls3 needed3
+ -- And finally get everything else
+ closeDecls decls needed
+
+-------------------------------------------------------
+slurpSourceRefs :: NameSet -- Variables defined in source
+ -> FreeVars -- Variables referenced in source
+ -> RnMG ([RenamedHsDecl],
+ FreeVars) -- Un-satisfied needs
+-- The declaration (and hence home module) of each gate has
+-- already been loaded
+
+slurpSourceRefs source_binders source_fvs
+ = go_outer [] -- Accumulating decls
+ emptyFVs -- Unsatisfied needs
+ emptyFVs -- Accumulating gates
+ (nameSetToList source_fvs) -- Things whose defn hasn't been loaded yet
where
- load_home local_binders name
- | name `elemNameSet` local_binders = returnRn ()
+ -- The outer loop repeatedly slurps the decls for the current gates
+ -- and the instance decls
+
+ -- The outer loop is needed because consider
+ -- instance Foo a => Baz (Maybe a) where ...
+ -- It may be that @Baz@ and @Maybe@ are used in the source module,
+ -- but not @Foo@; so we need to chase @Foo@ too.
+ --
+ -- We also need to follow superclass refs. In particular, 'chasing @Foo@' must
+ -- include actually getting in Foo's class decl
+ -- class Wib a => Foo a where ..
+ -- so that its superclasses are discovered. The point is that Wib is a gate too.
+ -- We do this for tycons too, so that we look through type synonyms.
+
+ go_outer decls fvs all_gates []
+ = returnRn (decls, fvs)
+
+ go_outer decls fvs all_gates refs -- refs are not necessarily slurped yet
+ = traceRn (text "go_outer" <+> ppr refs) `thenRn_`
+ go_inner decls fvs emptyFVs refs `thenRn` \ (decls1, fvs1, gates1) ->
+ getImportedInstDecls (all_gates `plusFV` gates1) `thenRn` \ inst_decls ->
+ rnInstDecls decls1 fvs1 gates1 inst_decls `thenRn` \ (decls2, fvs2, gates2) ->
+ go_outer decls2 fvs2 (all_gates `plusFV` gates2)
+ (nameSetToList (gates2 `minusNameSet` all_gates))
+ -- Knock out the all_gates because even ifwe don't slurp any new
+ -- decls we can get some apparently-new gates from wired-in names
+
+ go_inner decls fvs gates []
+ = returnRn (decls, fvs, gates)
+
+ go_inner decls fvs gates (wanted_name:refs)
+ | isWiredInName wanted_name
+ = load_home wanted_name `thenRn_`
+ go_inner decls fvs (gates `plusFV` getWiredInGates wanted_name) refs
+
+ | otherwise
+ = importDecl wanted_name `thenRn` \ maybe_decl ->
+ case maybe_decl of
+ Nothing -> go_inner decls fvs gates refs -- No declaration... (already slurped, or local)
+ Just decl -> rnIfaceDecl decl `thenRn` \ (new_decl, fvs1) ->
+ go_inner (new_decl : decls)
+ (fvs1 `plusFV` fvs)
+ (gates `plusFV` getGates source_fvs new_decl)
+ refs
+
+ -- When we find a wired-in name we must load its
+ -- home module so that we find any instance decls therein
+ load_home name
+ | name `elemNameSet` source_binders = returnRn ()
-- When compiling the prelude, a wired-in thing may
-- be defined in this module, in which case we don't
-- want to load its home module!
where
doc = ptext SLIT("need home module for wired in thing") <+> ppr name
--------------------------------------------------------
-slurpSourceRefs :: FreeVars -- Variables referenced in source
- -> RnMG ([RenamedHsDecl],
- FreeVars, -- Un-satisfied needs
- [Name]) -- Those variables referenced in the source
- -- that turned out to be wired in things
+rnInstDecls decls fvs gates []
+ = returnRn (decls, fvs, gates)
+rnInstDecls decls fvs gates (d:ds)
+ = rnIfaceDecl d `thenRn` \ (new_decl, fvs1) ->
+ rnInstDecls (new_decl:decls)
+ (fvs1 `plusFV` fvs)
+ (gates `plusFV` getInstDeclGates new_decl)
+ ds
+\end{code}
-slurpSourceRefs source_fvs
- = go [] emptyFVs [] (nameSetToList source_fvs)
- where
- go decls fvs wired []
- = returnRn (decls, fvs, wired)
- go decls fvs wired (wanted_name:refs)
- | isWiredInName wanted_name
- = go decls fvs (wanted_name:wired) refs
- | otherwise
- = importDecl wanted_name `thenRn` \ maybe_decl ->
- case maybe_decl of
- -- No declaration... (already slurped, or local)
- Nothing -> go decls fvs wired refs
- Just decl -> rnIfaceDecl decl `thenRn` \ (new_decl, fvs1) ->
- go (new_decl : decls) (fvs1 `plusFV` fvs) wired
- (extraGates new_decl ++ refs)
-
--- Hack alert. If we suck in a class
--- class Ord a => Baz a where ...
--- then Eq is also a 'gate'. Why? Because Eq is a superclass of Ord,
--- and hence may be needed during context reduction even though
--- Eq is never mentioned explicitly. So we snaffle out the super-classes
--- right now, so that slurpSourceRefs will heave them in
---
--- Similarly the RHS of type synonyms
-extraGates (TyClD (ClassDecl ctxt _ tvs _ _ _ _ _ _ _))
- = nameSetToList (delListFromNameSet (extractHsCtxtTyNames ctxt) (map getTyVarName tvs))
-extraGates (TyClD (TySynonym _ tvs ty _))
- = nameSetToList (delListFromNameSet (extractHsTyNames ty) (map getTyVarName tvs))
-extraGates other = []
+\begin{code}
-------------------------------------------------------
-- closeDecls keeps going until the free-var set is empty
closeDecls decls needed
%*********************************************************
%* *
-\subsection{Extracting the 'gates'}
+\subsection{Extracting the `gates'}
%* *
%*********************************************************
When we import a declaration like
-
+\begin{verbatim}
data T = T1 Wibble | T2 Wobble
-
-we don't want to treat Wibble and Wobble as gates *unless* T1, T2
-respectively are mentioned by the user program. If only T is mentioned
-we want only T to be a gate; that way we don't suck in useless instance
-decls for (say) Eq Wibble, when they can't possibly be useful.
+\end{verbatim}
+we don't want to treat @Wibble@ and @Wobble@ as gates
+{\em unless} @T1@, @T2@ respectively are mentioned by the user program.
+If only @T@ is mentioned
+we want only @T@ to be a gate;
+that way we don't suck in useless instance
+decls for (say) @Eq Wibble@, when they can't possibly be useful.
@getGates@ takes a newly imported (and renamed) decl, and the free
vars of the source program, and extracts from the decl the gate names.
(map getTyVarName tvs)
`addOneToNameSet` cls
where
- get (ClassOpSig n _ ty _)
+ get (ClassOpSig n _ _ ty _)
| n `elemNameSet` source_fvs = extractHsTyNames ty
| otherwise = emptyFVs
getGates source_fvs (TyClD (TySynonym tycon tvs ty _))
= delListFromNameSet (extractHsTyNames ty)
(map getTyVarName tvs)
- `addOneToNameSet` tycon
+ -- A type synonym type constructor isn't a "gate" for instance decls
getGates source_fvs (TyClD (TyData _ ctxt tycon tvs cons _ _ _))
= delListFromNameSet (foldr (plusFV . get) (extractHsCtxtTyNames ctxt) cons)
getGates source_fvs other_decl = emptyFVs
\end{code}
-getWiredInGates is just like getGates, but it sees a wired-in Name
+@getWiredInGates@ is just like @getGates@, but it sees a wired-in @Name@
rather than a declaration.
\begin{code}
-getWiredInGates name | is_tycon = get_wired_tycon the_tycon
- | otherwise = get_wired_id the_id
+getWiredInGates :: Name -> FreeVars
+getWiredInGates name -- No classes are wired in
+ | is_id = getWiredInGates_s (namesOfType (idType the_id))
+ | isSynTyCon the_tycon = getWiredInGates_s
+ (delListFromNameSet (namesOfType ty) (map getName tyvars))
+ | otherwise = unitFV name
where
- maybe_wired_in_tycon = maybeWiredInTyConName name
- is_tycon = maybeToBool maybe_wired_in_tycon
maybe_wired_in_id = maybeWiredInIdName name
- Just the_tycon = maybe_wired_in_tycon
+ is_id = maybeToBool maybe_wired_in_id
+ maybe_wired_in_tycon = maybeWiredInTyConName name
Just the_id = maybe_wired_in_id
+ Just the_tycon = maybe_wired_in_tycon
+ (tyvars,ty) = getSynTyConDefn the_tycon
-get_wired_id id = namesOfType (idType id)
-
-get_wired_tycon tycon
- | isSynTyCon tycon
- = namesOfType ty `minusNameSet` mkNameSet (map getName tyvars)
+getWiredInGates_s names = foldr (plusFV . getWiredInGates) emptyFVs (nameSetToList names)
+\end{code}
- | otherwise -- data or newtype
- = foldr (unionNameSets . namesOfType . dataConType) emptyNameSet data_cons
- where
- (tyvars,ty) = getSynTyConDefn tycon
- data_cons = tyConDataCons tycon
+\begin{code}
+getInstDeclGates (InstD (InstDecl inst_ty _ _ _ _)) = extractHsTyNames inst_ty
+getInstDeclGates other = emptyFVs
\end{code}
\begin{code}
reportUnusedNames gbl_env avail_env (ExportEnv export_avails _) mentioned_names
- | not (opt_WarnUnusedBinds || opt_WarnUnusedImports)
- = returnRn ()
-
- | otherwise
= let
used_names = mentioned_names `unionNameSets` availsToNameSet export_avails
-- Now, a use of C implies a use of T,
-- if C was brought into scope by T(..) or T(C)
really_used_names = used_names `unionNameSets`
- mkNameSet [ availName avail
- | sub_name <- nameSetToList used_names,
- let avail = case lookupNameEnv avail_env sub_name of
- Just avail -> avail
- Nothing -> pprTrace "r.u.n" (ppr sub_name) $
- Avail sub_name
- ]
+ mkNameSet [ availName avail
+ | sub_name <- nameSetToList used_names,
+ let avail = case lookupNameEnv avail_env sub_name of
+ Just avail -> avail
+ Nothing -> WARN( True, text "reportUnusedName: not in avail_env" <+> ppr sub_name )
+ Avail sub_name
+ ]
defined_names = mkNameSet (concat (rdrEnvElts gbl_env))
- defined_but_not_used = nameSetToList (defined_names `minusNameSet` really_used_names)
+ defined_but_not_used =
+ nameSetToList (defined_names `minusNameSet` really_used_names)
-- Filter out the ones only defined implicitly
bad_guys = filter reportableUnusedName defined_but_not_used
in
- warnUnusedTopNames bad_guys `thenRn_`
- returnRn ()
+ warnUnusedTopNames bad_guys
reportableUnusedName :: Name -> Bool
reportableUnusedName name
- = explicitlyImported (getNameProvenance name) &&
- not (startsWithUnderscore (occNameUserString (nameOccName name)))
+ = explicitlyImported (getNameProvenance name)
where
- explicitlyImported (LocalDef _ _) = True -- Report unused defns of local vars
- explicitlyImported (NonLocalDef (UserImport _ _ expl) _) = expl -- Report unused explicit imports
- explicitlyImported other = False -- Don't report others
-
- -- Haskell 98 encourages compilers to suppress warnings about
- -- unused names in a pattern if they start with "_".
- startsWithUnderscore ('_' : _) = True -- Suppress warnings for names starting
- startsWithUnderscore other = False -- with an underscore
+ explicitlyImported (LocalDef _ _) = True
+ -- Report unused defns of local vars
+ explicitlyImported (NonLocalDef (UserImport _ _ expl) _) = expl
+ -- Report unused explicit imports
+ explicitlyImported other = False
+ -- Don't report others
rnStats :: [RenamedHsDecl] -> RnMG ()
rnStats imp_decls
n_mods = length [() | (_, _, Just _) <- eltsFM (iImpModInfo ifaces)]
decls_read = [decl | (_, avail, True, (_,decl)) <- nameEnvElts (iDecls ifaces),
- -- Data, newtype, and class decls are in the decls_fm
- -- under multiple names; the tycon/class, and each
- -- constructor/class op too.
- -- The 'True' selects just the 'main' decl
+ -- Data, newtype, and class decls are in the decls_fm
+ -- under multiple names; the tycon/class, and each
+ -- constructor/class op too.
+ -- The 'True' selects just the 'main' decl
not (isLocallyDefined (availName avail))
]