diff options
author | Evan Rutledge Borden <eborden@frontrowed.com> | 2017-11-21 18:06:01 -0500 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2017-11-21 21:11:16 -0500 |
commit | 63e4ac37d7268e063cb6adcea89e1e8716c5de89 (patch) | |
tree | 3d0a04ae40369f660f131e16a3708719adcd1b4a | |
parent | f376ebac29d8dab023482a21ecfbc4dc032ab23e (diff) | |
download | haskell-63e4ac37d7268e063cb6adcea89e1e8716c5de89.tar.gz |
Add warn-missing-export-lists
Many industrial users have aligned around the idea that implicit exports
are an anti-pattern. They lead to namespace pollution and byzantine
naming schemes. They also prevent GHC's dead code analysis and create
more obstacles to optimization. This warning allows teams/projects to
warn on or enforce via -Werror explicit export lists.
This warning also serves as a complement to warn-missing-import-lists.
This was originally discussed here:
https://github.com/ghc-proposals/ghc-proposals/pull/93
Test Plan: Three new minimal tests have been added to the type checker.
Reviewers: bgamari
Reviewed By: bgamari
Subscribers: rwbarton, thomie
Differential Revision: https://phabricator.haskell.org/D4197
-rw-r--r-- | compiler/main/DynFlags.hs | 2 | ||||
-rw-r--r-- | compiler/typecheck/TcRnExports.hs | 18 | ||||
-rw-r--r-- | docs/users_guide/8.4.1-notes.rst | 3 | ||||
-rw-r--r-- | docs/users_guide/using-warnings.rst | 26 | ||||
-rw-r--r-- | testsuite/tests/typecheck/should_compile/MissingExportList01.hs | 5 | ||||
-rw-r--r-- | testsuite/tests/typecheck/should_compile/MissingExportList02.hs | 5 | ||||
-rw-r--r-- | testsuite/tests/typecheck/should_compile/all.T | 2 | ||||
-rw-r--r-- | testsuite/tests/typecheck/should_fail/MissingExportList03.hs | 5 | ||||
-rw-r--r-- | testsuite/tests/typecheck/should_fail/MissingExportList03.stderr | 2 | ||||
-rw-r--r-- | testsuite/tests/typecheck/should_fail/all.T | 1 |
10 files changed, 65 insertions, 4 deletions
diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs index cbf3ab7622..ffc8614734 100644 --- a/compiler/main/DynFlags.hs +++ b/compiler/main/DynFlags.hs @@ -683,6 +683,7 @@ data WarningFlag = | Opt_WarnUnbangedStrictPatterns -- Since 8.2 | Opt_WarnMissingHomeModules -- Since 8.2 | Opt_WarnPartialFields -- Since 8.4 + | Opt_WarnMissingExportList deriving (Eq, Show, Enum) data Language = Haskell98 | Haskell2010 @@ -3639,6 +3640,7 @@ wWarningFlagsDeps = [ flagSpec "identities" Opt_WarnIdentities, flagSpec "missing-fields" Opt_WarnMissingFields, flagSpec "missing-import-lists" Opt_WarnMissingImportList, + flagSpec "missing-export-lists" Opt_WarnMissingExportList, depFlagSpec "missing-local-sigs" Opt_WarnMissingLocalSignatures "it is replaced by -Wmissing-local-signatures", flagSpec "missing-local-signatures" Opt_WarnMissingLocalSignatures, diff --git a/compiler/typecheck/TcRnExports.hs b/compiler/typecheck/TcRnExports.hs index a79e30d5f2..e2b6a61bfa 100644 --- a/compiler/typecheck/TcRnExports.hs +++ b/compiler/typecheck/TcRnExports.hs @@ -181,10 +181,15 @@ exports_from_avail Nothing rdr_env _imports _this_mod -- The same as (module M) where M is the current module name, -- so that's how we handle it, except we also export the data family -- when a data instance is exported. - = let avails = - map fix_faminst . gresToAvailInfo - . filter isLocalGRE . globalRdrEnvElts $ rdr_env - in return (Nothing, avails) + = do { + ; warnMissingExportList <- woptM Opt_WarnMissingExportList + ; warnIfFlag Opt_WarnMissingExportList + warnMissingExportList + (missingModuleExportWarn $ moduleName _this_mod) + ; let avails = + map fix_faminst . gresToAvailInfo + . filter isLocalGRE . globalRdrEnvElts $ rdr_env + ; return (Nothing, avails) } where -- #11164: when we define a data instance -- but not data family, re-export the family @@ -659,6 +664,11 @@ nullModuleExport :: ModuleName -> SDoc nullModuleExport mod = text "The export item `module" <+> ppr mod <> ptext (sLit "' exports nothing") +missingModuleExportWarn :: ModuleName -> SDoc +missingModuleExportWarn mod + = text "The export item `module" <+> ppr mod <> + ptext (sLit "' is missing an export list") + dodgyExportWarn :: Name -> SDoc dodgyExportWarn item diff --git a/docs/users_guide/8.4.1-notes.rst b/docs/users_guide/8.4.1-notes.rst index 103559cedd..1acab73693 100644 --- a/docs/users_guide/8.4.1-notes.rst +++ b/docs/users_guide/8.4.1-notes.rst @@ -108,6 +108,9 @@ Language Compiler ~~~~~~~~ +- Add warning flag :ghc-flag:`-Wmissing-export-lists` which causes the type + checker to warn when a module does not include an explicit export list. + - The ``configure`` script now no longer accepts ``--with-TOOL`` flags (e.g. ``--with-nm``, ``--with-ld``, etc.). Instead, these are taken from environment variables, as is typical in ``autoconf`` scripts. For instance, diff --git a/docs/users_guide/using-warnings.rst b/docs/users_guide/using-warnings.rst index c6a86bbb71..cf41c283ab 100644 --- a/docs/users_guide/using-warnings.rst +++ b/docs/users_guide/using-warnings.rst @@ -74,6 +74,7 @@ The following flags are simple ways to select standard "packages" of warnings: * :ghc-flag:`-Wimplicit-prelude` * :ghc-flag:`-Wmissing-local-signatures` * :ghc-flag:`-Wmissing-exported-signatures` + * :ghc-flag:`-Wmissing-export-lists` * :ghc-flag:`-Wmissing-import-lists` * :ghc-flag:`-Wmissing-home-modules` * :ghc-flag:`-Widentities` @@ -858,6 +859,31 @@ of ``-W(no-)*``. fields are initialised with bottoms), it is often an indication of a programmer error. +.. ghc-flag:: -Wmissing-export-lists + :shortdesc: warn when a module declaration does not explicitly list all + exports + :type: dynamic + :reverse: -fnowarn-missing-export-lists + :category: + + :since: 8.4.1 + + .. index:: + single: missing export lists, warning + single: export lists, missing + + This flag warns if you declare a module without declaring an explicit + export list. For example :: + + module M where + + p x = x + + The :ghc-flag:`-Wmissing-export-lists` flag will warn that ``M`` does not + declare an export list. Declaring an explicit export list for ``M`` enables + GHC dead code analysis, prevents accidental export of names and can ease + optimizations like inlining. + .. ghc-flag:: -Wmissing-import-lists :shortdesc: warn when an import declaration does not explicitly list all the names brought into scope diff --git a/testsuite/tests/typecheck/should_compile/MissingExportList01.hs b/testsuite/tests/typecheck/should_compile/MissingExportList01.hs new file mode 100644 index 0000000000..62b9509bab --- /dev/null +++ b/testsuite/tests/typecheck/should_compile/MissingExportList01.hs @@ -0,0 +1,5 @@ +{-# OPTIONS_GHC -Werror -fwarn-missing-export-lists #-} +module ShouldCompile (foo) where + +foo :: String +foo = "foo" diff --git a/testsuite/tests/typecheck/should_compile/MissingExportList02.hs b/testsuite/tests/typecheck/should_compile/MissingExportList02.hs new file mode 100644 index 0000000000..15c31b93c3 --- /dev/null +++ b/testsuite/tests/typecheck/should_compile/MissingExportList02.hs @@ -0,0 +1,5 @@ +{-# OPTIONS_GHC -Werror -fwarn-missing-export-lists #-} +module ShouldCompile () where + +foo :: String +foo = "foo" diff --git a/testsuite/tests/typecheck/should_compile/all.T b/testsuite/tests/typecheck/should_compile/all.T index 03e70915d4..417e43ee70 100644 --- a/testsuite/tests/typecheck/should_compile/all.T +++ b/testsuite/tests/typecheck/should_compile/all.T @@ -582,3 +582,5 @@ test('T14363', normal, compile, ['']) test('T14363a', normal, compile, ['']) test('T7169', normal, compile, ['']) test('T14434', [], run_command, ['$MAKE -s --no-print-directory T14434']) +test('MissingExportList01', normal, compile, ['']) +test('MissingExportList02', normal, compile, ['']) diff --git a/testsuite/tests/typecheck/should_fail/MissingExportList03.hs b/testsuite/tests/typecheck/should_fail/MissingExportList03.hs new file mode 100644 index 0000000000..4a5ecf0bcf --- /dev/null +++ b/testsuite/tests/typecheck/should_fail/MissingExportList03.hs @@ -0,0 +1,5 @@ +{-# OPTIONS_GHC -Werror -fwarn-missing-export-lists #-} +module ShouldFail where + +foo :: String +foo = "foo" diff --git a/testsuite/tests/typecheck/should_fail/MissingExportList03.stderr b/testsuite/tests/typecheck/should_fail/MissingExportList03.stderr new file mode 100644 index 0000000000..f4258de0b4 --- /dev/null +++ b/testsuite/tests/typecheck/should_fail/MissingExportList03.stderr @@ -0,0 +1,2 @@ +MissingExportList03.hs:1:1: [-Wmissing-export-lists, -Werror=missing-export-lists] + The export item `module ShouldFail' is missing an export list diff --git a/testsuite/tests/typecheck/should_fail/all.T b/testsuite/tests/typecheck/should_fail/all.T index ca0264b773..553e10af88 100644 --- a/testsuite/tests/typecheck/should_fail/all.T +++ b/testsuite/tests/typecheck/should_fail/all.T @@ -461,3 +461,4 @@ test('T14232', normal, compile_fail, ['']) test('T14325', normal, compile_fail, ['']) test('T14350', normal, compile_fail, ['']) test('T14390', normal, compile_fail, ['']) +test('MissingExportList03', normal, compile_fail, ['']) |