summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorRyan Scott <ryan.gl.scott@gmail.com>2017-08-17 10:07:03 -0400
committerRyan Scott <ryan.gl.scott@gmail.com>2017-08-17 10:07:03 -0400
commit039fa1b994a8b0d6be25eb1bc711904db9661db2 (patch)
tree1ed9bec64b6aab32dbdcb4d13975424a86951ec9 /compiler
parent38260a9e9f8c38edd25f4b4c06e0ea5d88fc6bf2 (diff)
downloadhaskell-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.hs43
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