[Git][ghc/ghc][master] Use unsatisfiable for missing methods w/ defaults
Marge Bot (@marge-bot)
gitlab at gitlab.haskell.org
Thu Aug 17 11:55:17 UTC 2023
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
a975c663 by sheaf at 2023-08-17T07:54:47-04:00
Use unsatisfiable for missing methods w/ defaults
When a class instance has an Unsatisfiable constraint in its context
and the user has not explicitly provided an implementation of a method,
we now always provide a RHS of the form `unsatisfiable @msg`, even
if the method has a default definition available. This ensures that,
when deferring type errors, users get the appropriate error message
instead of a possible runtime loop, if class default methods were
defined recursively.
Fixes #23816
- - - - -
5 changed files:
- compiler/GHC/Tc/Errors.hs
- compiler/GHC/Tc/TyCl/Instance.hs
- + testsuite/tests/unsatisfiable/T23816.hs
- + testsuite/tests/unsatisfiable/T23816.stderr
- testsuite/tests/unsatisfiable/all.T
Changes:
=====================================
compiler/GHC/Tc/Errors.hs
=====================================
@@ -891,8 +891,8 @@ Its implementation consists of the following:
D. Adding "meth = unsatisfiable @msg" method bindings.
When a class instance has an "Unsatisfiable msg" constraint in its context,
- and the user has omitted methods (which don't have any default implementations),
- we add method bindings of the form "meth = unsatisfiable @msg".
+ and the user has omitted methods, we add method bindings of the form
+ "meth = unsatisfiable @msg".
See GHC.Tc.TyCl.Instance.tcMethods, in particular "tc_default".
Example:
@@ -909,6 +909,10 @@ Its implementation consists of the following:
We also switch off the "missing methods" warning in this situation.
See "checkMinimalDefinition" in GHC.Tc.TyCl.Instance.tcMethods.
+ Note that we do this even when there is a default method available. This
+ ensures we run into the unsatisfiable error message when deferring type
+ errors; otherwise we could end up with a runtime loop as seen in #23816.
+
E. Switching off functional dependency coverage checks when there is
an "Unsatisfiable msg" context.
=====================================
compiler/GHC/Tc/TyCl/Instance.hs
=====================================
@@ -6,7 +6,6 @@
{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeFamilies #-}
@@ -1835,46 +1834,51 @@ tcMethods skol_info dfun_id clas tyvars dfun_ev_vars inst_tys
tc_default :: Id -> DefMethInfo
-> TcM (TcId, LHsBind GhcTc, Maybe Implication)
- tc_default sel_id (Just (dm_name, _))
- = do { (meth_bind, inline_prags) <- mkDefMethBind inst_loc dfun_id clas sel_id dm_name
+ tc_default sel_id mb_dm = case mb_dm of
+
+ -- If the instance has an "Unsatisfiable msg" context,
+ -- add method bindings that use "unsatisfiable".
+ --
+ -- See Note [Implementation of Unsatisfiable constraints],
+ -- in GHC.Tc.Errors, point (D).
+ _ | (theta_id,unsat_msg) : _ <- unsat_thetas
+ -> do { (meth_id, _) <- mkMethIds clas tyvars dfun_ev_vars
+ inst_tys sel_id
+ ; unsat_id <- tcLookupId unsatisfiableIdName
+ -- Recall that unsatisfiable :: forall {rep} (msg :: ErrorMessage) (a :: TYPE rep). Unsatisfiable msg => a
+ --
+ -- So we need to instantiate the forall and pass the dictionary evidence.
+ ; let meth_rhs = L inst_loc' $
+ wrapId
+ ( mkWpEvApps [EvExpr $ Var theta_id]
+ <.> mkWpTyApps [getRuntimeRep meth_tau, unsat_msg, meth_tau])
+ unsat_id
+ meth_bind = mkVarBind meth_id $ mkLHsWrap lam_wrapper meth_rhs
+ ; return (meth_id, meth_bind, Nothing) }
+
+ Just (dm_name, _) ->
+ do { (meth_bind, inline_prags) <- mkDefMethBind inst_loc dfun_id clas sel_id dm_name
; tcMethodBody skol_info clas tyvars dfun_ev_vars inst_tys
dfun_ev_binds is_derived hs_sig_fn
spec_inst_prags inline_prags
sel_id meth_bind inst_loc }
- tc_default sel_id Nothing -- No default method at all
- = do { traceTc "tc_def: warn" (ppr sel_id)
+ -- No default method
+ Nothing ->
+ do { traceTc "tc_def: warn" (ppr sel_id)
; (meth_id, _) <- mkMethIds clas tyvars dfun_ev_vars
inst_tys sel_id
; dflags <- getDynFlags
- ; meth_rhs <-
- if
- -- If the instance has an "Unsatisfiable msg" context,
- -- add method bindings that use "unsatisfiable".
- --
- -- See Note [Implementation of Unsatisfiable constraints],
- -- in GHC.Tc.Errors, point (D).
- | (theta_id,unsat_msg):_ <- unsat_thetas
- -> do { unsat_id <- tcLookupId unsatisfiableIdName
- -- Recall that unsatisfiable :: forall {rep} (msg :: ErrorMessage) (a :: TYPE rep). Unsatisfiable msg => a
- --
- -- So we need to instantiate the forall and pass the dictionary evidence.
- ; return $ L inst_loc' $
- wrapId
- ( mkWpEvApps [EvExpr $ Var theta_id]
- <.> mkWpTyApps [getRuntimeRep meth_tau, unsat_msg, meth_tau])
- unsat_id }
-
- -- Otherwise, add bindings whose RHS is an error
- -- "No explicit nor default method for class operation 'meth'".
- | otherwise
- -> return $ error_rhs dflags
- ; let meth_bind = mkVarBind meth_id $ mkLHsWrap lam_wrapper meth_rhs
+ -- Add a binding whose RHS is an error
+ -- "No explicit nor default method for class operation 'meth'".
+ ; let meth_rhs = error_rhs dflags
+ meth_bind = mkVarBind meth_id $ mkLHsWrap lam_wrapper meth_rhs
; return (meth_id, meth_bind, Nothing) }
+
where
inst_loc' = noAnnSrcSpan inst_loc
error_rhs dflags = L inst_loc'
- $ HsApp noComments error_fun (error_msg dflags)
+ $ HsApp noComments error_fun (error_msg dflags)
error_fun = L inst_loc' $
wrapId (mkWpTyApps
[ getRuntimeRep meth_tau, meth_tau])
=====================================
testsuite/tests/unsatisfiable/T23816.hs
=====================================
@@ -0,0 +1,18 @@
+{-# LANGUAGE DataKinds #-}
+
+module Main where
+
+import GHC.TypeError
+
+class C a where
+ meth1 :: a -> Bool
+ meth2 :: a -> Bool
+
+ meth1 = not . meth2
+ meth2 = not . meth1
+ {-# MINIMAL meth1 | meth2 #-}
+
+instance Unsatisfiable (Text "Msg") => C a
+
+main :: IO ()
+main = print (meth1 'x')
=====================================
testsuite/tests/unsatisfiable/T23816.stderr
=====================================
@@ -0,0 +1,6 @@
+T23816.exe: T23816.hs:18:15: error: [GHC-22250]
+ • Msg
+ • In the first argument of ‘print’, namely ‘(meth1 'x')’
+ In the expression: print (meth1 'x')
+ In an equation for ‘main’: main = print (meth1 'x')
+(deferred type error)
=====================================
testsuite/tests/unsatisfiable/all.T
=====================================
@@ -17,3 +17,5 @@ test('T11503_Unsat', normal, compile, ['-Woverlapping-patterns -Wincomplete-patt
test('T14141_Unsat', normal, compile, ['-Woverlapping-patterns -Wincomplete-patterns'])
test('T14339_Unsat', normal, compile_fail, [''])
test('T15232_Unsat', normal, compile, ['-Wredundant-constraints'])
+
+test('T23816', exit_code(1), compile_and_run, ['-fdefer-type-errors'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/a975c6634b0d202b21e0e719efb9900e44f85392
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/a975c6634b0d202b21e0e719efb9900e44f85392
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/20230817/598d188a/attachment-0001.html>
More information about the ghc-commits
mailing list