Disable `-fdefer-out-of-scope-variables` in ghci.
authorHE, Tao <sighingnow@gmail.com>
Thu, 14 Jun 2018 13:14:58 +0000 (09:14 -0400)
committerBen Gamari <ben@smart-cactus.org>
Thu, 14 Jun 2018 14:03:28 +0000 (10:03 -0400)
We have already disabled `-fdefer-type-errors` and
`-fdefer-typed-holes` in ghci.
This patch disables `-fdefer-out-of-scope-variables` as well.

Fixes Trac #15259, as well as #14963.

Test Plan: make test TEST="T15259 T14963a T14963b T14963c"

Reviewers: bgamari, tdammers

Reviewed By: tdammers

Subscribers: tdammers, rwbarton, thomie, carter

GHC Trac Issues: #15259, #14963

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

15 files changed:
compiler/typecheck/TcRnDriver.hs
ghc/GHCi/UI.hs
testsuite/tests/ghci/scripts/T15259.script [new file with mode: 0644]
testsuite/tests/ghci/scripts/T15259.stderr [new file with mode: 0644]
testsuite/tests/ghci/scripts/all.T
testsuite/tests/ghci/should_run/T14963a.hs [new file with mode: 0644]
testsuite/tests/ghci/should_run/T14963a.script [new file with mode: 0644]
testsuite/tests/ghci/should_run/T14963a.stdout [new file with mode: 0644]
testsuite/tests/ghci/should_run/T14963b.hs [new file with mode: 0644]
testsuite/tests/ghci/should_run/T14963b.script [new file with mode: 0644]
testsuite/tests/ghci/should_run/T14963b.stdout [new file with mode: 0644]
testsuite/tests/ghci/should_run/T14963c.hs [new file with mode: 0644]
testsuite/tests/ghci/should_run/T14963c.script [new file with mode: 0644]
testsuite/tests/ghci/should_run/T14963c.stdout [new file with mode: 0644]
testsuite/tests/ghci/should_run/all.T

index 21aa59b..b073b50 100644 (file)
@@ -2061,22 +2061,74 @@ tcUserStmt (L loc (BodyStmt _ expr _ _))
                     tcGhciStmts [no_it_b] ,
                     tcGhciStmts [no_it_c] ]
 
-
-        -- Ensure that type errors don't get deferred when type checking the
-        -- naked expression. Deferring type errors here is unhelpful because the
-        -- expression gets evaluated right away anyway. It also would potentially
-        -- emit two redundant type-error warnings, one from each plan.
         ; generate_it <- goptM Opt_NoIt
+
+        -- We disable `-fdefer-type-errors` in GHCi for naked expressions.
+        -- See Note [Deferred type errors in GHCi]
+
+        -- NB: The flag `-fdefer-type-errors` implies `-fdefer-type-holes`
+        -- and `-fdefer-out-of-scope-variables`. However the flag
+        -- `-fno-defer-type-errors` doesn't imply `-fdefer-type-holes` and
+        -- `-fno-defer-out-of-scope-variables`. Thus the later two flags
+        -- also need to be unset here.
         ; plan <- unsetGOptM Opt_DeferTypeErrors $
                   unsetGOptM Opt_DeferTypedHoles $
+                  unsetGOptM Opt_DeferOutOfScopeVariables $
                     runPlans $ if generate_it
                                  then no_it_plans
                                  else it_plans
 
-
         ; fix_env <- getFixityEnv
         ; return (plan, fix_env) }
 
+{- Note [Deferred type errors in GHCi]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In GHCi, we ensure that type errors don't get deferred when type checking the
+naked expressions. Deferring type errors here is unhelpful because the
+expression gets evaluated right away anyway. It also would potentially emit
+two redundant type-error warnings, one from each plan.
+
+Trac #14963 reveals another bug that when deferred type errors is enabled
+in GHCi, any reference of imported/loaded variables (directly or indirectly)
+in interactively issued naked expressions will cause ghc panic. See more
+detailed dicussion in Trac #14963.
+
+The interactively issued declarations, statements, as well as the modules
+loaded into GHCi, are not affected. That means, for declaration, you could
+have
+
+    Prelude> :set -fdefer-type-errors
+    Prelude> x :: IO (); x = putStrLn True
+    <interactive>:14:26: warning: [-Wdeferred-type-errors]
+        ? Couldn't match type ‘Bool’ with ‘[Char]’
+          Expected type: String
+            Actual type: Bool
+        ? In the first argument of ‘putStrLn’, namely ‘True’
+          In the expression: putStrLn True
+          In an equation for ‘x’: x = putStrLn True
+
+But for naked expressions, you will have
+
+    Prelude> :set -fdefer-type-errors
+    Prelude> putStrLn True
+    <interactive>:2:10: error:
+        ? Couldn't match type ‘Bool’ with ‘[Char]’
+          Expected type: String
+            Actual type: Bool
+        ? In the first argument of ‘putStrLn’, namely ‘True’
+          In the expression: putStrLn True
+          In an equation for ‘it’: it = putStrLn True
+
+    Prelude> let x = putStrLn True
+    <interactive>:2:18: warning: [-Wdeferred-type-errors]
+        ? Couldn't match type ‘Bool’ with ‘[Char]’
+          Expected type: String
+            Actual type: Bool
+        ? In the first argument of ‘putStrLn’, namely ‘True’
+          In the expression: putStrLn True
+          In an equation for ‘x’: x = putStrLn True
+-}
+
 tcUserStmt rdr_stmt@(L loc _)
   = do { (([rn_stmt], fix_env), fvs) <- checkNoErrs $
            rnStmts GhciStmtCtxt rnLExpr [rdr_stmt] $ \_ -> do
@@ -2117,7 +2169,7 @@ tcUserStmt rdr_stmt@(L loc _)
 
 {-
 Note [GHCi Plans]
-
+~~~~~~~~~~~~~~~~~
 When a user types an expression in the repl we try to print it in three different
 ways. Also, depending on whether -fno-it is set, we bind a variable called `it`
 which can be used to refer to the result of the expression subsequently in the repl.
index 7c427a0..15cfcf3 100644 (file)
@@ -1085,6 +1085,10 @@ enqueueCommands cmds = do
 runStmt :: String -> SingleStep -> GHCi (Maybe GHC.ExecResult)
 runStmt stmt step = do
   dflags <- GHC.getInteractiveDynFlags
+  -- In GHCi, we disable `-fdefer-type-errors`, as well as `-fdefer-type-holes`
+  -- and `-fdefer-out-of-scope-variables` for **naked expressions**. The
+  -- declarations and statements are not affected.
+  -- See Note [Deferred type errors in GHCi] in typecheck/TcRnDriver.hs
   if | GHC.isStmt dflags stmt    -> run_stmt
      | GHC.isImport dflags stmt  -> run_import
      -- Every import declaration should be handled by `run_import`. As GHCi
diff --git a/testsuite/tests/ghci/scripts/T15259.script b/testsuite/tests/ghci/scripts/T15259.script
new file mode 100644 (file)
index 0000000..a2750c3
--- /dev/null
@@ -0,0 +1,3 @@
+:set -fdefer-out-of-scope-variables
+
+1 + a
diff --git a/testsuite/tests/ghci/scripts/T15259.stderr b/testsuite/tests/ghci/scripts/T15259.stderr
new file mode 100644 (file)
index 0000000..29a04a6
--- /dev/null
@@ -0,0 +1,2 @@
+
+<interactive>:3:5: error: Variable not in scope: a
index e803522..163ff0c 100755 (executable)
@@ -267,3 +267,4 @@ test('T14342', [extra_hc_opts("-XOverloadedStrings -XRebindableSyntax")],
 test('T14676', extra_files(['../prog002']), ghci_script, ['T14676.script'])
 test('T14796', normal, ghci_script, ['T14796.script'])
 test('T14969', normal, ghci_script, ['T14969.script'])
+test('T15259', normal, ghci_script, ['T15259.script'])
diff --git a/testsuite/tests/ghci/should_run/T14963a.hs b/testsuite/tests/ghci/should_run/T14963a.hs
new file mode 100644 (file)
index 0000000..b44e703
--- /dev/null
@@ -0,0 +1,2 @@
+test :: IO Bool
+test = return True
diff --git a/testsuite/tests/ghci/should_run/T14963a.script b/testsuite/tests/ghci/should_run/T14963a.script
new file mode 100644 (file)
index 0000000..add8e36
--- /dev/null
@@ -0,0 +1,3 @@
+:l T14963a
+:set -fdefer-type-errors
+test
diff --git a/testsuite/tests/ghci/should_run/T14963a.stdout b/testsuite/tests/ghci/should_run/T14963a.stdout
new file mode 100644 (file)
index 0000000..0ca9514
--- /dev/null
@@ -0,0 +1 @@
+True
diff --git a/testsuite/tests/ghci/should_run/T14963b.hs b/testsuite/tests/ghci/should_run/T14963b.hs
new file mode 100644 (file)
index 0000000..b44e703
--- /dev/null
@@ -0,0 +1,2 @@
+test :: IO Bool
+test = return True
diff --git a/testsuite/tests/ghci/should_run/T14963b.script b/testsuite/tests/ghci/should_run/T14963b.script
new file mode 100644 (file)
index 0000000..c2cb796
--- /dev/null
@@ -0,0 +1,3 @@
+:set -fdefer-type-errors
+:l T14963b
+test
diff --git a/testsuite/tests/ghci/should_run/T14963b.stdout b/testsuite/tests/ghci/should_run/T14963b.stdout
new file mode 100644 (file)
index 0000000..0ca9514
--- /dev/null
@@ -0,0 +1 @@
+True
diff --git a/testsuite/tests/ghci/should_run/T14963c.hs b/testsuite/tests/ghci/should_run/T14963c.hs
new file mode 100644 (file)
index 0000000..cac012e
--- /dev/null
@@ -0,0 +1,4 @@
+{-# OPTIONS_GHC -fdefer-type-errors #-}
+
+test :: IO Bool
+test = return True
diff --git a/testsuite/tests/ghci/should_run/T14963c.script b/testsuite/tests/ghci/should_run/T14963c.script
new file mode 100644 (file)
index 0000000..37dda62
--- /dev/null
@@ -0,0 +1,3 @@
+:set -fdefer-type-errors
+:l T14963c
+test
diff --git a/testsuite/tests/ghci/should_run/T14963c.stdout b/testsuite/tests/ghci/should_run/T14963c.stdout
new file mode 100644 (file)
index 0000000..0ca9514
--- /dev/null
@@ -0,0 +1 @@
+True
index c64b0e7..430df28 100644 (file)
@@ -30,3 +30,6 @@ test('T12549',     just_ghci, ghci_script, ['T12549.script'])
 test('BinaryArray', normal, compile_and_run, [''])
 test('T14125a',    just_ghci, ghci_script, ['T14125a.script'])
 test('T13825-ghci',just_ghci, ghci_script, ['T13825-ghci.script'])
+test('T14963a', just_ghci, ghci_script, ['T14963a.script'])
+test('T14963b', just_ghci, ghci_script, ['T14963b.script'])
+test('T14963c', [extra_hc_opts("-fdefer-type-errors")], ghci_script, ['T14963c.script'])