[Git][ghc/ghc][master] Fix tyvar scoping within class SPECIALISE pragmas

Marge Bot (@marge-bot) gitlab at gitlab.haskell.org
Wed Feb 8 19:41:03 UTC 2023



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


Commits:
9ee761bf by sheaf at 2023-02-08T14:40:40-05:00
Fix tyvar scoping within class SPECIALISE pragmas

Type variables from class/instance headers scope over class/instance
method type signatures, but DO NOT scope over the type signatures in
SPECIALISE and SPECIALISE instance pragmas.

The logic in GHC.Rename.Bind.rnMethodBinds correctly accounted for
SPECIALISE inline pragmas, but forgot to apply the same treatment
to method SPECIALISE pragmas, which lead to a Core Lint failure with
an out-of-scope type variable. This patch makes sure we apply the same
logic for both cases.

Fixes #22913

- - - - -


3 changed files:

- compiler/GHC/Rename/Bind.hs
- + testsuite/tests/rename/should_compile/T22913.hs
- testsuite/tests/rename/should_compile/all.T


Changes:

=====================================
compiler/GHC/Rename/Bind.hs
=====================================
@@ -893,17 +893,15 @@ rnMethodBinds is_cls_decl cls ktv_names binds sigs
 
        -- Rename the pragmas and signatures
        -- Annoyingly the type variables /are/ in scope for signatures, but
-       -- /are not/ in scope in the SPECIALISE instance pramas; e.g.
-       --    instance Eq a => Eq (T a) where
-       --       (==) :: a -> a -> a
-       --       {-# SPECIALISE instance Eq a => Eq (T [a]) #-}
-       ; let (spec_inst_prags, other_sigs) = partition isSpecInstLSig sigs
+       -- /are not/ in scope in SPECIALISE and SPECIALISE instance pragmas.
+       -- See Note [Type variable scoping in SPECIALISE pragmas].
+       ; let (spec_prags, other_sigs) = partition (isSpecLSig <||> isSpecInstLSig) sigs
              bound_nms = mkNameSet (collectHsBindsBinders CollNoDictBinders binds')
              sig_ctxt | is_cls_decl = ClsDeclCtxt cls
                       | otherwise   = InstDeclCtxt bound_nms
-       ; (spec_inst_prags', sip_fvs) <- renameSigs sig_ctxt spec_inst_prags
-       ; (other_sigs',      sig_fvs) <- bindLocalNamesFV ktv_names $
-                                        renameSigs sig_ctxt other_sigs
+       ; (spec_prags', spg_fvs) <- renameSigs sig_ctxt spec_prags
+       ; (other_sigs', sig_fvs) <- bindLocalNamesFV ktv_names $
+                                      renameSigs sig_ctxt other_sigs
 
        -- Rename the bindings RHSs.  Again there's an issue about whether the
        -- type variables from the class/instance head are in scope.
@@ -914,8 +912,47 @@ rnMethodBinds is_cls_decl cls ktv_names binds sigs
                                            emptyFVs binds_w_dus
                  ; return (mapBag fstOf3 binds_w_dus, bind_fvs) }
 
-       ; return ( binds'', spec_inst_prags' ++ other_sigs'
-                , sig_fvs `plusFV` sip_fvs `plusFV` bind_fvs) }
+       ; return ( binds'', spec_prags' ++ other_sigs'
+                , sig_fvs `plusFV` spg_fvs `plusFV` bind_fvs) }
+
+{- Note [Type variable scoping in SPECIALISE pragmas]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+When renaming the methods of a class or instance declaration, we must be careful
+with the scoping of the type variables that occur in SPECIALISE and SPECIALISE instance
+pragmas: the type variables from the class/instance header DO NOT scope over these,
+unlike class/instance method type signatures.
+
+Examples:
+
+  1. SPECIALISE
+
+    class C a where
+      meth :: a
+    instance C (Maybe a) where
+      meth = Nothing
+      {-# SPECIALISE INLINE meth :: Maybe [a] #-}
+
+  2. SPECIALISE instance
+
+    instance Eq a => Eq (T a) where
+       (==) :: a -> a -> a
+       {-# SPECIALISE instance Eq a => Eq (T [a]) #-}
+
+  In both cases, the type variable `a` mentioned in the PRAGMA is NOT the same
+  as the type variable `a` from the instance header.
+  For example, the SPECIALISE instance pragma above is a shorthand for
+
+      {-# SPECIALISE instance forall a. Eq a => Eq (T [a]) #-}
+
+  which is alpha-equivalent to
+
+      {-# SPECIALISE instance forall b. Eq b => Eq (T [b]) #-}
+
+  This shows that the type variables are not bound in the header.
+
+  Getting this scoping wrong can lead to out-of-scope type variable errors from
+  Core Lint, see e.g. #22913.
+-}
 
 rnMethodBindLHS :: Bool -> Name
                 -> LHsBindLR GhcPs GhcPs


=====================================
testsuite/tests/rename/should_compile/T22913.hs
=====================================
@@ -0,0 +1,10 @@
+module T22913 where
+
+class FromSourceIO a where
+    fromSourceIO :: a
+instance FromSourceIO (Maybe o) where
+    fromSourceIO = undefined
+    {-# SPECIALISE INLINE fromSourceIO :: Maybe o #-}
+ -- This SPECIALISE pragma caused a Core Lint error
+ -- due to incorrectly scoping the type variable 'o' from the instance header
+ -- over the SPECIALISE pragma.


=====================================
testsuite/tests/rename/should_compile/all.T
=====================================
@@ -199,3 +199,4 @@ test('T22513f', normal, compile, ['-Wterm-variable-capture'])
 test('T22513g', normal, compile, ['-Wterm-variable-capture'])
 test('T22513h', normal, compile, ['-Wterm-variable-capture'])
 test('T22513i', req_th, compile, ['-Wterm-variable-capture'])
+test('T22913', normal, compile, [''])



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9ee761bf02cdd11c955454a222c85971d95dce11

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9ee761bf02cdd11c955454a222c85971d95dce11
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/20230208/28cef7f5/attachment-0001.html>


More information about the ghc-commits mailing list