summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorRichard Eisenberg <rae@richarde.dev>2023-01-30 17:39:18 -0500
committerMarge Bot <ben+marge-bot@smart-cactus.org>2023-03-02 22:42:06 -0500
commit1ed573a53ee454db240b9fb1a17e28c97b6eb53a (patch)
tree239eae7a0faf92661ea2c3c17bb712c79d26a6f7 /compiler
parent86f240ca956f633c20a61872ec44de9e21266624 (diff)
downloadhaskell-1ed573a53ee454db240b9fb1a17e28c97b6eb53a.tar.gz
Don't suppress *all* Wanteds
Code in GHC.Tc.Errors.reportWanteds suppresses a Wanted if its rewriters have unfilled coercion holes; see Note [Wanteds rewrite Wanteds] in GHC.Tc.Types.Constraint. But if we thereby suppress *all* errors that's really confusing, and as #22707 shows, GHC goes on without even realising that the program is broken. Disaster. This MR arranges to un-suppress them all if they all get suppressed. Close #22707
Diffstat (limited to 'compiler')
-rw-r--r--compiler/GHC/Tc/Errors.hs33
-rw-r--r--compiler/GHC/Tc/Types/Constraint.hs8
2 files changed, 24 insertions, 17 deletions
diff --git a/compiler/GHC/Tc/Errors.hs b/compiler/GHC/Tc/Errors.hs
index 356d36e0ab..3816f31ddd 100644
--- a/compiler/GHC/Tc/Errors.hs
+++ b/compiler/GHC/Tc/Errors.hs
@@ -476,30 +476,37 @@ mkErrorItem ct
, ei_m_reason = m_reason
, ei_suppress = suppress }}
+-- | Actually report this 'ErrorItem'.
+unsuppressErrorItem :: ErrorItem -> ErrorItem
+unsuppressErrorItem ei = ei { ei_suppress = False }
+
----------------------------------------------------------------
reportWanteds :: SolverReportErrCtxt -> TcLevel -> WantedConstraints -> TcM ()
reportWanteds ctxt tc_lvl wc@(WC { wc_simple = simples, wc_impl = implics
, wc_errors = errs })
| isEmptyWC wc = traceTc "reportWanteds empty WC" empty
| otherwise
- = do { tidy_items <- mapMaybeM mkErrorItem tidy_cts
+ = do { tidy_items1 <- mapMaybeM mkErrorItem tidy_cts
; traceTc "reportWanteds 1" (vcat [ text "Simples =" <+> ppr simples
, text "Suppress =" <+> ppr (cec_suppress ctxt)
, text "tidy_cts =" <+> ppr tidy_cts
- , text "tidy_items =" <+> ppr tidy_items
+ , text "tidy_items1 =" <+> ppr tidy_items1
, text "tidy_errs =" <+> ppr tidy_errs ])
- -- This check makes sure that we aren't suppressing the only error that will
- -- actually stop compilation
- ; assertPprM
- ( do { errs_already <- ifErrsM (return True) (return False)
- ; return $
- errs_already || -- we already reported an error (perhaps from an outer implication)
- null simples || -- no errors to report here
- any ignoreConstraint simples || -- one error is ignorable (is reported elsewhere)
- not (all ei_suppress tidy_items) -- not all errors are suppressed
- } )
- (vcat [text "reportWanteds is suppressing all errors"])
+ -- Catch an awkward case in which /all/ errors are suppressed:
+ -- see Wrinkle at end of Note [Wanteds rewrite Wanteds] in GHC.Tc.Types.Constraint
+ -- Unless we are sure that an error will be reported some other way (details
+ -- in the defn of tidy_items) un-suppress the lot. This makes sure we don't forget to
+ -- report an error at all, which is catastrophic: GHC proceeds to desguar and optimise
+ -- the program, even though it is full of type errors (#22702, #22793)
+ ; errs_already <- ifErrsM (return True) (return False)
+ ; let tidy_items
+ | not errs_already -- Have not already reported an error (perhaps
+ -- from an outer implication); see #21405
+ , not (any ignoreConstraint simples) -- No error is ignorable (is reported elsewhere)
+ , all ei_suppress tidy_items1 -- All errors are suppressed
+ = map unsuppressErrorItem tidy_items1
+ | otherwise = tidy_items1
-- First, deal with any out-of-scope errors:
; let (out_of_scope, other_holes, not_conc_errs) = partition_errors tidy_errs
diff --git a/compiler/GHC/Tc/Types/Constraint.hs b/compiler/GHC/Tc/Types/Constraint.hs
index 0623acd3d5..bd66282b24 100644
--- a/compiler/GHC/Tc/Types/Constraint.hs
+++ b/compiler/GHC/Tc/Types/Constraint.hs
@@ -2127,10 +2127,10 @@ uses GHC.Tc.Utils.anyUnfilledCoercionHoles to look through any filled coercion
holes. The idea is that we wish to report the "root cause" -- the error that
rewrote all the others.
-Worry: It seems possible that *all* unsolved wanteds are rewritten by other
-unsolved wanteds, so that e.g. w1 has w2 in its rewriter set, and w2 has
-w1 in its rewiter set. We are unable to come up with an example of this in
-practice, however, and so we believe this case cannot happen.
+Wrinkle: In #22707, we have a case where all of the Wanteds have rewritten
+each other. In order to report /some/ error in this case, we simply report
+all the Wanteds. The user will get a perhaps-confusing error message, but
+they've written a confusing program!
Note [Avoiding rewriting cycles]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~