[Git][ghc/ghc][master] Fix ParallelListComp out of scope suggestion

Marge Bot (@marge-bot) gitlab at gitlab.haskell.org
Sat Feb 25 02:30:31 UTC 2023



Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC


Commits:
69fb0b13 by Aaron Allen at 2023-02-24T21:30:10-05:00
Fix ParallelListComp out of scope suggestion

This patch makes it so vars from one block of a parallel list
comprehension are not in scope in a subsequent block during type
checking. This was causing GHC to emit a faulty suggestion when an out
of scope variable shared the occ name of a var from a different block.

Fixes #22940

- - - - -


4 changed files:

- compiler/GHC/Tc/Gen/Match.hs
- + testsuite/tests/typecheck/should_fail/T22940.hs
- + testsuite/tests/typecheck/should_fail/T22940.stderr
- testsuite/tests/typecheck/should_fail/all.T


Changes:

=====================================
compiler/GHC/Tc/Gen/Match.hs
=====================================
@@ -42,6 +42,7 @@ import {-# SOURCE #-}   GHC.Tc.Gen.Expr( tcSyntaxOp, tcInferRho, tcInferRhoNC
                                        , tcCheckMonoExpr, tcCheckMonoExprNC
                                        , tcCheckPolyExpr )
 
+import GHC.Rename.Utils ( bindLocalNames )
 import GHC.Tc.Errors.Types
 import GHC.Tc.Utils.Monad
 import GHC.Tc.Utils.Env
@@ -473,21 +474,28 @@ tcLcStmt _ _ (BodyStmt _ rhs _ _) elt_ty thing_inside
         ; thing <- thing_inside elt_ty
         ; return (BodyStmt boolTy rhs' noSyntaxExpr noSyntaxExpr, thing) }
 
--- ParStmt: See notes with tcMcStmt
+-- ParStmt: See notes with tcMcStmt and Note [Scoping in parallel list comprehensions]
 tcLcStmt m_tc ctxt (ParStmt _ bndr_stmts_s _ _) elt_ty thing_inside
-  = do  { (pairs', thing) <- loop bndr_stmts_s
+  = do  { env <- getLocalRdrEnv
+        ; (pairs', thing) <- loop env [] bndr_stmts_s
         ; return (ParStmt unitTy pairs' noExpr noSyntaxExpr, thing) }
   where
-    -- loop :: [([LStmt GhcRn], [GhcRn])]
+    -- loop :: LocalRdrEnv -- The original LocalRdrEnv
+    --      -> [Name]      -- Variables bound by earlier branches
+    --      -> [([LStmt GhcRn], [GhcRn])]
     --      -> TcM ([([LStmt GhcTc], [GhcTc])], thing)
-    loop [] = do { thing <- thing_inside elt_ty
-                 ; return ([], thing) }         -- matching in the branches
+    --
+    -- Invariant: on entry to `loop`, the LocalRdrEnv is set to
+    --            origEnv, the LocalRdrEnv for the entire comprehension
+    loop _ allBinds [] = do { thing <- bindLocalNames allBinds $ thing_inside elt_ty
+                            ; return ([], thing) }   -- matching in the branches
 
-    loop (ParStmtBlock x stmts names _ : pairs)
+    loop origEnv priorBinds (ParStmtBlock x stmts names _ : pairs)
       = do { (stmts', (ids, pairs', thing))
                 <- tcStmtsAndThen ctxt (tcLcStmt m_tc) stmts elt_ty $ \ _elt_ty' ->
                    do { ids <- tcLookupLocalIds names
-                      ; (pairs', thing) <- loop pairs
+                      ; (pairs', thing) <- setLocalRdrEnv origEnv $
+                          loop origEnv (names ++ priorBinds) pairs
                       ; return (ids, pairs', thing) }
            ; return ( ParStmtBlock x stmts' ids noSyntaxExpr : pairs', thing ) }
 
@@ -1012,6 +1020,21 @@ e_i   :: exp_ty_i
 <$>   :: (pat_ty_1 -> ... -> pat_ty_n -> body_ty) -> exp_ty_1 -> t_1
 <*>_i :: t_(i-1) -> exp_ty_i -> t_i
 join :: tn -> res_ty
+
+Note [Scoping in parallel list comprehensions]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In a parallel list comprehension like [ ebody | a <- blah1; e1 | b <- blah2; e2 ]
+we want to ensure that in the lexical environment, tcl_rdr :: LocalRdrEnv, we have
+  * 'a' in scope in e1, but not 'b'
+  * 'b' in scope in e2, but not 'a'
+  * Both in scope in ebody
+We don't want too /many/ variables in the LocalRdrEnv, else we make stupid
+suggestions for an out-of-scope variable (#22940).
+
+To achieve this we:
+  * At the start of each branch, reset the LocalRdrEnv to the outer scope.
+  * Before typechecking ebody, add to LocalRdrEnv all the variables bound in
+    all branches. This step is done with bindLocalNames.
 -}
 
 tcApplicativeStmts


=====================================
testsuite/tests/typecheck/should_fail/T22940.hs
=====================================
@@ -0,0 +1,4 @@
+{-# LANGUAGE ParallelListComp #-}
+
+x :: [(Int, Char)]
+x = [ (a, b) | a <- [0 ..] | b <- "abcd", even a ]


=====================================
testsuite/tests/typecheck/should_fail/T22940.stderr
=====================================
@@ -0,0 +1,3 @@
+
+T22940.hs:4:48: error: [GHC-88464]
+    Variable not in scope: a


=====================================
testsuite/tests/typecheck/should_fail/all.T
=====================================
@@ -669,4 +669,4 @@ test('T20666', normal, compile, [''])   # To become compile_fail after migration
 test('T20666a', normal, compile, [''])  # To become compile_fail after migration period (see #22912)
 test('T22924a', normal, compile_fail, [''])
 test('T22924b', normal, compile_fail, [''])
-
+test('T22940', normal, compile_fail, [''])



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/69fb0b13abe14af4537f3828ef08f9841e34e630

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/69fb0b13abe14af4537f3828ef08f9841e34e630
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20230224/fa6f9442/attachment-0001.html>


More information about the ghc-commits mailing list