diff options
author | Ryan Scott <ryan.gl.scott@gmail.com> | 2017-08-17 10:07:03 -0400 |
---|---|---|
committer | Ryan Scott <ryan.gl.scott@gmail.com> | 2017-08-17 10:07:03 -0400 |
commit | 039fa1b994a8b0d6be25eb1bc711904db9661db2 (patch) | |
tree | 1ed9bec64b6aab32dbdcb4d13975424a86951ec9 /compiler | |
parent | 38260a9e9f8c38edd25f4b4c06e0ea5d88fc6bf2 (diff) | |
download | haskell-039fa1b994a8b0d6be25eb1bc711904db9661db2.tar.gz |
Suggest how to fix illegally nested foralls in GADT constructor type signatures
Summary:
Although the code from #12087 isn't accepted by GHC, we can at least
do a better job of letting users know what the problem is, and how to fix it.
Test Plan: make test TEST=T12087
Reviewers: goldfire, austin, bgamari
Reviewed By: goldfire
Subscribers: rwbarton, thomie
GHC Trac Issues: #12087
Differential Revision: https://phabricator.haskell.org/D3851
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/typecheck/TcTyClsDecls.hs | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/compiler/typecheck/TcTyClsDecls.hs b/compiler/typecheck/TcTyClsDecls.hs index ba35db5f3d..0974fe5b2d 100644 --- a/compiler/typecheck/TcTyClsDecls.hs +++ b/compiler/typecheck/TcTyClsDecls.hs @@ -3138,9 +3138,52 @@ noClassTyVarErr clas fam_tc badDataConTyCon :: DataCon -> Type -> Type -> SDoc badDataConTyCon data_con res_ty_tmpl actual_res_ty + | tcIsForAllTy actual_res_ty + = nested_foralls_contexts_suggestion + | isJust (tcSplitPredFunTy_maybe actual_res_ty) + = nested_foralls_contexts_suggestion + | otherwise = hang (text "Data constructor" <+> quotes (ppr data_con) <+> text "returns type" <+> quotes (ppr actual_res_ty)) 2 (text "instead of an instance of its parent type" <+> quotes (ppr res_ty_tmpl)) + where + -- This suggestion is useful for suggesting how to correct code like what + -- was reported in Trac #12087: + -- + -- data F a where + -- MkF :: Ord a => Eq a => a -> F a + -- + -- Although nested foralls or contexts are allowed in function type + -- signatures, it is much more difficult to engineer GADT constructor type + -- signatures to allow something similar, so we error in the latter case. + -- Nevertheless, we can at least suggest how a user might reshuffle their + -- exotic GADT constructor type signature so that GHC will accept. + nested_foralls_contexts_suggestion = + text "GADT constructor type signature cannot contain nested" + <+> quotes forAllLit <> text "s or contexts" + $+$ hang (text "Suggestion: instead use this type signature:") + 2 (ppr (dataConName data_con) <+> dcolon <+> ppr suggested_ty) + + -- To construct a type that GHC would accept (suggested_ty), we: + -- + -- 1) Find the existentially quantified type variables and the class + -- predicates from the datacon. (NB: We don't need the universally + -- quantified type variables, since rejigConRes won't substitute them in + -- the result type if it fails, as in this scenario.) + -- 2) Split apart the return type (which is headed by a forall or a + -- context) using tcSplitNestedSigmaTys, collecting the type variables + -- and class predicates we find, as well as the rho type lurking + -- underneath the nested foralls and contexts. + -- 3) Smash together the type variables and class predicates from 1) and + -- 2), and prepend them to the rho type from 2). + actual_ex_tvs = dataConExTyVarBinders data_con + actual_theta = dataConTheta data_con + (actual_res_tvs, actual_res_theta, actual_res_rho) + = tcSplitNestedSigmaTys actual_res_ty + actual_res_tvbs = mkTyVarBinders Specified actual_res_tvs + suggested_ty = mkForAllTys (actual_ex_tvs ++ actual_res_tvbs) $ + mkFunTys (actual_theta ++ actual_res_theta) + actual_res_rho badGadtDecl :: Name -> SDoc badGadtDecl tc_name |