diff --git a/compiler/typecheck/TcDeriv.hs b/compiler/typecheck/TcDeriv.hs index a93712c8b232f9d4e4055a678f473b9791a047d3..f15c00324e8b43c80466fc0614d1caef639db317 100644 --- a/compiler/typecheck/TcDeriv.hs +++ b/compiler/typecheck/TcDeriv.hs @@ -26,6 +26,7 @@ import TcValidity( allDistinctTyVars ) import TcClassDcl( instDeclCtxt3, tcATDefault, tcMkDeclCtxt ) import TcEnv import TcGenDeriv -- Deriv stuff +import TcValidity import InstEnv import Inst import FamInstEnv @@ -742,8 +743,9 @@ deriveTyData tvs tc tc_args deriv_strat deriv_pred ; traceTc "derivTyData2" (vcat [ ppr tkvs ]) + ; let final_tc_app = mkTyConApp tc final_tc_args ; checkTc (allDistinctTyVars (mkVarSet tkvs) args_to_drop) -- (a, b, c) - (derivingEtaErr cls final_cls_tys (mkTyConApp tc final_tc_args)) + (derivingEtaErr cls final_cls_tys final_tc_app) -- Check that -- (a) The args to drop are all type variables; eg reject: -- data instance T a Int = .... deriving( Monad ) @@ -759,6 +761,11 @@ deriveTyData tvs tc tc_args deriv_strat deriv_pred -- expand any type synonyms. -- See Note [Eta-reducing type synonyms] + ; checkValidInstHead DerivClauseCtxt cls $ + final_cls_tys ++ [final_tc_app] + -- Check that we aren't deriving an instance of a magical + -- type like (~) or Coercible (#14916). + ; spec <- mkEqnHelp Nothing tkvs cls final_cls_tys tc final_tc_args Nothing deriv_strat diff --git a/compiler/typecheck/TcType.hs b/compiler/typecheck/TcType.hs index ba3cd6f53e34ddc6b3c5601a0c73f3f3d23b35cf..f6343da6fd11fd4aaaad2905d98749f2dce319d8 100644 --- a/compiler/typecheck/TcType.hs +++ b/compiler/typecheck/TcType.hs @@ -617,6 +617,7 @@ data UserTypeCtxt -- f :: <S> => a -> a | DataTyCtxt Name -- The "stupid theta" part of a data decl -- data <S> => T a = MkT a + | DerivClauseCtxt -- A 'deriving' clause {- -- Notes re TySynCtxt @@ -652,6 +653,7 @@ pprUserTypeCtxt (ClassSCCtxt c) = text "the super-classes of class" <+> quotes pprUserTypeCtxt SigmaCtxt = text "the context of a polymorphic type" pprUserTypeCtxt (DataTyCtxt tc) = text "the context of the data type declaration for" <+> quotes (ppr tc) pprUserTypeCtxt (PatSynCtxt n) = text "the signature for pattern synonym" <+> quotes (ppr n) +pprUserTypeCtxt (DerivClauseCtxt) = text "a `deriving' clause" isSigMaybe :: UserTypeCtxt -> Maybe Name isSigMaybe (FunSigCtxt n _) = Just n diff --git a/compiler/typecheck/TcValidity.hs b/compiler/typecheck/TcValidity.hs index 8c01460f2e43d7079c673ee205e20ffd89f0ac0f..6b3b24d373de87bd013b4014a23fc9c9c9574fd1 100644 --- a/compiler/typecheck/TcValidity.hs +++ b/compiler/typecheck/TcValidity.hs @@ -9,7 +9,7 @@ module TcValidity ( Rank, UserTypeCtxt(..), checkValidType, checkValidMonoType, ContextKind(..), expectedKindInCtxt, checkValidTheta, checkValidFamPats, - checkValidInstance, validDerivPred, + checkValidInstance, checkValidInstHead, validDerivPred, checkInstTermination, checkTySynRhs, ClsInstInfo, checkValidCoAxiom, checkValidCoAxBranch, checkValidTyFamEqn, @@ -915,6 +915,7 @@ okIPCtxt (InstDeclCtxt {}) = False okIPCtxt (SpecInstCtxt {}) = False okIPCtxt (RuleSigCtxt {}) = False okIPCtxt DefaultDeclCtxt = False +okIPCtxt DerivClauseCtxt = False {- Note [Kind polymorphic type classes] @@ -1044,9 +1045,9 @@ checkValidInstHead ctxt clas cls_args checkHasFieldInst clas cls_args -- Check language restrictions; - -- but not for SPECIALISE instance pragmas + -- but not for SPECIALISE instance pragmas or deriving clauses ; let ty_args = filterOutInvisibleTypes (classTyCon clas) cls_args - ; unless spec_inst_prag $ + ; unless (spec_inst_prag || deriv_clause) $ do { checkTc (xopt LangExt.TypeSynonymInstances dflags || all tcInstHeadTyNotSynonym ty_args) (instTypeErr clas cls_args head_type_synonym_msg) @@ -1062,6 +1063,7 @@ checkValidInstHead ctxt clas cls_args ; mapM_ checkValidTypePat ty_args } where spec_inst_prag = case ctxt of { SpecInstCtxt -> True; _ -> False } + deriv_clause = case ctxt of { DerivClauseCtxt -> True; _ -> False } head_type_synonym_msg = parens ( text "All instance types must be of the form (T t1 ... tn)" $$ diff --git a/testsuite/tests/deriving/should_fail/T14916.hs b/testsuite/tests/deriving/should_fail/T14916.hs new file mode 100644 index 0000000000000000000000000000000000000000..19b323fc6dd562eb8437db1b0f8806776e5bbb86 --- /dev/null +++ b/testsuite/tests/deriving/should_fail/T14916.hs @@ -0,0 +1,8 @@ +{-# LANGUAGE DeriveAnyClass #-} +module T14916 where + +import Data.Coerce +import Data.Typeable + +data A = MkA deriving ((~) A) +data B = MkB deriving (Coercible B) diff --git a/testsuite/tests/deriving/should_fail/T14916.stderr b/testsuite/tests/deriving/should_fail/T14916.stderr new file mode 100644 index 0000000000000000000000000000000000000000..2a6cca187d728fc08c70b31fcdcf0eff9f5c5959 --- /dev/null +++ b/testsuite/tests/deriving/should_fail/T14916.stderr @@ -0,0 +1,10 @@ + +T14916.hs:7:24: error: + • Illegal instance declaration for ‘A ~ A’ + Manual instances of this class are not permitted. + • In the data declaration for ‘A’ + +T14916.hs:8:24: error: + • Illegal instance declaration for ‘Coercible B B’ + Manual instances of this class are not permitted. + • In the data declaration for ‘B’ diff --git a/testsuite/tests/deriving/should_fail/all.T b/testsuite/tests/deriving/should_fail/all.T index acd348691877f244565645e2390570d99cacf491..8dc5b780afa839e5f4a6704f66ce746a763ceb17 100644 --- a/testsuite/tests/deriving/should_fail/all.T +++ b/testsuite/tests/deriving/should_fail/all.T @@ -71,3 +71,4 @@ test('T14365', [extra_files(['T14365B.hs','T14365B.hs-boot'])], multimod_compile_fail, ['T14365A','']) test('T14728a', normal, compile_fail, ['']) test('T14728b', normal, compile_fail, ['']) +test('T14916', normal, compile_fail, [''])