From e7db36c175520210e443fff89cb594beb179705c Mon Sep 17 00:00:00 2001 From: sheaf <sam.derbyshire@gmail.com> Date: Tue, 22 Aug 2023 13:29:29 +0200 Subject: [PATCH] Don't attempt pattern synonym error recovery This commit gets rid of the pattern synonym error recovery mechanism (recoverPSB). The rationale is that the fake pattern synonym binding that the recovery mechanism introduced could lead to undesirable knock-on errors, and it isn't really feasible to conjure up a satisfactory binding as pattern synonyms can be used both in expressions and patterns. See Note [Pattern synonym error recovery] in GHC.Tc.TyCl.PatSyn. It isn't such a big deal to eagerly fail compilation on a pattern synonym that doesn't typecheck anyway. Fixes #23467 --- compiler/GHC/Tc/TyCl/PatSyn.hs | 48 ++++++------------- testsuite/tests/patsyn/should_fail/T23467.hs | 12 +++++ .../tests/patsyn/should_fail/T23467.stderr | 5 ++ testsuite/tests/patsyn/should_fail/all.T | 1 + 4 files changed, 32 insertions(+), 34 deletions(-) create mode 100644 testsuite/tests/patsyn/should_fail/T23467.hs create mode 100644 testsuite/tests/patsyn/should_fail/T23467.stderr diff --git a/compiler/GHC/Tc/TyCl/PatSyn.hs b/compiler/GHC/Tc/TyCl/PatSyn.hs index 71e4b5f319bb..6e65c7eaa83d 100644 --- a/compiler/GHC/Tc/TyCl/PatSyn.hs +++ b/compiler/GHC/Tc/TyCl/PatSyn.hs @@ -41,7 +41,6 @@ import GHC.Core.Type ( typeKind, tidyForAllTyBinders, tidyTypes, tidyType, isMan import GHC.Core.TyCo.Subst( extendTvSubstWithClone ) import GHC.Core.Predicate -import GHC.Builtin.Types.Prim import GHC.Types.Name import GHC.Types.Name.Set import GHC.Types.SrcLoc @@ -86,36 +85,12 @@ tcPatSynDecl (L loc psb@(PSB { psb_id = L _ name })) sig_fn prag_fn = setSrcSpanA loc $ addErrCtxt (text "In the declaration for pattern synonym" <+> quotes (ppr name)) $ - recoverM (recoverPSB psb) $ - case (sig_fn name) of + -- See Note [Pattern synonym error recovery] + case sig_fn name of Nothing -> tcInferPatSynDecl psb prag_fn Just (TcPatSynSig tpsi) -> tcCheckPatSynDecl psb tpsi prag_fn _ -> panic "tcPatSynDecl" -recoverPSB :: PatSynBind GhcRn GhcRn - -> TcM (LHsBinds GhcTc, TcGblEnv) --- See Note [Pattern synonym error recovery] -recoverPSB (PSB { psb_id = L _ name - , psb_args = details }) - = do { matcher_name <- newImplicitBinder name mkMatcherOcc - ; let placeholder = AConLike $ PatSynCon $ - mk_placeholder matcher_name - ; gbl_env <- tcExtendGlobalEnv [placeholder] getGblEnv - ; return (emptyBag, gbl_env) } - where - (_arg_names, is_infix) = collectPatSynArgInfo details - mk_placeholder matcher_name - = mkPatSyn name is_infix - ([mkTyVarBinder SpecifiedSpec alphaTyVar], []) ([], []) - [] -- Arg tys - alphaTy - (matcher_name, matcher_ty, True) Nothing - [] -- Field labels - where - -- The matcher_id is used only by the desugarer, so actually - -- and error-thunk would probably do just as well here. - matcher_ty = mkSpecForAllTys [alphaTyVar] alphaTy - {- Note [Pattern synonym error recovery] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If type inference for a pattern synonym fails, we can't continue with @@ -134,14 +109,19 @@ reporting no end (#15685). So we use simplifyTop to completely solve the constraint, report any errors, throw an exception. -Even in the event of such an error we can recover and carry on, just -as we do for value bindings, provided we plug in placeholder for the -pattern synonym: see recoverPSB. The goal of the placeholder is not -to cause a raft of follow-on errors. I've used the simplest thing for -now, but we might need to elaborate it a bit later. (e.g. I've given -it zero args, which may cause knock-on errors if it is used in a -pattern.) But it'll do for now. +Unlike for value bindings, we don't create a placeholder pattern +synonym binding in an attempt to recover from the error, as this placeholder +was occasionally the cause of strange follow-up errors to occur, as reported in #23467. +It seems rather difficult to come up with a satisfactory placeholder: + + - it would need to have the right number of arguments, + with the appropriate field names (if any), + - we could give each argument the type `forall a. a`; this would generally + work OK in pattern occurrences of the PatSyn, but not so in expressions, + e.g. "let x = Con y" would require (y :: forall a. a) which would cause + confusing errors. +So, for now at least, we don't attempt to recover at all. -} tcInferPatSynDecl :: PatSynBind GhcRn GhcRn diff --git a/testsuite/tests/patsyn/should_fail/T23467.hs b/testsuite/tests/patsyn/should_fail/T23467.hs new file mode 100644 index 000000000000..0f9275b1c08b --- /dev/null +++ b/testsuite/tests/patsyn/should_fail/T23467.hs @@ -0,0 +1,12 @@ +{-# LANGUAGE PatternSynonyms #-} + +module T23467 where + +data ConData = ConData { _pars :: Int } +data Decl = ConDecl ConData + +pattern Con :: Decl -- The correct type would be Int -> Decl +pattern Con { pars } = ConDecl (ConData pars) + +foo :: Decl -> Int +foo (Con { pars }) = pars diff --git a/testsuite/tests/patsyn/should_fail/T23467.stderr b/testsuite/tests/patsyn/should_fail/T23467.stderr new file mode 100644 index 000000000000..cad595e1d2ee --- /dev/null +++ b/testsuite/tests/patsyn/should_fail/T23467.stderr @@ -0,0 +1,5 @@ + +T23467.hs:9:1: error: [GHC-18365] + • Pattern synonym ‘Con’ has one argument + but its type signature has 1 fewer arrows + • In the declaration for pattern synonym ‘Con’ diff --git a/testsuite/tests/patsyn/should_fail/all.T b/testsuite/tests/patsyn/should_fail/all.T index 9879f2d9b0fa..4a8e419acbc9 100644 --- a/testsuite/tests/patsyn/should_fail/all.T +++ b/testsuite/tests/patsyn/should_fail/all.T @@ -48,3 +48,4 @@ test('T16900', normal, compile_fail, ['-fdiagnostics-show-caret']) test('T14552', normal, compile_fail, ['']) test('T18856', normal, compile_fail, ['-fdiagnostics-show-caret']) test('T21479', normal, compile_fail, ['']) +test('T23467', normal, compile_fail, ['']) -- GitLab