[Git][ghc/ghc][wip/sand-witch/fix-tysyn] Fix compiler crash caused by implicit RHS quantification in type synonyms (#24470)
Andrei Borzenkov (@sand-witch)
gitlab at gitlab.haskell.org
Mon Mar 11 15:36:12 UTC 2024
Andrei Borzenkov pushed to branch wip/sand-witch/fix-tysyn at Glasgow Haskell Compiler / GHC
Commits:
283f257f by Andrei Borzenkov at 2024-03-11T19:35:59+04:00
Fix compiler crash caused by implicit RHS quantification in type synonyms (#24470)
- - - - -
9 changed files:
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Errors/Types.hs
- compiler/GHC/Tc/Gen/HsType.hs
- compiler/GHC/Types/Error/Codes.hs
- + testsuite/tests/typecheck/should_compile/T24470b.hs
- testsuite/tests/typecheck/should_compile/all.T
- + testsuite/tests/typecheck/should_fail/T24470a.hs
- + testsuite/tests/typecheck/should_fail/T24470a.stderr
- testsuite/tests/typecheck/should_fail/all.T
Changes:
=====================================
compiler/GHC/Tc/Errors/Ppr.hs
=====================================
@@ -1922,6 +1922,18 @@ instance Diagnostic TcRnMessage where
, text "in a fixity signature"
]
+ TcRnOutOfArityTyVar ts_name tv_name -> mkDecorated
+ [ vcat [ text "The arity of" <+> quotes (ppr ts_name) <+> text "is insufficiently high to accommodate"
+ , text "an implicit binding for the" <+> quotes (ppr tv_name) <+> text "type variable." ]
+ , suggestion ]
+ where
+ suggestion =
+ text "Use" <+> quotes at_bndr <+> text "on the LHS" <+>
+ text "or" <+> quotes forall_bndr <+> text "on the RHS" <+>
+ text "to bring it into scope."
+ at_bndr = char '@' <> ppr tv_name
+ forall_bndr = text "forall" <+> ppr tv_name <> text "."
+
diagnosticReason :: TcRnMessage -> DiagnosticReason
diagnosticReason = \case
TcRnUnknownMessage m
@@ -2556,6 +2568,8 @@ instance Diagnostic TcRnMessage where
-> ErrorWithoutFlag
TcRnNamespacedFixitySigWithoutFlag{}
-> ErrorWithoutFlag
+ TcRnOutOfArityTyVar{}
+ -> ErrorWithoutFlag
diagnosticHints = \case
TcRnUnknownMessage m
@@ -3224,6 +3238,8 @@ instance Diagnostic TcRnMessage where
-> noHints
TcRnNamespacedFixitySigWithoutFlag{}
-> [suggestExtension LangExt.ExplicitNamespaces]
+ TcRnOutOfArityTyVar{}
+ -> noHints
diagnosticCode = constructorCode
=====================================
compiler/GHC/Tc/Errors/Types.hs
=====================================
@@ -2272,6 +2272,8 @@ data TcRnMessage where
where the implicitly-bound type type variables can't be matched up unambiguously
with the ones from the signature. See Note [Disconnected type variables] in
GHC.Tc.Gen.HsType.
+
+ Test cases: T24083
-}
TcRnDisconnectedTyVar :: !Name -> TcRnMessage
@@ -4267,6 +4269,24 @@ data TcRnMessage where
-}
TcRnDefaultedExceptionContext :: CtLoc -> TcRnMessage
+ {-| TcRnOutOfArityTyVar is an error raised when the arity of a type synonym
+ (as determined by the SAKS and the LHS) is insufficiently high to
+ accommodate an implicit binding for a free variable that occurs in the
+ outermost kind signature on the RHS of the said type synonym.
+
+ Example:
+
+ type SynBad :: forall k. k -> Type
+ type SynBad = Proxy :: j -> Type
+
+ Test cases:
+ T24770a
+ -}
+ TcRnOutOfArityTyVar
+ :: Name -- ^ Type synonym's name
+ -> Name -- ^ Type variable's name
+ -> TcRnMessage
+
deriving Generic
----
=====================================
compiler/GHC/Tc/Gen/HsType.hs
=====================================
@@ -2617,7 +2617,7 @@ kcCheckDeclHeader_sig sig_kind name flav
; implicit_tvs <- liftZonkM $ zonkTcTyVarsToTcTyVars implicit_tvs
; let implicit_prs = implicit_nms `zip` implicit_tvs
; checkForDuplicateScopedTyVars implicit_prs
- ; checkForDisconnectedScopedTyVars flav all_tcbs implicit_prs
+ ; checkForDisconnectedScopedTyVars name flav all_tcbs implicit_prs
-- Swizzle the Names so that the TyCon uses the user-declared implicit names
-- E.g type T :: k -> Type
@@ -2978,25 +2978,32 @@ expectedKindInCtxt _ = OpenKind
* *
********************************************************************* -}
-checkForDisconnectedScopedTyVars :: TyConFlavour TyCon -> [TcTyConBinder]
+checkForDisconnectedScopedTyVars :: Name -> TyConFlavour TyCon -> [TcTyConBinder]
-> [(Name,TcTyVar)] -> TcM ()
-- See Note [Disconnected type variables]
+-- For the type synonym case see Note [Out of arity type variables]
-- `scoped_prs` is the mapping gotten by unifying
-- - the standalone kind signature for T, with
-- - the header of the type/class declaration for T
-checkForDisconnectedScopedTyVars flav sig_tcbs scoped_prs
- = when (needsEtaExpansion flav) $
+checkForDisconnectedScopedTyVars name flav all_tcbs scoped_prs
-- needsEtaExpansion: see wrinkle (DTV1) in Note [Disconnected type variables]
- mapM_ report_disconnected (filterOut ok scoped_prs)
+ | needsEtaExpansion flav = mapM_ report_disconnected (filterOut ok scoped_prs)
+ | flav == TypeSynonymFlavour = mapM_ report_out_of_arity (filterOut ok scoped_prs)
+ | otherwise = pure ()
where
- sig_tvs = mkVarSet (binderVars sig_tcbs)
- ok (_, tc_tv) = tc_tv `elemVarSet` sig_tvs
+ all_tvs = mkVarSet (binderVars all_tcbs)
+ ok (_, tc_tv) = tc_tv `elemVarSet` all_tvs
report_disconnected :: (Name,TcTyVar) -> TcM ()
report_disconnected (nm, _)
= setSrcSpan (getSrcSpan nm) $
addErrTc $ TcRnDisconnectedTyVar nm
+ report_out_of_arity :: (Name,TcTyVar) -> TcM ()
+ report_out_of_arity (tv_nm, _)
+ = setSrcSpan (getSrcSpan tv_nm) $
+ addErrTc $ TcRnOutOfArityTyVar name tv_nm
+
checkForDuplicateScopedTyVars :: [(Name,TcTyVar)] -> TcM ()
-- Check for duplicates
-- E.g. data SameKind (a::k) (b::k)
@@ -3083,6 +3090,63 @@ explicitly, rather than binding it implicitly via unification.
The scoped-tyvar stuff is needed precisely for data/class/newtype declarations,
where needsEtaExpansion is True.
+
+Note [Out of arity type variables]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+(Relevant ticket: #24470)
+Type synonyms have a special scoping rule that allows implicit quantification in
+the outermost kind signature:
+
+ type P_e :: k -> Type
+ type P_e @k = Proxy :: k -> Type -- explicit binding
+
+ type P_i = Proxy :: k -> Type -- implicit binding (relies on the special rule)
+
+This is a deprecated feature (warning flag: -Wimplicit-rhs-quantification) but
+we have to support it for a couple more releases. It is explained in more detail
+in Note [Implicit quantification in type synonyms] in GHC.Rename.HsType.
+
+Type synonyms `P_e` and `P_i` are equivalent. Both of them have kind
+`forall k. k -> Type` and arity 1. (Recall that the arity of a type synonym is
+the number of arguments it requires at use sites; the arity matter because
+unsaturated application of type families and type synonyms is not allowed).
+
+We start to see problems when implicit RHS quantification (as in `P_i`) is
+combined with a standalone king signature (like the one that `P_e` has).
+That is:
+
+ type P_i_sig :: k -> Type
+ type P_i_sig = Proxy :: k -> Type
+
+Per GHC Proposal #425, the arity of `P_i_sig` is determined /by the LHS only/,
+which has no binders. So the arity of `P_i_sig` is 0.
+At the same time, the legacy implicit quantification rule dictates that `k` is
+brought into scope, as if there was a binder `@k` on the LHS.
+
+We end up with a `k` that is in scope on the RHS but cannot be bound implicitly
+on the LHS without affecting the arity. This led to #24470 (a compiler crash)
+
+ GHC internal error: ‘k’ is not in scope during type checking,
+ but it passed the renamer
+
+This problem occurs only if the arity of the type synonym is insufficiently
+high to accommodate an implicit binding. It can be worked around by adding an
+unused binder on the LHS:
+
+ type P_w :: k -> Type
+ type P_w @_w = Proxy :: k -> Type
+
+The variable `_w` is unused. The only effect of the `@_w` binder is that the
+arity of `P_w` is changed from 0 to 1. However, bumping the arity is exactly
+what's needed to make the implicit binding of `k` possible.
+
+All this is a rather unfortunate bit of accidental complexity that will go away
+when GHC drops support for implicit RHS quantification. In the meantime, we
+ought to produce a proper error message instead of a compiler panic, and we do
+that with a check in checkForDisconnectedScopedTyVars:
+
+ | flav == TypeSynonymFlavour = mapM_ report_out_of_arity (filterOut ok scoped_prs)
+
-}
{- *********************************************************************
=====================================
compiler/GHC/Types/Error/Codes.hs
=====================================
@@ -606,6 +606,7 @@ type family GhcDiagnosticCode c = n | n -> c where
GhcDiagnosticCode "TcRnInvisPatWithNoForAll" = 14964
GhcDiagnosticCode "TcRnIllegalInvisibleTypePattern" = 78249
GhcDiagnosticCode "TcRnNamespacedFixitySigWithoutFlag" = 78534
+ GhcDiagnosticCode "TcRnOutOfArityTyVar" = 84925
-- TcRnTypeApplicationsDisabled
GhcDiagnosticCode "TypeApplication" = 23482
=====================================
testsuite/tests/typecheck/should_compile/T24470b.hs
=====================================
@@ -0,0 +1,10 @@
+{-# OPTIONS_GHC -Wno-implicit-rhs-quantification #-}
+{-# LANGUAGE TypeAbstractions #-}
+
+module T24470b where
+
+import Data.Kind
+import Data.Data
+
+type SynOK :: forall k. k -> Type
+type SynOK @t = Proxy :: j -> Type
=====================================
testsuite/tests/typecheck/should_compile/all.T
=====================================
@@ -912,3 +912,4 @@ test('T21206', normal, compile, [''])
test('T17594a', req_th, compile, [''])
test('T17594f', normal, compile, [''])
test('WarnDefaultedExceptionContext', normal, compile, ['-Wdefaulted-exception-context'])
+test('T24470b', normal, compile, [''])
=====================================
testsuite/tests/typecheck/should_fail/T24470a.hs
=====================================
@@ -0,0 +1,7 @@
+module T24470a where
+
+import Data.Data
+import Data.Kind
+
+type SynBad :: forall k. k -> Type
+type SynBad = Proxy :: j -> Type
=====================================
testsuite/tests/typecheck/should_fail/T24470a.stderr
=====================================
@@ -0,0 +1,6 @@
+
+T24470a.hs:7:24: error: [GHC-84925]
+ • The arity of ‘SynBad’ is insufficiently high to accommodate
+ an implicit binding for the ‘j’ type variable.
+ • Use ‘@j’ on the LHS or ‘forall j.’ on the RHS to bring it into scope.
+ • In the type synonym declaration for ‘SynBad’
=====================================
testsuite/tests/typecheck/should_fail/all.T
=====================================
@@ -722,3 +722,5 @@ test('DoExpansion3', normal, compile, ['-fdefer-type-errors'])
test('T17594c', normal, compile_fail, [''])
test('T17594d', normal, compile_fail, [''])
test('T17594g', normal, compile_fail, [''])
+
+test('T24470a', normal, compile_fail, [''])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/283f257f45b11e3824ff7d7bd3fe1ae6881c713a
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/283f257f45b11e3824ff7d7bd3fe1ae6881c713a
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/20240311/3db216f7/attachment-0001.html>
More information about the ghc-commits
mailing list