Add -fdefer-out-of-scope-variables flag (#12170).
authorEugene Akentyev <ak3ntev@gmail.com>
Wed, 31 Aug 2016 20:02:10 +0000 (16:02 -0400)
committerBen Gamari <ben@smart-cactus.org>
Wed, 31 Aug 2016 20:32:44 +0000 (16:32 -0400)
Reviewers: simonpj, thomie, austin, bgamari

Reviewed By: simonpj, thomie, bgamari

Subscribers: simonpj, thomie

Differential Revision: https://phabricator.haskell.org/D2458

GHC Trac Issues: #12170

12 files changed:
compiler/main/DynFlags.hs
compiler/typecheck/TcErrors.hs
docs/users_guide/8.2.1-notes.rst
docs/users_guide/glasgow_exts.rst
docs/users_guide/using-warnings.rst
testsuite/tests/typecheck/should_compile/T12170b.hs [new file with mode: 0644]
testsuite/tests/typecheck/should_compile/T12170b.stderr [new file with mode: 0644]
testsuite/tests/typecheck/should_compile/all.T
testsuite/tests/typecheck/should_fail/T12170a.hs [new file with mode: 0644]
testsuite/tests/typecheck/should_fail/T12170a.stderr [new file with mode: 0644]
testsuite/tests/typecheck/should_fail/all.T
utils/mkUserGuidePart/Options/Warnings.hs

index 17386ab..065a732 100644 (file)
@@ -480,6 +480,7 @@ data GeneralFlag
    | Opt_HelpfulErrors
    | Opt_DeferTypeErrors
    | Opt_DeferTypedHoles
+   | Opt_DeferOutOfScopeVariables
    | Opt_PIC
    | Opt_SccProfilingOn
    | Opt_Ticky
@@ -608,6 +609,7 @@ data WarningFlag =
    | Opt_WarnUntickedPromotedConstructors
    | Opt_WarnDerivingTypeable
    | Opt_WarnDeferredTypeErrors
+   | Opt_WarnDeferredOutOfScopeVariables
    | Opt_WarnNonCanonicalMonadInstances   -- since 8.0
    | Opt_WarnNonCanonicalMonadFailInstances -- since 8.0
    | Opt_WarnNonCanonicalMonoidInstances  -- since 8.0
@@ -3248,6 +3250,8 @@ wWarningFlagsDeps = [
   depFlagSpec "auto-orphans"             Opt_WarnAutoOrphans
     "it has no effect",
   flagSpec "deferred-type-errors"        Opt_WarnDeferredTypeErrors,
+  flagSpec "deferred-out-of-scope-variables"
+                                         Opt_WarnDeferredOutOfScopeVariables,
   flagSpec "deprecations"                Opt_WarnWarningsDeprecations,
   flagSpec "deprecated-flags"            Opt_WarnDeprecatedFlags,
   flagSpec "deriving-typeable"           Opt_WarnDerivingTypeable,
@@ -3363,6 +3367,7 @@ fFlagsDeps = [
   flagSpec "cpr-anal"                         Opt_CprAnal,
   flagSpec "defer-type-errors"                Opt_DeferTypeErrors,
   flagSpec "defer-typed-holes"                Opt_DeferTypedHoles,
+  flagSpec "defer-out-of-scope-variables"     Opt_DeferOutOfScopeVariables,
   flagSpec "dicts-cheap"                      Opt_DictsCheap,
   flagSpec "dicts-strict"                     Opt_DictsStrict,
   flagSpec "dmd-tx-dict-sel"                  Opt_DmdTxDictSel,
@@ -3709,6 +3714,7 @@ default_PIC platform =
 -- on
 impliedGFlags :: [(GeneralFlag, TurnOnFlag, GeneralFlag)]
 impliedGFlags = [(Opt_DeferTypeErrors, turnOn, Opt_DeferTypedHoles)
+                ,(Opt_DeferTypeErrors, turnOn, Opt_DeferOutOfScopeVariables)
                 ,(Opt_Strictness, turnOn, Opt_WorkerWrapper)
                 ]
 
@@ -3906,6 +3912,7 @@ standardWarnings -- see Note [Documenting warning flags]
         Opt_WarnDeprecatedFlags,
         Opt_WarnDeferredTypeErrors,
         Opt_WarnTypedHoles,
+        Opt_WarnDeferredOutOfScopeVariables,
         Opt_WarnPartialTypeSignatures,
         Opt_WarnUnrecognisedPragmas,
         Opt_WarnDuplicateExports,
index f3f5b12..4f1c5db 100644 (file)
@@ -136,7 +136,14 @@ reportUnsolved wanted
                         | warn_partial_sigs = HoleWarn
                         | otherwise         = HoleDefer
 
-       ; report_unsolved (Just binds_var) False type_errors expr_holes type_holes wanted
+       ; defer_out_of_scope <- goptM Opt_DeferOutOfScopeVariables
+       ; warn_out_of_scope <- woptM Opt_WarnDeferredOutOfScopeVariables
+       ; let out_of_scope_holes | not defer_out_of_scope = HoleError
+                                | warn_out_of_scope      = HoleWarn
+                                | otherwise              = HoleDefer
+
+       ; report_unsolved (Just binds_var) False type_errors expr_holes
+          type_holes out_of_scope_holes wanted
        ; getTcEvBinds binds_var }
 
 -- | Report *all* unsolved goals as errors, even if -fdefer-type-errors is on
@@ -148,14 +155,14 @@ reportUnsolved wanted
 -- and for simplifyDefault.
 reportAllUnsolved :: WantedConstraints -> TcM ()
 reportAllUnsolved wanted
-  = report_unsolved Nothing False TypeError HoleError HoleError wanted
+  = report_unsolved Nothing False TypeError HoleError HoleError HoleError wanted
 
 -- | Report all unsolved goals as warnings (but without deferring any errors to
 -- run-time). See Note [Safe Haskell Overlapping Instances Implementation] in
 -- TcSimplify
 warnAllUnsolved :: WantedConstraints -> TcM ()
 warnAllUnsolved wanted
-  = report_unsolved Nothing True TypeWarn HoleWarn HoleWarn wanted
+  = report_unsolved Nothing True TypeWarn HoleWarn HoleWarn HoleWarn wanted
 
 -- | Report unsolved goals as errors or warnings.
 report_unsolved :: Maybe EvBindsVar  -- cec_binds
@@ -163,8 +170,10 @@ report_unsolved :: Maybe EvBindsVar  -- cec_binds
                 -> TypeErrorChoice   -- Deferred type errors
                 -> HoleChoice        -- Expression holes
                 -> HoleChoice        -- Type holes
+                -> HoleChoice        -- Out of scope holes
                 -> WantedConstraints -> TcM ()
-report_unsolved mb_binds_var err_as_warn type_errors expr_holes type_holes wanted
+report_unsolved mb_binds_var err_as_warn type_errors expr_holes
+    type_holes out_of_scope_holes wanted
   | isEmptyWC wanted
   = return ()
   | otherwise
@@ -188,6 +197,7 @@ report_unsolved mb_binds_var err_as_warn type_errors expr_holes type_holes wante
                             , cec_errors_as_warns = err_as_warn
                             , cec_expr_holes = expr_holes
                             , cec_type_holes = type_holes
+                            , cec_out_of_scope_holes = out_of_scope_holes
                             , cec_suppress = False -- See Note [Suppressing error messages]
                             , cec_warn_redundant = warn_redundant
                             , cec_binds    = mb_binds_var }
@@ -278,8 +288,13 @@ data ReportErrCtxt
           , cec_defer_type_errors :: TypeErrorChoice -- Defer type errors until runtime
                                                      -- Irrelevant if cec_binds = Nothing
 
-          , cec_expr_holes :: HoleChoice  -- Holes in expressions
-          , cec_type_holes :: HoleChoice  -- Holes in types
+          -- cec_expr_holes is a union of:
+          --   cec_type_holes - a set of typed holes: '_', '_a', '_foo'
+          --   cec_out_of_scope_holes - a set of variables which are
+          --                            out of scope: 'x', 'y', 'bar'
+          , cec_expr_holes :: HoleChoice           -- Holes in expressions
+          , cec_type_holes :: HoleChoice           -- Holes in types
+          , cec_out_of_scope_holes :: HoleChoice   -- Out of scope holes
 
           , cec_warn_redundant :: Bool    -- True <=> -Wredundant-constraints
 
@@ -621,10 +636,17 @@ maybeReportHoleError ctxt ct err
        HoleWarn  -> reportWarning (Reason Opt_WarnPartialTypeSignatures) err
        HoleDefer -> return ()
 
+  -- Always report an error for out-of-scope variables
+  -- Unless -fdefer-out-of-scope-variables is on,
+  -- in which case the messages are discarded.
+  -- See Trac #12170, #12406
   | isOutOfScopeCt ct
-  = -- Always report an error for out-of-scope variables
-    -- See Trac #12170, #12406
-    reportError err
+  = -- If deferring, report a warning only if -Wout-of-scope-variables is on
+    case cec_out_of_scope_holes ctxt of
+      HoleError -> reportError err
+      HoleWarn  ->
+        reportWarning (Reason Opt_WarnDeferredOutOfScopeVariables) err
+      HoleDefer -> return ()
 
   -- Otherwise this is a typed hole in an expression,
   -- but not for an out-of-scope variable
index 1b4b34e..ec413b9 100644 (file)
@@ -38,6 +38,9 @@ Compiler
   syntax can be used, in addition to a new form for specifying the cost centre
   name. See :ref:`scc-pragma` for examples.
 
+- Added :ghc-flag:`-fdefer-out-of-scope-variables`, which converts variable
+  out of scope variables errors into warnings.
+
 GHCi
 ~~~~
 
index 94172e3..7709b22 100644 (file)
@@ -9430,13 +9430,21 @@ Here are some more details:
    containing holes, by using the :ghc-flag:`-fdefer-typed-holes` flag. This
    flag defers errors produced by typed holes until runtime, and
    converts them into compile-time warnings. These warnings can in turn
-   be suppressed entirely by :ghc-flag:`-fno-warn-typed-holes`).
+   be suppressed entirely by :ghc-flag:`-fno-warn-typed-holes`.
 
-   The result is that a hole will behave like ``undefined``, but with
+   The same behaviour for "``Variable out of scope``" errors, it terminates
+   compilation by default. You can defer such errors by using the
+   :ghc-flag:`-fdefer-out-of-scope-variables` flag. This flag defers errors
+   produced by out of scope variables until runtime, and
+   converts them into compile-time warnings. These warnings can in turn
+   be suppressed entirely by :ghc-flag:`-fno-warn-deferred-out-of-scope-variables`.
+
+   The result is that a hole or a variable will behave like ``undefined``, but with
    the added benefits that it shows a warning at compile time, and will
    show the same message if it gets evaluated at runtime. This behaviour
    follows that of the :ghc-flag:`-fdefer-type-errors` option, which implies
-   :ghc-flag:`-fdefer-typed-holes`. See :ref:`defer-type-errors`.
+   :ghc-flag:`-fdefer-typed-holes` and :ghc-flag:`-fdefer-out-of-scope-variables`.
+   See :ref:`defer-type-errors`.
 
 -  All unbound identifiers are treated as typed holes, *whether or not
    they start with an underscore*. The only difference is in the error
@@ -9930,12 +9938,13 @@ will not prevent compilation. You can use
 :ghc-flag:`-Wno-deferred-type-errors <-Wdeferred-type-errors>` to suppress these
 warnings.
 
-This flag implies the :ghc-flag:`-fdefer-typed-holes` flag, which enables this
-behaviour for `typed holes <#typed-holes>`__. Should you so wish, it is
+This flag implies the :ghc-flag:`-fdefer-typed-holes` and
+:ghc-flag:`-fdefer-out-of-scope-variables` flags, which enables this
+behaviour for `typed holes <#typed-holes>`__ and variables. Should you so wish, it is
 possible to enable :ghc-flag:`-fdefer-type-errors` without enabling
-:ghc-flag:`-fdefer-typed-holes`, by explicitly specifying
-:ghc-flag:`-fno-defer-typed-holes` on the command-line after the
-:ghc-flag:`-fdefer-type-errors` flag.
+:ghc-flag:`-fdefer-typed-holes` or :ghc-flag:`-fdefer-out-of-scope-variables`,
+by explicitly specifying :ghc-flag:`-fno-defer-typed-holes` or :ghc-flag:`-fno-defer-out-of-scope-variables`
+on the command-line after the :ghc-flag:`-fdefer-type-errors` flag.
 
 At runtime, whenever a term containing a type error would need to be
 evaluated, the error is converted into a runtime exception of type
index 46b6984..8b5e704 100644 (file)
@@ -152,7 +152,8 @@ of ``-W(no-)*``.
 
 .. ghc-flag:: -fdefer-typed-holes
 
-    Defer typed holes errors until runtime. This will turn the errors
+    Defer typed holes errors (errors about names with a leading underscore
+    (e.g., “_”, “_foo”, “_bar”)) until runtime. This will turn the errors
     produced by :ref:`typed holes <typed-holes>` into warnings. Using a value
     that depends on a typed hole produces a runtime error, the same as
     :ghc-flag:`-fdefer-type-errors` (which implies this option). See :ref:`typed-holes`
@@ -160,6 +161,16 @@ of ``-W(no-)*``.
 
     Implied by :ghc-flag:`-fdefer-type-errors`. See also :ghc-flag:`-Wtyped-holes`.
 
+.. ghc-flag:: -fdefer-out-of-scope-variables
+
+    Defer variable out of scope errors (errors about names without a leading underscore)
+    until runtime. This will turn variable-out-of-scope errors into warnings.
+    Using a value that depends on a typed hole produces a runtime error,
+    the same as :ghc-flag:`-fdefer-type-errors` (which implies this option).
+    See :ref:`typed-holes` and :ref:`defer-type-errors`.
+
+    Implied by :ghc-flag:`-fdefer-type-errors`. See also :ghc-flag:`-Wdeferred-out-of-scope-variables`.
+
 .. ghc-flag:: -Wpartial-type-signatures
 
     Determines whether the compiler reports holes in partial type
diff --git a/testsuite/tests/typecheck/should_compile/T12170b.hs b/testsuite/tests/typecheck/should_compile/T12170b.hs
new file mode 100644 (file)
index 0000000..1466afc
--- /dev/null
@@ -0,0 +1,5 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# OPTIONS_GHC -fdefer-out-of-scope-variables #-}
+
+main :: IO ()
+main = smth
diff --git a/testsuite/tests/typecheck/should_compile/T12170b.stderr b/testsuite/tests/typecheck/should_compile/T12170b.stderr
new file mode 100644 (file)
index 0000000..4ff0f52
--- /dev/null
@@ -0,0 +1,3 @@
+
+T12170b.hs:5:8: warning: [-Wdeferred-out-of-scope-variables (in -Wdefault)]
+    Variable not in scope: smth :: IO ()
index 0f05a11..4bebf97 100644 (file)
@@ -537,3 +537,4 @@ test('T12185', normal, compile, [''])
 test('T12133', normal, compile, [''])
 test('T12381', normal, compile, [''])
 test('T12082', normal, compile, [''])
+test('T12170b', normal, compile, [''])
diff --git a/testsuite/tests/typecheck/should_fail/T12170a.hs b/testsuite/tests/typecheck/should_fail/T12170a.hs
new file mode 100644 (file)
index 0000000..6783cd0
--- /dev/null
@@ -0,0 +1,20 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# OPTIONS_GHC -fdefer-out-of-scope-variables #-}
+
+module T12170a where
+
+-- import Control.Monad  -- comment this out to cause error
+import Data.IORef
+
+class MonadRef m where
+    type Ref m :: * -> *
+    newRef :: a -> m (Ref m a)
+    readRef :: Ref m a -> m a
+
+instance MonadRef IO where
+    type Ref IO = IORef
+    newRef = newIORef
+    readRef = readIORef
+
+foo :: IO ()
+foo = newRef (pure ()) >>= join . readRef
diff --git a/testsuite/tests/typecheck/should_fail/T12170a.stderr b/testsuite/tests/typecheck/should_fail/T12170a.stderr
new file mode 100644 (file)
index 0000000..c1e4bdc
--- /dev/null
@@ -0,0 +1,9 @@
+
+T12170a.hs:20:7: error:
+    • Couldn't match type ‘Ref m0’ with ‘IORef’
+      Expected type: IO (Ref m0 (f0 ()))
+        Actual type: IO (Ref IO (f0 ()))
+      The type variable ‘m0’ is ambiguous
+    • In the first argument of ‘(>>=)’, namely ‘newRef (pure ())’
+      In the expression: newRef (pure ()) >>= join . readRef
+      In an equation for ‘foo’: foo = newRef (pure ()) >>= join . readRef
\ No newline at end of file
index dda2a7d..eda6a9f 100644 (file)
@@ -429,3 +429,4 @@ test('T12151', normal, compile_fail, [''])
 test('T7437', normal, compile_fail, [''])
 test('T12177', normal, compile_fail, [''])
 test('T12406', normal, compile_fail, [''])
+test('T12170a', normal, compile_fail, [''])
index 61e6019..eadb600 100644 (file)
@@ -51,7 +51,9 @@ warningsOptions =
   , flag { flagName = "-fdefer-type-errors"
          , flagDescription =
            "Turn type errors into warnings, :ref:`deferring the error until "++
-           "runtime <defer-type-errors>`. Implies :ghc-flag:`-fdefer-typed-holes`. "++
+           "runtime <defer-type-errors>`. Implies "++
+           ":ghc-flag:`-fdefer-typed-holes` and "++
+           ":ghc-flag:`-fdefer-out-of-scope-variables`. "++
            "See also :ghc-flag:`-Wdeferred-type-errors`"
          , flagType = DynamicFlag
          , flagReverse = "-fno-defer-type-errors"
@@ -65,6 +67,14 @@ warningsOptions =
          , flagType = DynamicFlag
          , flagReverse = "-fno-defer-typed-holes"
          }
+  , flag { flagName = "-fdefer-out-of-scope-variables"
+         , flagDescription =
+           "Convert variable out of scope variables errors into warnings. "++
+           "Implied by :ghc-flag:`-fdefer-type-errors`. "++
+           "See also :ghc-flag:`-Wdeferred-out-of-scope-variables`."
+         , flagType = DynamicFlag
+         , flagReverse = "-fno-defer-out-of-scope-variables"
+         }
   , flag { flagName = "-fhelpful-errors"
          , flagDescription = "Make suggestions for mis-spelled names."
          , flagType = DynamicFlag
@@ -398,6 +408,14 @@ warningsOptions =
          , flagType = DynamicFlag
          , flagReverse = "-Wno-typed-holes"
          }
+  , flag { flagName = "-Wdeferred-out-of-scope-variables"
+         , flagDescription =
+           "Report warnings when variable out-of-scope errors are "++
+           ":ref:`deferred until runtime <defer-out-of-scope-variables>`. "++
+           "See :ghc-flag:`-fdefer-out-of-scope-variables`."
+         , flagType = DynamicFlag
+         , flagReverse = "-Wno-deferred-out-of-scope-variables"
+         }
   , flag { flagName = "-Wpartial-type-signatures"
          , flagDescription =
            "warn about holes in partial type signatures when "++