Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleans up the -Werror check, adds GHC 8.6.1 support and also filters RTS flags, fixing #5575 #5589

Merged
merged 2 commits into from
Nov 8, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 107 additions & 32 deletions Cabal/Distribution/Simple/Program/GHC.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Distribution.Simple.Program.GHC (
GhcOptions(..),
Expand Down Expand Up @@ -42,58 +43,73 @@ import Language.Haskell.Extension

import Data.List (stripPrefix)
import qualified Data.Map as Map
import Data.Monoid (All(..), Any(..), Endo(..), First(..))
import Data.Monoid (All(..), Any(..), Endo(..), First(..), Last(..))
import Data.Set (Set)
import qualified Data.Set as Set

normaliseGhcArgs :: Maybe Version -> PackageDescription -> [String] -> [String]
normaliseGhcArgs (Just ghcVersion) PackageDescription{..} ghcArgs
| ghcVersion `withinRange` supportedGHCVersions
= argumentFilters $ filter simpleFilters ghcArgs
= argumentFilters . filter simpleFilters . filterRtsOpts $ ghcArgs
where
supportedGHCVersions :: VersionRange
supportedGHCVersions = intersectVersionRanges
(orLaterVersion (mkVersion [8,0]))
(earlierVersion (mkVersion [8,5]))
(earlierVersion (mkVersion [8,7]))

from :: Monoid m => [Int] -> m -> m
from version flags
| ghcVersion `withinRange` orLaterVersion (mkVersion version) = flags
| otherwise = mempty

checkComponentWarnings :: (a -> BuildInfo) -> [a] -> All
checkComponentWarnings getInfo = foldMap $ checkComponent . getInfo
where
checkComponent :: BuildInfo -> All
checkComponent =
foldMap checkWarnings . filterGhcOptions . allBuildInfoOptions
to :: Monoid m => [Int] -> m -> m
to version flags
| ghcVersion `withinRange` earlierVersion (mkVersion version) = flags
| otherwise = mempty

allBuildInfoOptions :: BuildInfo -> [(CompilerFlavor, [String])]
allBuildInfoOptions =
mconcat [options, profOptions, sharedOptions, staticOptions]
checkGhcFlags :: forall m . Monoid m => ([String] -> m) -> m
checkGhcFlags fun = mconcat
[ fun ghcArgs
, checkComponentFlags libBuildInfo pkgLibs
, checkComponentFlags buildInfo executables
, checkComponentFlags testBuildInfo testSuites
, checkComponentFlags benchmarkBuildInfo benchmarks
]
where
pkgLibs = maybeToList library ++ subLibraries

filterGhcOptions :: [(CompilerFlavor, [String])] -> [[String]]
filterGhcOptions l = [opts | (GHC, opts) <- l]
checkComponentFlags :: (a -> BuildInfo) -> [a] -> m
checkComponentFlags getInfo = foldMap (checkComponent . getInfo)
where
checkComponent :: BuildInfo -> m
checkComponent = foldMap fun . filterGhcOptions . allGhcOptions

libs, exes, tests, benches :: All
libs = checkComponentWarnings libBuildInfo $
maybeToList library ++ subLibraries
allGhcOptions :: BuildInfo -> [(CompilerFlavor, [String])]
allGhcOptions =
mconcat [options, profOptions, sharedOptions, staticOptions]

exes = checkComponentWarnings buildInfo $ executables
tests = checkComponentWarnings testBuildInfo $ testSuites
benches = checkComponentWarnings benchmarkBuildInfo $ benchmarks
filterGhcOptions :: [(CompilerFlavor, [String])] -> [[String]]
filterGhcOptions l = [opts | (GHC, opts) <- l]

safeToFilterWarnings :: Bool
safeToFilterWarnings = getAll $ mconcat
[checkWarnings ghcArgs, libs, exes, tests, benches]

checkWarnings :: [String] -> All
checkWarnings = All . Set.null . foldr alter Set.empty
safeToFilterWarnings = getAll $ checkGhcFlags checkWarnings
where
checkWarnings :: [String] -> All
checkWarnings = All . Set.null . foldr alter Set.empty

alter :: String -> Set String -> Set String
alter flag = appEndo $ mconcat
[ \s -> Endo $ if s == "-Werror" then Set.insert s else id
, \s -> Endo $ if s == "-Wwarn" then const Set.empty else id
, \s -> from [8,6] . Endo $
if s == "-Werror=compat"
then Set.union compatWarningSet else id
, \s -> from [8,6] . Endo $
if s == "-Wno-error=compat"
then (`Set.difference` compatWarningSet) else id
, \s -> from [8,6] . Endo $
if s == "-Wwarn=compat"
then (`Set.difference` compatWarningSet) else id
, from [8,4] $ markFlag "-Werror=" Set.insert
, from [8,4] $ markFlag "-Wwarn=" Set.delete
, from [8,4] $ markFlag "-Wno-error=" Set.delete
Expand All @@ -105,7 +121,7 @@ normaliseGhcArgs (Just ghcVersion) PackageDescription{..} ghcArgs
-> String
-> Endo (Set String)
markFlag name update flag = Endo $ case stripPrefix name flag of
Just rest | not (null rest) -> update rest
Just rest | not (null rest) && rest /= "compat" -> update rest
_ -> id

flagArgumentFilter :: [String] -> [String] -> [String]
Expand All @@ -128,7 +144,20 @@ normaliseGhcArgs (Just ghcVersion) PackageDescription{..} ghcArgs
Nothing -> arg : go args

argumentFilters :: [String] -> [String]
argumentFilters = flagArgumentFilter ["-ghci-script", "-H"]
argumentFilters = flagArgumentFilter
["-ghci-script", "-H", "-interactive-print"]

filterRtsOpts :: [String] -> [String]
filterRtsOpts = go False
where
go :: Bool -> [String] -> [String]
go _ [] = []
go _ ("+RTS":opts) = go True opts
go _ ("-RTS":opts) = go False opts
go isRTSopts (opt:opts) = addOpt $ go isRTSopts opts
where
addOpt | isRTSopts = id
| otherwise = (opt:)

simpleFilters :: String -> Bool
simpleFilters = not . getAny . mconcat
Expand All @@ -138,20 +167,28 @@ normaliseGhcArgs (Just ghcVersion) PackageDescription{..} ghcArgs
, Any . isPrefixOf "-dno-suppress-"
, flagIn $ invertibleFlagSet "-" ["ignore-dot-ghci"]
, flagIn . invertibleFlagSet "-f" . mconcat $
[ [ "reverse-errors", "warn-unused-binds" ]
[ [ "reverse-errors", "warn-unused-binds", "break-on-error"
, "break-on-exception", "print-bind-result"
, "print-bind-contents", "print-evld-with-show"
, "implicit-import-qualified" ]
, from [8,2]
[ "diagnostics-show-caret", "local-ghci-history"
, "show-warning-groups", "hide-source-paths"
, "show-hole-constraints"
]
, from [8,4] ["show-loaded-modules"]
, from [8,6] [ "ghci-leak-check", "no-it" ]
]
, flagIn . invertibleFlagSet "-d" $ [ "ppr-case-as-let", "ppr-ticks" ]
, isOptIntFlag
, isIntFlag
, if safeToFilterWarnings
then isWarning <> (Any . ("-w"==))
else mempty
, from [8,6] $
if safeToFilterHoles
then isTypedHoleFlag
else mempty
]

flagIn :: Set String -> String -> Any
Expand All @@ -168,7 +205,7 @@ normaliseGhcArgs (Just ghcVersion) PackageDescription{..} ghcArgs
, "-dverbose-stg2stg", "-dcore-lint", "-dstg-lint", "-dcmm-lint"
, "-dasm-lint", "-dannot-lint", "-dshow-passes", "-dfaststring-stats"
, "-fno-max-relevant-binds", "-recomp", "-no-recomp", "-fforce-recomp"
, "-fno-force-recomp", "-interactive-print"
, "-fno-force-recomp"
]

, from [8,2]
Expand All @@ -177,8 +214,9 @@ normaliseGhcArgs (Just ghcVersion) PackageDescription{..} ghcArgs
, "-dppr-debug", "-dno-debug-output"
]

, from [8,4]
[ "-ddebug-output", "-fno-max-valid-substitutions" ]
, from [8,4] [ "-ddebug-output" ]
, from [8,4] $ to [8,6] [ "-fno-max-valid-substitutions" ]
, from [8,6] [ "-dhex-word-literals" ]
]

isOptIntFlag :: String -> Any
Expand All @@ -189,7 +227,7 @@ normaliseGhcArgs (Just ghcVersion) PackageDescription{..} ghcArgs
[ [ "-fmax-relevant-binds", "-ddpr-user-length", "-ddpr-cols"
, "-dtrace-level", "-fghci-hist-size" ]
, from [8,2] ["-fmax-uncovered-patterns", "-fmax-errors"]
, from [8,4] ["-fmax-valid-substitutions"]
, from [8,4] $ to [8,6] ["-fmax-valid-substitutions"]
]

dropIntFlag :: Bool -> String -> String -> Any
Expand All @@ -216,6 +254,43 @@ normaliseGhcArgs (Just ghcVersion) PackageDescription{..} ghcArgs
invertibleFlagSet prefix flagNames =
Set.fromList $ (++) <$> [prefix, prefix ++ "no-"] <*> flagNames

compatWarningSet :: Set String
compatWarningSet = Set.fromList $ mconcat
[ from [8,6]
[ "missing-monadfail-instances", "semigroup"
, "noncanonical-monoid-instances", "implicit-kind-vars" ]
]

safeToFilterHoles :: Bool
safeToFilterHoles = getAll . checkGhcFlags $ fromLast . foldMap notDeferred
where
fromLast :: Last All -> All
fromLast = fromMaybe (All True) . getLast

notDeferred :: String -> Last All
notDeferred "-fdefer-typed-holes" = Last . Just . All $ False
notDeferred "-fno-defer-typed-holes" = Last . Just . All $ True
notDeferred _ = Last Nothing

isTypedHoleFlag :: String -> Any
isTypedHoleFlag = mconcat
[ flagIn . invertibleFlagSet "-f" $
[ "show-hole-constraints", "show-valid-substitutions"
, "show-valid-hole-fits", "sort-valid-hole-fits"
, "sort-by-size-hole-fits", "sort-by-subsumption-hole-fits"
, "abstract-refinement-hole-fits", "show-provenance-of-hole-fits"
, "show-hole-matches-of-hole-fits", "show-type-of-hole-fits"
, "show-type-app-of-hole-fits", "show-type-app-vars-of-hole-fits"
, "unclutter-valid-hole-fits"
]
, flagIn . Set.fromList $
[ "-fno-max-valid-hole-fits", "-fno-max-refinement-hole-fits"
, "-fno-refinement-level-hole-fits" ]
, mconcat . map (dropIntFlag False) $
[ "-fmax-valid-hole-fits", "-fmax-refinement-hole-fits"
, "-frefinement-level-hole-fits" ]
]

normaliseGhcArgs _ _ args = args

-- | A structured set of GHC options/flags
Expand Down