Implement -Wunrecognised-warning-flag
[ghc.git] / compiler / main / DynFlags.hs
index a23ecfa..f6496d5 100644 (file)
@@ -45,6 +45,7 @@ module DynFlags (
         GhcMode(..), isOneShot,
         GhcLink(..), isNoLink,
         PackageFlag(..), PackageArg(..), ModRenaming(..),
+        IgnorePackageFlag(..), TrustFlag(..),
         PkgConfRef(..),
         Option(..), showOpt,
         DynLibLoader(..),
@@ -81,6 +82,7 @@ module DynFlags (
         defaultDynFlags,                -- Settings -> DynFlags
         defaultWays,
         interpWays,
+        interpreterProfiled, interpreterDynamic,
         initDynFlags,                   -- DynFlags -> IO DynFlags
         defaultFatalMessager,
         defaultLogAction,
@@ -180,9 +182,7 @@ import Control.Monad
 import Control.Monad.Trans.Class
 import Control.Monad.Trans.Writer
 import Control.Monad.Trans.Reader
-#if MIN_VERSION_transformers(0,4,0)
 import Control.Monad.Trans.Except
-#endif
 import Control.Exception (throwIO)
 
 import Data.Bits
@@ -193,7 +193,6 @@ import Data.Map (Map)
 import qualified Data.Map as Map
 import Data.Set (Set)
 import qualified Data.Set as Set
-import Data.Monoid (Monoid)
 import Data.Word
 import System.FilePath
 import System.Directory
@@ -234,6 +233,59 @@ import qualified GHC.LanguageExtensions as LangExt
 -- have effect, and annotate it accordingly. For Flags use defFlag, defGhcFlag,
 -- defGhciFlag, and for FlagSpec use flagSpec or flagGhciSpec.
 
+-- Note [Adding a language extension]
+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+--
+-- There are a few steps to adding (or removing) a language extension,
+--
+--  * Adding the extension to GHC.LanguageExtensions
+--
+--    The Extension type in libraries/ghc-boot/GHC/LanguageExtensions.hs is
+--    the canonical list of language extensions known by GHC.
+--
+--  * Adding a flag to DynFlags.xFlags
+--
+--    This is fairly self-explanatory. The name should be concise, memorable,
+--    and consistent with any previous implementations of the similar idea in
+--    other Haskell compilers.
+--
+--  * Adding the flag to the documentation
+--
+--    This is the same as any other flag. See
+--    Note [Updating flag description in the User's Guide]
+--
+--  * Adding the flag to Cabal
+--
+--    The Cabal library has its own list of all language extensions supported
+--    by all major compilers. This is the list that user code being uploaded
+--    to Hackage is checked against to ensure language extension validity.
+--    Consequently, it is very important that this list remains up-to-date.
+--
+--    To this end, there is a testsuite test (testsuite/tests/driver/T4437.hs)
+--    whose job it is to ensure these GHC's extensions are consistent with
+--    Cabal.
+--
+--    The recommended workflow is,
+--
+--     1. Temporarily add your new language extension to the
+--        expectedGhcOnlyExtensions list in T4437 to ensure the test doesn't
+--        break while Cabal is updated.
+--
+--     2. After your GHC change is accepted, submit a Cabal pull request adding
+--        your new extension to Cabal's list (found in
+--        Cabal/Language/Haskell/Extension.hs).
+--
+--     3. After your Cabal change is accepted, let the GHC developers know so
+--        they can update the Cabal submodule and remove the extensions from
+--        expectedGhcOnlyExtensions.
+--
+--  * Adding the flag to the GHC Wiki
+--
+--    There is a change log tracking language extension additions and removals
+--    on the GHC wiki:  https://ghc.haskell.org/trac/ghc/wiki/LanguagePragmaHistory
+--
+--  See Trac #4437 and #8176.
+
 -- -----------------------------------------------------------------------------
 -- DynFlags
 
@@ -338,7 +390,7 @@ data GeneralFlag
    | Opt_PrintUnicodeSyntax
    | Opt_PrintExpandedSynonyms
    | Opt_PrintPotentialInstances
-   | Opt_PrintTypechekerElaboration
+   | Opt_PrintTypecheckerElaboration
 
    -- optimisation opts
    | Opt_CallArity
@@ -402,6 +454,7 @@ data GeneralFlag
    | Opt_SplitSections
    | Opt_StgStats
    | Opt_HideAllPackages
+   | Opt_HideAllPluginPackages
    | Opt_PrintBindResult
    | Opt_Haddock
    | Opt_HaddockOptions
@@ -478,6 +531,8 @@ data GeneralFlag
    | Opt_DistrustAllPackages
    | Opt_PackageTrust
 
+   -- pm checking with guards
+   | Opt_FullGuardReasoning
    deriving (Eq, Show, Enum)
 
 data WarningFlag =
@@ -499,6 +554,7 @@ data WarningFlag =
    | Opt_WarnMissingLocalSigs
    | Opt_WarnNameShadowing
    | Opt_WarnOverlappingPatterns
+   | Opt_WarnTooManyGuards
    | Opt_WarnTypeDefaults
    | Opt_WarnMonomorphism
    | Opt_WarnUnusedTopBinds
@@ -510,7 +566,7 @@ data WarningFlag =
    | Opt_WarnWarningsDeprecations
    | Opt_WarnDeprecatedFlags
    | Opt_WarnAMP -- Introduced in GHC 7.8, obsolete since 7.10
-   | Opt_WarnMissingMonadFailInstance -- since 8.0
+   | Opt_WarnMissingMonadFailInstances -- since 8.0
    | Opt_WarnSemigroup -- since 8.0
    | Opt_WarnDodgyExports
    | Opt_WarnDodgyImports
@@ -538,8 +594,10 @@ data WarningFlag =
    | Opt_WarnDerivingTypeable
    | Opt_WarnDeferredTypeErrors
    | Opt_WarnNonCanonicalMonadInstances   -- since 8.0
+   | Opt_WarnNonCanonicalMonadFailInstances -- since 8.0
    | Opt_WarnNonCanonicalMonoidInstances  -- since 8.0
    | Opt_WarnMissingPatSynSigs            -- since 8.0
+   | Opt_WarnUnrecognisedWarningFlags     -- since 8.0
    deriving (Eq, Show, Enum)
 
 data Language = Haskell98 | Haskell2010
@@ -690,8 +748,14 @@ data DynFlags = DynFlags {
         -- ^ The @-package-db@ flags given on the command line, in the order
         -- they appeared.
 
+  ignorePackageFlags    :: [IgnorePackageFlag],
+        -- ^ The @-ignore-package@ flags from the command line
   packageFlags          :: [PackageFlag],
         -- ^ The @-package@ and @-hide-package@ flags from the command-line
+  pluginPackageFlags    :: [PackageFlag],
+        -- ^ The @-plugin-package-id@ flags from command line
+  trustFlags            :: [TrustFlag],
+        -- ^ The @-trust@ and @-distrust@ flags
   packageEnv            :: Maybe FilePath,
         -- ^ Filepath to the package environment file (if overriding default)
 
@@ -838,14 +902,11 @@ instance (Monad m, HasDynFlags m) => HasDynFlags (ReaderT a m) where
 instance (Monad m, HasDynFlags m) => HasDynFlags (MaybeT m) where
     getDynFlags = lift getDynFlags
 
-#if MIN_VERSION_transformers(0,4,0)
 instance (Monad m, HasDynFlags m) => HasDynFlags (ExceptT e m) where
     getDynFlags = lift getDynFlags
-#endif
 
 class ContainsDynFlags t where
     extractDynFlags :: t -> DynFlags
-    replaceDynFlags :: t -> DynFlags -> t
 
 data ProfAuto
   = NoProfAuto         -- ^ no SCC annotations added
@@ -980,7 +1041,15 @@ opt_i dflags = sOpt_i (settings dflags)
 versionedAppDir :: DynFlags -> IO FilePath
 versionedAppDir dflags = do
   appdir <- getAppUserDataDirectory (programName dflags)
-  return $ appdir </> (TARGET_ARCH ++ '-':TARGET_OS ++ '-':projectVersion dflags)
+  return $ appdir </> versionedFilePath dflags
+
+-- | A filepath like @x86_64-linux-7.6.3@ with the platform string to use when
+-- constructing platform-version-dependent files that need to co-exist.
+--
+versionedFilePath :: DynFlags -> FilePath
+versionedFilePath dflags =     TARGET_ARCH
+                        ++ '-':TARGET_OS
+                        ++ '-':projectVersion dflags
   -- NB: This functionality is reimplemented in Cabal, so if you
   -- change it, be sure to update Cabal.
 
@@ -1038,9 +1107,9 @@ data GhcMode
   deriving Eq
 
 instance Outputable GhcMode where
-  ppr CompManager = ptext (sLit "CompManager")
-  ppr OneShot     = ptext (sLit "OneShot")
-  ppr MkDepend    = ptext (sLit "MkDepend")
+  ppr CompManager = text "CompManager"
+  ppr OneShot     = text "OneShot"
+  ppr MkDepend    = text "MkDepend"
 
 isOneShot :: GhcMode -> Bool
 isOneShot OneShot = True
@@ -1065,8 +1134,7 @@ isNoLink _      = False
 -- is used.
 data PackageArg =
       PackageArg String    -- ^ @-package@, by 'PackageName'
-    | PackageIdArg String  -- ^ @-package-id@, by 'SourcePackageId'
-    | UnitIdArg String -- ^ @-package-key@, by 'ComponentId'
+    | UnitIdArg String     -- ^ @-package-id@, by 'UnitId'
   deriving (Eq, Show)
 
 -- | Represents the renaming that may be associated with an exposed
@@ -1086,15 +1154,23 @@ data ModRenaming = ModRenaming {
                                                --   under name @n@.
   } deriving (Eq)
 
--- | Flags for manipulating packages.
+-- | Flags for manipulating the set of non-broken packages.
+newtype IgnorePackageFlag = IgnorePackage String -- ^ @-ignore-package@
+  deriving (Eq)
+
+-- | Flags for manipulating package trust.
+data TrustFlag
+  = TrustPackage    String -- ^ @-trust@
+  | DistrustPackage String -- ^ @-distrust@
+  deriving (Eq)
+
+-- | Flags for manipulating packages visibility.
 data PackageFlag
-  = ExposePackage   PackageArg ModRenaming -- ^ @-package@, @-package-id@
-                                           -- and @-package-key@
+  = ExposePackage   String PackageArg ModRenaming -- ^ @-package@, @-package-id@
   | HidePackage     String -- ^ @-hide-package@
-  | IgnorePackage   String -- ^ @-ignore-package@
-  | TrustPackage    String -- ^ @-trust-package@
-  | DistrustPackage String -- ^ @-distrust-package@
   deriving (Eq)
+-- NB: equality instance is used by InteractiveUI to test if
+-- package flags have changed.
 
 defaultHscTarget :: Platform -> HscTarget
 defaultHscTarget = defaultObjectTarget
@@ -1423,6 +1499,9 @@ defaultDynFlags mySettings =
 
         extraPkgConfs           = id,
         packageFlags            = [],
+        pluginPackageFlags      = [],
+        ignorePackageFlags      = [],
+        trustFlags              = [],
         packageEnv              = Nothing,
         pkgDatabase             = Nothing,
         -- This gets filled in with GHC.setSessionDynFlags
@@ -1522,6 +1601,16 @@ interpWays
   | rtsIsProfiled = [WayProf]
   | otherwise = []
 
+interpreterProfiled :: DynFlags -> Bool
+interpreterProfiled dflags
+  | gopt Opt_ExternalInterpreter dflags = gopt Opt_SccProfilingOn dflags
+  | otherwise = rtsIsProfiled
+
+interpreterDynamic :: DynFlags -> Bool
+interpreterDynamic dflags
+  | gopt Opt_ExternalInterpreter dflags = WayDyn `elem` ways dflags
+  | otherwise = dynamicGhc
+
 --------------------------------------------------------------------------
 
 type FatalMessager = String -> IO ()
@@ -2325,6 +2414,7 @@ dynamic_flags = [
   , defGhcFlag "no-rtsopts"     (NoArg (setRtsOptsEnabled RtsOptsNone))
   , defGhcFlag "no-rtsopts-suggestions"
       (noArg (\d -> d {rtsOptsSuggestions = False} ))
+
   , defGhcFlag "main-is"        (SepArg setMainIs)
   , defGhcFlag "haddock"        (NoArg (setGeneralFlag Opt_Haddock))
   , defGhcFlag "haddock-opts"   (hasArg addHaddockOpts)
@@ -2357,7 +2447,7 @@ dynamic_flags = [
   , defFlag "dppr-cols"        (intSuffix (\n d -> d{ pprCols = n }))
   , defGhcFlag "dtrace-level"  (intSuffix (\n d -> d{ traceLevel = n }))
   -- Suppress all that is suppressable in core dumps.
-  -- Except for uniques, as some simplifier phases introduce new varibles that
+  -- Except for uniques, as some simplifier phases introduce new variables that
   -- have otherwise identical names.
   , defGhcFlag "dsuppress-all"
       (NoArg $ do setGeneralFlag Opt_SuppressCoercions
@@ -2655,7 +2745,8 @@ dynamic_flags = [
  ++ map (mkFlag turnOff "XNo"       unSetExtensionFlag) xFlags
  ++ map (mkFlag turnOn  "X"         setLanguage       ) languageFlags
  ++ map (mkFlag turnOn  "X"         setSafeHaskell    ) safeHaskellFlags
- ++ [ defFlag "XGenerics"
+ ++ [ unrecognisedWarning
+    , defFlag "XGenerics"
         (NoArg (deprecate $
                   "it does nothing; look into -XDefaultSignatures " ++
                   "and -XDeriveGeneric for generic programming support."))
@@ -2664,6 +2755,16 @@ dynamic_flags = [
                   "it does nothing; look into -XDefaultSignatures and " ++
                   "-XDeriveGeneric for generic programming support.")) ]
 
+-- | This is where we handle unrecognised warning flags. We only issue a warning
+-- if -Wunrecognised-warning-flags is set. See Trac #11429 for context.
+unrecognisedWarning :: Flag (CmdLineP DynFlags)
+unrecognisedWarning = defFlag "W" (Prefix action)
+  where
+    action :: String -> EwM (CmdLineP DynFlags) ()
+    action flag = do
+      f <- wopt Opt_WarnUnrecognisedWarningFlags <$> liftEwM getCmdLineState
+      when f $ addWarn $ "unrecognised warning flag: -W"++flag
+
 -- See Note [Supporting CLI completion]
 package_flags :: [Flag (CmdLineP DynFlags)]
 package_flags = [
@@ -2683,15 +2784,24 @@ package_flags = [
       (NoArg $ do removeUserPkgConf
                   deprecate "Use -no-user-package-db instead")
 
-  , defGhcFlag "package-name"      (HasArg $ \name -> do
+  , defGhcFlag "package-name"       (HasArg $ \name -> do
+                                      upd (setUnitId name))
+                                      -- TODO: Since we JUST deprecated
+                                      -- -this-package-key, let's keep this
+                                      -- undeprecated for another cycle.
+                                      -- Deprecate this eventually.
+                                      -- deprecate "Use -this-unit-id instead")
+  , defGhcFlag "this-package-key"   (HasArg $ \name -> do
                                       upd (setUnitId name)
-                                      deprecate "Use -this-package-key instead")
-  , defGhcFlag "this-package-key"   (hasArg setUnitId)
-  , defFlag "package-id"            (HasArg exposePackageId)
+                                      deprecate "Use -this-unit-id instead")
+  , defGhcFlag "this-unit-id"       (hasArg setUnitId)
   , defFlag "package"               (HasArg exposePackage)
-  , defFlag "package-key"           (HasArg exposeUnitId)
+  , defFlag "plugin-package-id"     (HasArg exposePluginPackageId)
+  , defFlag "plugin-package"        (HasArg exposePluginPackage)
+  , defFlag "package-id"            (HasArg exposePackageId)
   , defFlag "hide-package"          (HasArg hidePackage)
   , defFlag "hide-all-packages"     (NoArg (setGeneralFlag Opt_HideAllPackages))
+  , defFlag "hide-all-plugin-packages" (NoArg (setGeneralFlag Opt_HideAllPluginPackages))
   , defFlag "package-env"           (HasArg setPackageEnv)
   , defFlag "ignore-package"        (HasArg ignorePackage)
   , defFlag "syslib"
@@ -2828,7 +2938,7 @@ wWarningFlags = [
   flagSpec "missing-import-lists"        Opt_WarnMissingImportList,
   flagSpec "missing-local-sigs"          Opt_WarnMissingLocalSigs,
   flagSpec "missing-methods"             Opt_WarnMissingMethods,
-  flagSpec "missing-monadfail-instance"  Opt_WarnMissingMonadFailInstance,
+  flagSpec "missing-monadfail-instances" Opt_WarnMissingMonadFailInstances,
   flagSpec "semigroup"                   Opt_WarnSemigroup,
   flagSpec "missing-signatures"          Opt_WarnMissingSigs,
   flagSpec "missing-exported-sigs"       Opt_WarnMissingExportedSigs,
@@ -2836,11 +2946,14 @@ wWarningFlags = [
   flagSpec "name-shadowing"              Opt_WarnNameShadowing,
   flagSpec "noncanonical-monad-instances"
                                          Opt_WarnNonCanonicalMonadInstances,
+  flagSpec "noncanonical-monadfail-instances"
+                                         Opt_WarnNonCanonicalMonadFailInstances,
   flagSpec "noncanonical-monoid-instances"
                                          Opt_WarnNonCanonicalMonoidInstances,
   flagSpec "orphans"                     Opt_WarnOrphans,
   flagSpec "overflowed-literals"         Opt_WarnOverflowedLiterals,
   flagSpec "overlapping-patterns"        Opt_WarnOverlappingPatterns,
+  flagSpec "too-many-guards"             Opt_WarnTooManyGuards,
   flagSpec "missed-specialisations"      Opt_WarnMissedSpecs,
   flagSpec "all-missed-specialisations"  Opt_WarnAllMissedSpecs,
   flagSpec' "safe"                       Opt_WarnSafe setWarnSafe,
@@ -2864,7 +2977,8 @@ wWarningFlags = [
   flagSpec "unused-top-binds"            Opt_WarnUnusedTopBinds,
   flagSpec "warnings-deprecations"       Opt_WarnWarningsDeprecations,
   flagSpec "wrong-do-bind"               Opt_WarnWrongDoBind,
-  flagSpec "missing-pat-syn-sigs"        Opt_WarnMissingPatSynSigs]
+  flagSpec "missing-pat-syn-sigs"        Opt_WarnMissingPatSynSigs,
+  flagSpec "unrecognised-warning-flags"  Opt_WarnUnrecognisedWarningFlags ]
 
 -- | These @-\<blah\>@ flags can all be reversed with @-no-\<blah\>@
 negatableFlags :: [FlagSpec GeneralFlag]
@@ -2952,7 +3066,7 @@ fFlags = [
   flagSpec "print-unicode-syntax"             Opt_PrintUnicodeSyntax,
   flagSpec "print-expanded-synonyms"          Opt_PrintExpandedSynonyms,
   flagSpec "print-potential-instances"        Opt_PrintPotentialInstances,
-  flagSpec "print-typechecker-elaboration"    Opt_PrintTypechekerElaboration,
+  flagSpec "print-typechecker-elaboration"    Opt_PrintTypecheckerElaboration,
   flagSpec "prof-cafs"                        Opt_AutoSccsOnIndividualCafs,
   flagSpec "prof-count-entries"               Opt_ProfCountEntries,
   flagSpec "regs-graph"                       Opt_RegsGraph,
@@ -2973,7 +3087,8 @@ fFlags = [
   flagSpec "unbox-strict-fields"              Opt_UnboxStrictFields,
   flagSpec "vectorisation-avoidance"          Opt_VectorisationAvoidance,
   flagSpec "vectorise"                        Opt_Vectorise,
-  flagSpec "worker-wrapper"                   Opt_WorkerWrapper
+  flagSpec "worker-wrapper"                   Opt_WorkerWrapper,
+  flagSpec "full-guard-reasoning"             Opt_FullGuardReasoning
   ]
 
 -- | These @-f\<blah\>@ flags can all be reversed with @-fno-\<blah\>@
@@ -3060,6 +3175,7 @@ xFlags :: [FlagSpec LangExt.Extension]
 xFlags = [
 -- See Note [Updating flag description in the User's Guide]
 -- See Note [Supporting CLI completion]
+-- See Note [Adding a language extension]
 -- Please keep the list of flags below sorted alphabetically
   flagSpec "AllowAmbiguousTypes"              LangExt.AllowAmbiguousTypes,
   flagSpec "AlternativeLayoutRule"            LangExt.AlternativeLayoutRule,
@@ -3111,6 +3227,7 @@ xFlags = [
   flagSpec "ImpredicativeTypes"               LangExt.ImpredicativeTypes,
   flagSpec' "IncoherentInstances"             LangExt.IncoherentInstances
                                               setIncoherentInsts,
+  flagSpec "TypeFamilyDependencies"           LangExt.TypeFamilyDependencies,
   flagSpec "InstanceSigs"                     LangExt.InstanceSigs,
   flagSpec "ApplicativeDo"                    LangExt.ApplicativeDo,
   flagSpec "InterruptibleFFI"                 LangExt.InterruptibleFFI,
@@ -3176,6 +3293,7 @@ xFlags = [
   flagSpec "TraditionalRecordSyntax"          LangExt.TraditionalRecordSyntax,
   flagSpec "TransformListComp"                LangExt.TransformListComp,
   flagSpec "TupleSections"                    LangExt.TupleSections,
+  flagSpec "TypeApplications"                 LangExt.TypeApplications,
   flagSpec "TypeInType"                       LangExt.TypeInType,
   flagSpec "TypeFamilies"                     LangExt.TypeFamilies,
   flagSpec "TypeOperators"                    LangExt.TypeOperators,
@@ -3249,6 +3367,7 @@ impliedXFlags
     , (LangExt.FlexibleInstances,         turnOn, LangExt.TypeSynonymInstances)
     , (LangExt.FunctionalDependencies,    turnOn, LangExt.MultiParamTypeClasses)
     , (LangExt.MultiParamTypeClasses,     turnOn, LangExt.ConstrainedClassMethods)  -- c.f. Trac #7854
+    , (LangExt.TypeFamilyDependencies,    turnOn, LangExt.TypeFamilies)
 
     , (LangExt.RebindableSyntax, turnOff, LangExt.ImplicitPrelude)      -- NB: turn off!
 
@@ -3290,6 +3409,7 @@ impliedXFlags
 
     , (LangExt.TemplateHaskell, turnOn, LangExt.TemplateHaskellQuotes)
     , (LangExt.Strict, turnOn, LangExt.StrictData)
+    , (LangExt.TypeApplications, turnOn, LangExt.AllowAmbiguousTypes)
   ]
 
 -- Note [Documenting optimisation flags]
@@ -3357,7 +3477,7 @@ optLevelFlags -- see Note [Documenting optimisation flags]
 -- please remember to update the User's Guide. The relevant file is:
 --
 --  * utils/mkUserGuidePart/
---  * docs/users_guide/using.rst
+--  * docs/users_guide/using-warnings.rst
 
 -- | Warnings enabled unless specified otherwise
 standardWarnings :: [WarningFlag]
@@ -3369,7 +3489,6 @@ standardWarnings -- see Note [Documenting warning flags]
         Opt_WarnTypedHoles,
         Opt_WarnPartialTypeSignatures,
         Opt_WarnUnrecognisedPragmas,
-        Opt_WarnRedundantConstraints,
         Opt_WarnDuplicateExports,
         Opt_WarnOverflowedLiterals,
         Opt_WarnEmptyEnumerations,
@@ -3381,7 +3500,8 @@ standardWarnings -- see Note [Documenting warning flags]
         Opt_WarnInlineRuleShadowing,
         Opt_WarnAlternativeLayoutRuleTransitional,
         Opt_WarnUnsupportedLlvmVersion,
-        Opt_WarnTabs
+        Opt_WarnTabs,
+        Opt_WarnUnrecognisedWarningFlags
       ]
 
 -- | Things you get with -W
@@ -3420,7 +3540,7 @@ minusWallOpts
 -- code future compatible to fix issues before they even generate warnings.
 minusWcompatOpts :: [WarningFlag]
 minusWcompatOpts
-    = [ Opt_WarnMissingMonadFailInstance
+    = [ Opt_WarnMissingMonadFailInstances
       , Opt_WarnSemigroup
       , Opt_WarnNonCanonicalMonoidInstances
       ]
@@ -3730,18 +3850,22 @@ parseModuleName :: ReadP ModuleName
 parseModuleName = fmap mkModuleName
                 $ munch1 (\c -> isAlphaNum c || c `elem` "_.")
 
-parsePackageFlag :: (String -> PackageArg) -- type of argument
+parsePackageFlag :: String                 -- the flag
+                 -> (String -> PackageArg) -- type of argument
                  -> String                 -- string to parse
                  -> PackageFlag
-parsePackageFlag constr str = case filter ((=="").snd) (readP_to_S parse str) of
+parsePackageFlag flag constr str
+ = case filter ((=="").snd) (readP_to_S parse str) of
     [(r, "")] -> r
     _ -> throwGhcException $ CmdLineError ("Can't parse package flag: " ++ str)
-  where parse = do
+  where doc = flag ++ " " ++ str
+        parse = do
             pkg <- tok $ munch1 (\c -> isAlphaNum c || c `elem` ":-_.")
+            let mk_expose = ExposePackage doc (constr pkg)
             ( do _ <- tok $ string "with"
-                 fmap (ExposePackage (constr pkg) . ModRenaming True) parseRns
-             <++ fmap (ExposePackage (constr pkg) . ModRenaming False) parseRns
-             <++ return (ExposePackage (constr pkg) (ModRenaming True [])))
+                 fmap (mk_expose . ModRenaming True) parseRns
+             <++ fmap (mk_expose . ModRenaming False) parseRns
+             <++ return (mk_expose (ModRenaming True [])))
         parseRns = do _ <- tok $ R.char '('
                       rns <- tok $ sepBy parseItem (tok $ R.char ',')
                       _ <- tok $ R.char ')'
@@ -3755,28 +3879,34 @@ parsePackageFlag constr str = case filter ((=="").snd) (readP_to_S parse str) of
              return (orig, orig))
         tok m = m >>= \x -> skipSpaces >> return x
 
-exposePackage, exposePackageId, exposeUnitId, hidePackage, ignorePackage,
+exposePackage, exposePackageId, hidePackage,
+        exposePluginPackage, exposePluginPackageId,
+        ignorePackage,
         trustPackage, distrustPackage :: String -> DynP ()
 exposePackage p = upd (exposePackage' p)
 exposePackageId p =
   upd (\s -> s{ packageFlags =
-    parsePackageFlag PackageIdArg p : packageFlags s })
-exposeUnitId p =
-  upd (\s -> s{ packageFlags =
-    parsePackageFlag UnitIdArg p : packageFlags s })
+    parsePackageFlag "-package-id" UnitIdArg p : packageFlags s })
+exposePluginPackage p =
+  upd (\s -> s{ pluginPackageFlags =
+    parsePackageFlag "-plugin-package" PackageArg p : pluginPackageFlags s })
+exposePluginPackageId p =
+  upd (\s -> s{ pluginPackageFlags =
+    parsePackageFlag "-plugin-package-id" UnitIdArg p : pluginPackageFlags s })
 hidePackage p =
   upd (\s -> s{ packageFlags = HidePackage p : packageFlags s })
 ignorePackage p =
-  upd (\s -> s{ packageFlags = IgnorePackage p : packageFlags s })
+  upd (\s -> s{ ignorePackageFlags = IgnorePackage p : ignorePackageFlags s })
+
 trustPackage p = exposePackage p >> -- both trust and distrust also expose a package
-  upd (\s -> s{ packageFlags = TrustPackage p : packageFlags s })
+  upd (\s -> s{ trustFlags = TrustPackage p : trustFlags s })
 distrustPackage p = exposePackage p >>
-  upd (\s -> s{ packageFlags = DistrustPackage p : packageFlags s })
+  upd (\s -> s{ trustFlags = DistrustPackage p : trustFlags s })
 
 exposePackage' :: String -> DynFlags -> DynFlags
 exposePackage' p dflags
     = dflags { packageFlags =
-            parsePackageFlag PackageArg p : packageFlags dflags }
+            parsePackageFlag "-package" PackageArg p : packageFlags dflags }
 
 setUnitId :: String -> DynFlags -> DynFlags
 setUnitId p s =  s{ thisPackage = stringToUnitId p }
@@ -3785,46 +3915,58 @@ setUnitId p s =  s{ thisPackage = stringToUnitId p }
 -- | Find the package environment (if one exists)
 --
 -- We interpret the package environment as a set of package flags; to be
--- specific, if we find a package environment
+-- specific, if we find a package environment file like
 --
--- > id1
--- > id2
--- > ..
--- > idn
+-- > clear-package-db
+-- > global-package-db
+-- > package-db blah/package.conf.d
+-- > package-id id1
+-- > package-id id2
 --
 -- we interpret this as
 --
 -- > [ -hide-all-packages
+-- > , -clear-package-db
+-- > , -global-package-db
+-- > , -package-db blah/package.conf.d
 -- > , -package-id id1
 -- > , -package-id id2
--- > , ..
--- > , -package-id idn
 -- > ]
+--
+-- There's also an older syntax alias for package-id, which is just an
+-- unadorned package id
+--
+-- > id1
+-- > id2
+--
 interpretPackageEnv :: DynFlags -> IO DynFlags
 interpretPackageEnv dflags = do
     mPkgEnv <- runMaybeT $ msum $ [
                    getCmdLineArg >>= \env -> msum [
-                       loadEnvFile  env
-                     , loadEnvName  env
+                       probeEnvFile env
+                     , probeEnvName env
                      , cmdLineError env
                      ]
                  , getEnvVar >>= \env -> msum [
-                       loadEnvFile env
-                     , loadEnvName env
-                     , envError    env
+                       probeEnvFile env
+                     , probeEnvName env
+                     , envError     env
+                     ]
+                 , notIfHideAllPackages >> msum [
+                       findLocalEnvFile >>= probeEnvFile
+                     , probeEnvName defaultEnvName
                      ]
-                 , loadEnvFile localEnvFile
-                 , loadEnvName defaultEnvName
                  ]
     case mPkgEnv of
       Nothing ->
         -- No environment found. Leave DynFlags unchanged.
         return dflags
-      Just ids -> do
+      Just envfile -> do
+        content <- readFile envfile
         let setFlags :: DynP ()
             setFlags = do
               setGeneralFlag Opt_HideAllPackages
-              mapM_ exposePackageId (lines ids)
+              parseEnvFile envfile content
 
             (_, dflags') = runCmdLine (runEwM setFlags) dflags
 
@@ -3837,13 +3979,31 @@ interpretPackageEnv dflags = do
      appdir <- liftMaybeT $ versionedAppDir dflags
      return $ appdir </> "environments" </> name
 
-    loadEnvName :: String -> MaybeT IO String
-    loadEnvName name = loadEnvFile =<< namedEnvPath name
+    probeEnvName :: String -> MaybeT IO FilePath
+    probeEnvName name = probeEnvFile =<< namedEnvPath name
 
-    loadEnvFile :: String -> MaybeT IO String
-    loadEnvFile path = do
+    probeEnvFile :: FilePath -> MaybeT IO FilePath
+    probeEnvFile path = do
       guard =<< liftMaybeT (doesFileExist path)
-      liftMaybeT $ readFile path
+      return path
+
+    parseEnvFile :: FilePath -> String -> DynP ()
+    parseEnvFile envfile = mapM_ parseEntry . lines
+      where
+        parseEntry str = case words str of
+          ["package-db", db]    -> addPkgConfRef (PkgConfFile (envdir </> db))
+            -- relative package dbs are interpreted relative to the env file
+            where envdir = takeDirectory envfile
+          ["clear-package-db"]  -> clearPkgConf
+          ["global-package-db"] -> addPkgConfRef GlobalPkgConf
+          ["user-package-db"]   -> addPkgConfRef UserPkgConf
+          ["package-id", pkgid] -> exposePackageId pkgid
+          -- and the original syntax introduced in 7.10:
+          [pkgid]               -> exposePackageId pkgid
+          []                    -> return ()
+          _                     -> throwGhcException $ CmdLineError $
+                                        "Can't parse environment file entry: "
+                                     ++ envfile ++ ": " ++ str
 
     -- Various ways to define which environment to use
 
@@ -3858,11 +4018,34 @@ interpretPackageEnv dflags = do
         Left err  -> if isDoesNotExistError err then mzero
                                                 else liftMaybeT $ throwIO err
 
+    notIfHideAllPackages :: MaybeT IO ()
+    notIfHideAllPackages =
+      guard (not (gopt Opt_HideAllPackages dflags))
+
     defaultEnvName :: String
     defaultEnvName = "default"
 
-    localEnvFile :: FilePath
-    localEnvFile = "./.ghc.environment"
+    -- e.g. .ghc.environment.x86_64-linux-7.6.3
+    localEnvFileName :: FilePath
+    localEnvFileName = ".ghc.environment" <.> versionedFilePath dflags
+
+    -- Search for an env file, starting in the current dir and looking upwards.
+    -- Fail if we get to the users home dir or the filesystem root. That is,
+    -- we don't look for an env file in the user's home dir. The user-wide
+    -- env lives in ghc's versionedAppDir/environments/default
+    findLocalEnvFile :: MaybeT IO FilePath
+    findLocalEnvFile = do
+        curdir  <- liftMaybeT getCurrentDirectory
+        homedir <- liftMaybeT getHomeDirectory
+        let probe dir | isDrive dir || dir == homedir
+                      = mzero
+            probe dir = do
+              let file = dir </> localEnvFileName
+              exists <- liftMaybeT (doesFileExist file)
+              if exists
+                then return file
+                else probe (takeDirectory dir)
+        probe curdir
 
     -- Error reporting
 
@@ -4118,18 +4301,34 @@ compilerInfo dflags
        ("Tables next to code",         cGhcEnableTablesNextToCode),
        ("RTS ways",                    cGhcRTSWays),
        ("RTS expects libdw",           showBool cGhcRtsWithLibdw),
+       -- Whether or not we support @-dynamic-too@
        ("Support dynamic-too",         showBool $ not isWindows),
+       -- Whether or not we support the @-j@ flag with @--make@.
        ("Support parallel --make",     "YES"),
+       -- Whether or not we support "Foo from foo-0.1-XXX:Foo" syntax in
+       -- installed package info.
        ("Support reexported-modules",  "YES"),
+       -- Whether or not we support extended @-package foo (Foo)@ syntax.
        ("Support thinning and renaming package flags", "YES"),
+       -- If true, we require that the 'id' field in installed package info
+       -- match what is passed to the @-this-unit-id@ flag for modules
+       -- built in it
        ("Requires unified installed package IDs", "YES"),
+       -- Whether or not we support the @-this-package-key@ flag.  Prefer
+       -- "Uses unit IDs" over it.
        ("Uses package keys",           "YES"),
+       -- Whether or not we support the @-this-unit-id@ flag
+       ("Uses unit IDs",               "YES"),
+       -- Whether or not GHC compiles libraries as dynamic by default
        ("Dynamic by default",          showBool $ dYNAMIC_BY_DEFAULT dflags),
+       -- Whether or not GHC was compiled using -dynamic
        ("GHC Dynamic",                 showBool dynamicGhc),
+       -- Whether or not GHC was compiled using -prof
        ("GHC Profiled",                showBool rtsIsProfiled),
        ("Leading underscore",          cLeadingUnderscore),
        ("Debug on",                    show debugIsOn),
        ("LibDir",                      topDir dflags),
+       -- The path of the global package database used by GHC
        ("Global Package DB",           systemPackageConfig dflags)
       ]
   where