summaryrefslogtreecommitdiff
path: root/compiler/GHC/Tc
diff options
context:
space:
mode:
authorRyan Scott <ryan.gl.scott@gmail.com>2020-05-21 12:01:06 -0400
committerRyan Scott <ryan.gl.scott@gmail.com>2020-06-08 10:18:48 -0400
commit102458850d1340f9f638d67f91e568c3d7821cef (patch)
treed4efccb746e666068b6fddfb492d2eedd9343077 /compiler/GHC/Tc
parentf1bfb806683b3092fc5ead84e7ecff928c55fbc4 (diff)
downloadhaskell-wip/T18191.tar.gz
Make GADT constructors adhere to the forall-or-nothing rule properlywip/T18191
Issue #18191 revealed that the types of GADT constructors don't quite adhere to the `forall`-or-nothing rule. This patch serves to clean up this sad state of affairs somewhat. The main change is not in the code itself, but in the documentation, as this patch introduces two sections to the GHC User's Guide: * A "Formal syntax for GADTs" section that presents a BNF-style grammar for what is and isn't allowed in GADT constructor types. This mostly exists to codify GHC's existing behavior, but it also imposes a new restriction that addresses #18191: the outermost `forall` and/or context in a GADT constructor is not allowed to be surrounded by parentheses. Doing so would make these `forall`s/contexts nested, and GADTs do not support nested `forall`s/contexts at present. * A "`forall`-or-nothing rule" section that describes exactly what the `forall`-or-nothing rule is all about. Surprisingly, there was no mention of this anywhere in the User's Guide up until now! To adhere the new specification in the "Formal syntax for GADTs" section of the User's Guide, the following code changes were made: * A new function, `GHC.Hs.Type.splitLHsGADTPrefixTy`, was introduced. This is very much like `splitLHsSigmaTy`, except that it avoids splitting apart any parentheses, which can be syntactically significant for GADT types. See `Note [No nested foralls or contexts in GADT constructors]` in `GHC.Hs.Type`. * `ConDeclGADTPrefixPs`, an extension constructor for `XConDecl`, was introduced so that `GHC.Parser.PostProcess.mkGadtDecl` can return it when given a prefix GADT constructor. Unlike `ConDeclGADT`, `ConDeclGADTPrefixPs` does not split the GADT type into its argument and result types, as this cannot be done until after the type is renamed (see `Note [GADT abstract syntax]` in `GHC.Hs.Decls` for why this is the case). * `GHC.Renamer.Module.rnConDecl` now has an additional case for `ConDeclGADTPrefixPs` that (1) splits apart the full `LHsType` into its `forall`s, context, argument types, and result type, and (2) checks for nested `forall`s/contexts. Step (2) used to be performed the typechecker (in `GHC.Tc.TyCl.badDataConTyCon`) rather than the renamer, but now the relevant code from the typechecker can simply be deleted. One nice side effect of this change is that we are able to give a more accurate error message for GADT constructors that use visible dependent quantification (e.g., `MkFoo :: forall a -> a -> Foo a`), which improves the stderr in the `T16326_Fail6` test case. Fixes #18191. Bumps the Haddock submodule.
Diffstat (limited to 'compiler/GHC/Tc')
-rw-r--r--compiler/GHC/Tc/TyCl.hs40
1 files changed, 1 insertions, 39 deletions
diff --git a/compiler/GHC/Tc/TyCl.hs b/compiler/GHC/Tc/TyCl.hs
index 98550132c5..8ff9ad0d3e 100644
--- a/compiler/GHC/Tc/TyCl.hs
+++ b/compiler/GHC/Tc/TyCl.hs
@@ -3058,7 +3058,7 @@ dataDeclChecks tc_name new_or_data (L _ stupid_theta) cons
-----------------------------------
-consUseGadtSyntax :: [LConDecl a] -> Bool
+consUseGadtSyntax :: [LConDecl GhcRn] -> Bool
consUseGadtSyntax (L _ (ConDeclGADT {}) : _) = True
consUseGadtSyntax _ = False
-- All constructors have same shape
@@ -4705,50 +4705,12 @@ noClassTyVarErr clas fam_tc
badDataConTyCon :: DataCon -> Type -> SDoc
badDataConTyCon data_con res_ty_tmpl
- | ASSERT( all isTyVar tvs )
- 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
actual_res_ty = dataConOrigResTy data_con
- -- This suggestion is useful for suggesting how to correct code like what
- -- was reported in #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
- -- simply drag all the foralls and (=>) contexts to the front
- -- of the type.
- suggested_ty = mkSpecSigmaTy tvs theta rho
- (tvs, theta, rho) = go (dataConUserType data_con)
-
- go :: Type -> ([TyVar],ThetaType,Type)
- -- The returned Type has no foralls or =>, even to the right of an (->)
- go ty | null arg_tys = (tvs1, theta1, rho1)
- | otherwise = (tvs1 ++ tvs2, theta1 ++ theta2, mkVisFunTys arg_tys rho2)
- where
- (tvs1, theta1, rho1) = tcSplitNestedSigmaTys ty
- (arg_tys, ty2) = tcSplitFunTys rho1
- (tvs2, theta2, rho2) = go ty2
-
badGadtDecl :: Name -> SDoc
badGadtDecl tc_name
= vcat [ text "Illegal generalised algebraic data declaration for" <+> quotes (ppr tc_name)