diff options
author | mynguyen <mnguyen1@brynmawr.edu> | 2018-12-18 11:52:26 -0500 |
---|---|---|
committer | Richard Eisenberg <rae@cs.brynmawr.edu> | 2019-01-03 08:57:32 -0500 |
commit | 17bd163566153babbf51adaff8397f948ae363ca (patch) | |
tree | ef25e933481def276de4cdcad77eb4a34a76444b /libraries/template-haskell | |
parent | 6e4e63764aaf558cf177c2a9c2da345b2a360ea6 (diff) | |
download | haskell-17bd163566153babbf51adaff8397f948ae363ca.tar.gz |
Visible kind application
Summary:
This patch implements visible kind application (GHC Proposal 15/#12045), as well as #15360 and #15362.
It also refactors unnamed wildcard handling, and requires that type equations in type families in Template Haskell be
written with full type on lhs. PartialTypeSignatures are on and warnings are off automatically with visible kind
application, just like in term-level.
There are a few remaining issues with this patch, as documented in
ticket #16082.
Includes a submodule update for Haddock.
Test Plan: Tests T12045a/b/c/TH1/TH2, T15362, T15592a
Reviewers: simonpj, goldfire, bgamari, alanz, RyanGlScott, Iceland_jack
Subscribers: ningning, Iceland_jack, RyanGlScott, int-index, rwbarton, mpickering, carter
GHC Trac Issues: `#12045`, `#15362`, `#15592`, `#15788`, `#15793`, `#15795`, `#15797`, `#15799`, `#15801`, `#15807`, `#15816`
Differential Revision: https://phabricator.haskell.org/D5229
Diffstat (limited to 'libraries/template-haskell')
5 files changed, 120 insertions, 76 deletions
diff --git a/libraries/template-haskell/Language/Haskell/TH/Lib.hs b/libraries/template-haskell/Language/Haskell/TH/Lib.hs index 67a8773ecc..60527b6c82 100644 --- a/libraries/template-haskell/Language/Haskell/TH/Lib.hs +++ b/libraries/template-haskell/Language/Haskell/TH/Lib.hs @@ -52,9 +52,10 @@ module Language.Haskell.TH.Lib ( bindS, letS, noBindS, parS, recS, -- *** Types - forallT, varT, conT, appT, arrowT, infixT, uInfixT, parensT, equalityT, - listT, tupleT, unboxedTupleT, unboxedSumT, sigT, litT, wildCardT, - promotedT, promotedTupleT, promotedNilT, promotedConsT, implicitParamT, + forallT, varT, conT, appT, appKindT, arrowT, infixT, uInfixT, parensT, + equalityT, listT, tupleT, unboxedTupleT, unboxedSumT, sigT, litT, + wildCardT, promotedT, promotedTupleT, promotedNilT, promotedConsT, + implicitParamT, -- **** Type literals numTyLit, strTyLit, -- **** Strictness @@ -207,20 +208,20 @@ dataInstD :: CxtQ -> Name -> [TypeQ] -> Maybe Kind -> [ConQ] -> [DerivClauseQ] dataInstD ctxt tc tys ksig cons derivs = do ctxt1 <- ctxt - tys1 <- sequence tys + ty1 <- foldl appT (conT tc) tys cons1 <- sequence cons derivs1 <- sequence derivs - return (DataInstD ctxt1 tc Nothing tys1 ksig cons1 derivs1) + return (DataInstD ctxt1 Nothing ty1 ksig cons1 derivs1) newtypeInstD :: CxtQ -> Name -> [TypeQ] -> Maybe Kind -> ConQ -> [DerivClauseQ] -> DecQ newtypeInstD ctxt tc tys ksig con derivs = do ctxt1 <- ctxt - tys1 <- sequence tys + ty1 <- foldl appT (conT tc) tys con1 <- con derivs1 <- sequence derivs - return (NewtypeInstD ctxt1 tc Nothing tys1 ksig con1 derivs1) + return (NewtypeInstD ctxt1 Nothing ty1 ksig con1 derivs1) dataFamilyD :: Name -> [TyVarBndr] -> Maybe Kind -> DecQ dataFamilyD tc tvs kind @@ -237,12 +238,12 @@ closedTypeFamilyD tc tvs result injectivity eqns = do eqns1 <- sequence eqns return (ClosedTypeFamilyD (TypeFamilyHead tc tvs result injectivity) eqns1) -tySynEqn :: [TypeQ] -> TypeQ -> TySynEqnQ -tySynEqn lhs rhs = +tySynEqn :: (Maybe [TyVarBndr]) -> TypeQ -> TypeQ -> TySynEqnQ +tySynEqn tvs lhs rhs = do - lhs1 <- sequence lhs + lhs1 <- lhs rhs1 <- rhs - return (TySynEqn Nothing lhs1 rhs1) + return (TySynEqn tvs lhs1 rhs1) forallC :: [TyVarBndr] -> CxtQ -> ConQ -> ConQ forallC ns ctxt con = liftM2 (ForallC ns) ctxt con diff --git a/libraries/template-haskell/Language/Haskell/TH/Lib/Internal.hs b/libraries/template-haskell/Language/Haskell/TH/Lib/Internal.hs index 11391da95f..ec9ca4fafb 100644 --- a/libraries/template-haskell/Language/Haskell/TH/Lib/Internal.hs +++ b/libraries/template-haskell/Language/Haskell/TH/Lib/Internal.hs @@ -491,35 +491,35 @@ pragLineD line file = return $ PragmaD $ LineP line file pragCompleteD :: [Name] -> Maybe Name -> DecQ pragCompleteD cls mty = return $ PragmaD $ CompleteP cls mty -dataInstD :: CxtQ -> Name -> (Maybe [TyVarBndrQ]) -> [TypeQ] -> Maybe KindQ - -> [ConQ] -> [DerivClauseQ] -> DecQ -dataInstD ctxt tc mb_bndrs tys ksig cons derivs = +dataInstD :: CxtQ -> (Maybe [TyVarBndrQ]) -> TypeQ -> Maybe KindQ -> [ConQ] + -> [DerivClauseQ] -> DecQ +dataInstD ctxt mb_bndrs ty ksig cons derivs = do - ctxt1 <- ctxt + ctxt1 <- ctxt mb_bndrs1 <- traverse sequence mb_bndrs - tys1 <- sequenceA tys - ksig1 <- sequenceA ksig - cons1 <- sequenceA cons - derivs1 <- sequenceA derivs - return (DataInstD ctxt1 tc mb_bndrs1 tys1 ksig1 cons1 derivs1) - -newtypeInstD :: CxtQ -> Name -> (Maybe [TyVarBndrQ]) -> [TypeQ] -> Maybe KindQ - -> ConQ -> [DerivClauseQ] -> DecQ -newtypeInstD ctxt tc mb_bndrs tys ksig con derivs = + ty1 <- ty + ksig1 <- sequenceA ksig + cons1 <- sequenceA cons + derivs1 <- sequenceA derivs + return (DataInstD ctxt1 mb_bndrs1 ty1 ksig1 cons1 derivs1) + +newtypeInstD :: CxtQ -> (Maybe [TyVarBndrQ]) -> TypeQ -> Maybe KindQ -> ConQ + -> [DerivClauseQ] -> DecQ +newtypeInstD ctxt mb_bndrs ty ksig con derivs = do - ctxt1 <- ctxt + ctxt1 <- ctxt mb_bndrs1 <- traverse sequence mb_bndrs - tys1 <- sequenceA tys - ksig1 <- sequenceA ksig - con1 <- con - derivs1 <- sequence derivs - return (NewtypeInstD ctxt1 tc mb_bndrs1 tys1 ksig1 con1 derivs1) - -tySynInstD :: Name -> TySynEqnQ -> DecQ -tySynInstD tc eqn = + ty1 <- ty + ksig1 <- sequenceA ksig + con1 <- con + derivs1 <- sequence derivs + return (NewtypeInstD ctxt1 mb_bndrs1 ty1 ksig1 con1 derivs1) + +tySynInstD :: TySynEqnQ -> DecQ +tySynInstD eqn = do eqn1 <- eqn - return (TySynInstD tc eqn1) + return (TySynInstD eqn1) dataFamilyD :: Name -> [TyVarBndrQ] -> Maybe KindQ -> DecQ dataFamilyD tc tvs kind = @@ -584,11 +584,11 @@ implicitParamBindD n e = e' <- e return $ ImplicitParamBindD n e' -tySynEqn :: (Maybe [TyVarBndrQ]) -> [TypeQ] -> TypeQ -> TySynEqnQ +tySynEqn :: (Maybe [TyVarBndrQ]) -> TypeQ -> TypeQ -> TySynEqnQ tySynEqn mb_bndrs lhs rhs = do mb_bndrs1 <- traverse sequence mb_bndrs - lhs1 <- sequence lhs + lhs1 <- lhs rhs1 <- rhs return (TySynEqn mb_bndrs1 lhs1 rhs1) @@ -672,6 +672,12 @@ appT t1 t2 = do t2' <- t2 return $ AppT t1' t2' +appKindT :: TypeQ -> KindQ -> TypeQ +appKindT ty ki = do + ty' <- ty + ki' <- ki + return $ AppKindT ty' ki' + arrowT :: TypeQ arrowT = return ArrowT diff --git a/libraries/template-haskell/Language/Haskell/TH/Ppr.hs b/libraries/template-haskell/Language/Haskell/TH/Ppr.hs index 621c0f5fcc..c25b2fb702 100644 --- a/libraries/template-haskell/Language/Haskell/TH/Ppr.hs +++ b/libraries/template-haskell/Language/Haskell/TH/Ppr.hs @@ -325,11 +325,11 @@ ppr_dec _ (FunD f cs) = vcat $ map (\c -> pprPrefixOcc f <+> ppr c) cs ppr_dec _ (ValD p r ds) = ppr p <+> pprBody True r $$ where_clause ds ppr_dec _ (TySynD t xs rhs) - = ppr_tySyn empty t (hsep (map ppr xs)) rhs + = ppr_tySyn empty (Just t) (hsep (map ppr xs)) rhs ppr_dec _ (DataD ctxt t xs ksig cs decs) - = ppr_data empty ctxt t (hsep (map ppr xs)) ksig cs decs + = ppr_data empty ctxt (Just t) (hsep (map ppr xs)) ksig cs decs ppr_dec _ (NewtypeD ctxt t xs ksig c decs) - = ppr_newtype empty ctxt t (sep (map ppr xs)) ksig c decs + = ppr_newtype empty ctxt (Just t) (sep (map ppr xs)) ksig c decs ppr_dec _ (ClassD ctxt c xs fds ds) = text "class" <+> pprCxt ctxt <+> ppr c <+> hsep (map ppr xs) <+> ppr fds $$ where_clause ds @@ -347,21 +347,21 @@ ppr_dec isTop (DataFamilyD tc tvs kind) | otherwise = empty maybeKind | (Just k') <- kind = dcolon <+> ppr k' | otherwise = empty -ppr_dec isTop (DataInstD ctxt tc bndrs tys ksig cs decs) - = ppr_data (maybeInst <+> ppr_bndrs bndrs) ctxt tc - (sep (map pprParendType tys)) ksig cs decs +ppr_dec isTop (DataInstD ctxt bndrs ty ksig cs decs) + = ppr_data (maybeInst <+> ppr_bndrs bndrs) + ctxt Nothing (ppr ty) ksig cs decs where maybeInst | isTop = text "instance" | otherwise = empty -ppr_dec isTop (NewtypeInstD ctxt tc bndrs tys ksig c decs) - = ppr_newtype (maybeInst <+> ppr_bndrs bndrs) ctxt tc - (sep (map pprParendType tys)) ksig c decs +ppr_dec isTop (NewtypeInstD ctxt bndrs ty ksig c decs) + = ppr_newtype (maybeInst <+> ppr_bndrs bndrs) + ctxt Nothing (ppr ty) ksig c decs where maybeInst | isTop = text "instance" | otherwise = empty -ppr_dec isTop (TySynInstD tc (TySynEqn mb_bndrs tys rhs)) - = ppr_tySyn (maybeInst <+> ppr_bndrs mb_bndrs) tc - (sep (map pprParendType tys)) rhs +ppr_dec isTop (TySynInstD (TySynEqn mb_bndrs ty rhs)) + = ppr_tySyn (maybeInst <+> ppr_bndrs mb_bndrs) + Nothing (ppr ty) rhs where maybeInst | isTop = text "instance" | otherwise = empty @@ -370,13 +370,12 @@ ppr_dec isTop (OpenTypeFamilyD tfhead) where maybeFamily | isTop = text "family" | otherwise = empty -ppr_dec _ (ClosedTypeFamilyD tfhead@(TypeFamilyHead tc _ _ _) eqns) +ppr_dec _ (ClosedTypeFamilyD tfhead eqns) = hang (text "type family" <+> ppr_tf_head tfhead <+> text "where") nestDepth (vcat (map ppr_eqn eqns)) where ppr_eqn (TySynEqn mb_bndrs lhs rhs) - = ppr_bndrs mb_bndrs <+> ppr tc <+> sep (map pprParendType lhs) - <+> text "=" <+> ppr rhs + = ppr_bndrs mb_bndrs <+> ppr lhs <+> text "=" <+> ppr rhs ppr_dec _ (RoleAnnotD name roles) = hsep [ text "type role", ppr name ] <+> hsep (map ppr roles) ppr_dec _ (StandaloneDerivD ds cxt ty) @@ -416,12 +415,15 @@ ppr_overlap o = text $ Overlapping -> "{-# OVERLAPPING #-}" Incoherent -> "{-# INCOHERENT #-}" -ppr_data :: Doc -> Cxt -> Name -> Doc -> Maybe Kind -> [Con] -> [DerivClause] +ppr_data :: Doc -> Cxt -> Maybe Name -> Doc -> Maybe Kind -> [Con] -> [DerivClause] -> Doc ppr_data maybeInst ctxt t argsDoc ksig cs decs = sep [text "data" <+> maybeInst <+> pprCxt ctxt - <+> pprName' Applied t <+> argsDoc <+> ksigDoc <+> maybeWhere, + <+> case t of + Just n -> pprName' Applied n <+> argsDoc + Nothing -> argsDoc + <+> ksigDoc <+> maybeWhere, nest nestDepth (sep (pref $ map ppr cs)), if null decs then empty @@ -448,12 +450,15 @@ ppr_data maybeInst ctxt t argsDoc ksig cs decs Nothing -> empty Just k -> dcolon <+> ppr k -ppr_newtype :: Doc -> Cxt -> Name -> Doc -> Maybe Kind -> Con -> [DerivClause] +ppr_newtype :: Doc -> Cxt -> Maybe Name -> Doc -> Maybe Kind -> Con -> [DerivClause] -> Doc ppr_newtype maybeInst ctxt t argsDoc ksig c decs = sep [text "newtype" <+> maybeInst <+> pprCxt ctxt - <+> ppr t <+> argsDoc <+> ksigDoc, + <+> case t of + Just n -> ppr n <+> argsDoc + Nothing -> argsDoc + <+> ksigDoc, nest 2 (char '=' <+> ppr c), if null decs then empty @@ -477,9 +482,13 @@ ppr_deriv_clause (DerivClause ds ctxt) Just (via@ViaStrategy{}) -> (empty, ppr_deriv_strategy via) _ -> (maybe empty ppr_deriv_strategy ds, empty) -ppr_tySyn :: Doc -> Name -> Doc -> Type -> Doc +ppr_tySyn :: Doc -> Maybe Name -> Doc -> Type -> Doc ppr_tySyn maybeInst t argsDoc rhs - = text "type" <+> maybeInst <+> ppr t <+> argsDoc <+> text "=" <+> ppr rhs + = text "type" <+> maybeInst + <+> case t of + Just n -> ppr n <+> argsDoc + Nothing -> argsDoc + <+> text "=" <+> ppr rhs ppr_tf_head :: TypeFamilyHead -> Doc ppr_tf_head (TypeFamilyHead tc tvs res inj) @@ -742,6 +751,7 @@ pprParendType (ImplicitParamT n t)= text ('?':n) <+> text "::" <+> ppr t pprParendType EqualityT = text "(~)" pprParendType t@(ForallT {}) = parens (ppr t) pprParendType t@(AppT {}) = parens (ppr t) +pprParendType t@(AppKindT {}) = parens (ppr t) pprUInfixT :: Type -> Doc pprUInfixT (UInfixT x n y) = pprUInfixT x <+> pprName' Infix n <+> pprUInfixT y @@ -752,7 +762,13 @@ instance Ppr Type where ppr ty = pprTyApp (split ty) -- Works, in a degnerate way, for SigT, and puts parens round (ty :: kind) -- See Note [Pretty-printing kind signatures] +instance Ppr TypeArg where + ppr (TANormal ty) = ppr ty + ppr (TyArg ki) = char '@' <> ppr ki +pprParendTypeArg :: TypeArg -> Doc +pprParendTypeArg (TANormal ty) = pprParendType ty +pprParendTypeArg (TyArg ki) = char '@' <> pprParendType ki {- Note [Pretty-printing kind signatures] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GHC's parser only recognises a kind signature in a type when there are @@ -761,16 +777,16 @@ parens around it. E.g. the parens are required here: type instance F Int = (Bool :: *) So we always print a SigT with parens (see Trac #10050). -} -pprTyApp :: (Type, [Type]) -> Doc -pprTyApp (ArrowT, [arg1,arg2]) = sep [pprFunArgType arg1 <+> text "->", ppr arg2] -pprTyApp (EqualityT, [arg1, arg2]) = +pprTyApp :: (Type, [TypeArg]) -> Doc +pprTyApp (ArrowT, [TANormal arg1, TANormal arg2]) = sep [pprFunArgType arg1 <+> text "->", ppr arg2] +pprTyApp (EqualityT, [TANormal arg1, TANormal arg2]) = sep [pprFunArgType arg1 <+> text "~", ppr arg2] -pprTyApp (ListT, [arg]) = brackets (ppr arg) +pprTyApp (ListT, [TANormal arg]) = brackets (ppr arg) pprTyApp (TupleT n, args) | length args == n = parens (commaSep args) pprTyApp (PromotedTupleT n, args) | length args == n = quoteParens (commaSep args) -pprTyApp (fun, args) = pprParendType fun <+> sep (map pprParendType args) +pprTyApp (fun, args) = pprParendType fun <+> sep (map pprParendTypeArg args) pprFunArgType :: Type -> Doc -- Should really use a precedence argument -- Everything except forall and (->) binds more tightly than (->) @@ -779,9 +795,13 @@ pprFunArgType ty@((ArrowT `AppT` _) `AppT` _) = parens (ppr ty) pprFunArgType ty@(SigT _ _) = parens (ppr ty) pprFunArgType ty = ppr ty -split :: Type -> (Type, [Type]) -- Split into function and args +data TypeArg = TANormal Type + | TyArg Kind + +split :: Type -> (Type, [TypeArg]) -- Split into function and args split t = go t [] - where go (AppT t1 t2) args = go t1 (t2:args) + where go (AppT t1 t2) args = go t1 (TANormal t2:args) + go (AppKindT ty ki) args = go ty (TyArg ki:args) go ty args = (ty, args) pprTyLit :: TyLit -> Doc diff --git a/libraries/template-haskell/Language/Haskell/TH/Syntax.hs b/libraries/template-haskell/Language/Haskell/TH/Syntax.hs index ef44a5cbf3..770fac7580 100644 --- a/libraries/template-haskell/Language/Haskell/TH/Syntax.hs +++ b/libraries/template-haskell/Language/Haskell/TH/Syntax.hs @@ -1727,24 +1727,20 @@ data Dec (Maybe Kind) -- ^ @{ data family T a b c :: * }@ - | DataInstD Cxt Name - (Maybe [TyVarBndr]) -- Quantified type vars - [Type] + | DataInstD Cxt (Maybe [TyVarBndr]) Type (Maybe Kind) -- Kind signature [Con] [DerivClause] -- ^ @{ data instance Cxt x => T [x] -- = A x | B (T x) -- deriving (Z,W) -- deriving stock Eq }@ - | NewtypeInstD Cxt Name - (Maybe [TyVarBndr]) -- Quantified type vars - [Type] + | NewtypeInstD Cxt (Maybe [TyVarBndr]) Type -- Quantified type vars (Maybe Kind) -- Kind signature Con [DerivClause] -- ^ @{ newtype instance Cxt x => T [x] -- = A (B x) -- deriving (Z,W) -- deriving stock Eq }@ - | TySynInstD Name TySynEqn -- ^ @{ type instance ... }@ + | TySynInstD TySynEqn -- ^ @{ type instance ... }@ -- | open type families (may also appear in [Dec] of 'ClassD' and 'InstanceD') | OpenTypeFamilyD TypeFamilyHead @@ -1855,9 +1851,23 @@ data TypeFamilyHead = deriving( Show, Eq, Ord, Data, Generic ) -- | One equation of a type family instance or closed type family. The --- arguments are the left-hand-side type patterns and the right-hand-side --- result. -data TySynEqn = TySynEqn (Maybe [TyVarBndr]) [Type] Type +-- arguments are the left-hand-side type and the right-hand-side result. +-- +-- For instance, if you had the following type family: +-- +-- @ +-- type family Foo (a :: k) :: k where +-- forall k (a :: k). Foo \@k a = a +-- @ +-- +-- The @Foo \@k a = a@ equation would be represented as follows: +-- +-- @ +-- 'TySynEqn' ('Just' ['PlainTV' k, 'KindedTV' a ('VarT' k)]) +-- ('AppT' ('AppKindT' ('ConT' ''Foo) ('VarT' k)) ('VarT' a)) +-- ('VarT' a) +-- @ +data TySynEqn = TySynEqn (Maybe [TyVarBndr]) Type Type deriving( Show, Eq, Ord, Data, Generic ) data FunDep = FunDep [Name] [Name] @@ -2037,6 +2047,7 @@ data PatSynArgs data Type = ForallT [TyVarBndr] Cxt Type -- ^ @forall \<vars\>. \<ctxt\> => \<type\>@ | AppT Type Type -- ^ @T a b@ + | AppKindT Type Kind -- ^ @T \@k t@ | SigT Type Kind -- ^ @t :: k@ | VarT Name -- ^ @a@ | ConT Name -- ^ @T@ diff --git a/libraries/template-haskell/changelog.md b/libraries/template-haskell/changelog.md index 5dca9832c5..b1444341d8 100644 --- a/libraries/template-haskell/changelog.md +++ b/libraries/template-haskell/changelog.md @@ -5,12 +5,18 @@ * In `Language.Haskell.TH.Syntax`, `DataInstD`, `NewTypeInstD`, `TySynEqn`, and `RuleP` now all have a `Maybe [TyVarBndr]` argument, which contains a list of quantified type variables if an explicit `forall` is present, and - `Nothing` otherwise. + `Nothing` otherwise. `DataInstD`, `NewTypeInstD`, `TySynEqn` also now use + a single `Type` argument to represent the left-hand-side to avoid + malformed type family equations and allow visible kind application. Correspondingly, in `Language.Haskell.TH.Lib.Internal`, `pragRuleD`, `dataInstD`, `newtypeInstD`, and `tySynEqn` now all have a `Maybe [TyVarBndrQ]` argument. Non-API-breaking versions of these - functions can be found in `Language.Haskell.TH.Lib`. + functions can be found in `Language.Haskell.TH.Lib`. The type signature + of `tySynEqn` has also changed from `[TypeQ] -> TypeQ -> TySynEqnQ` to + `(Maybe [TyVarBndrQ]) -> TypeQ -> TypeQ -> TySynEqnQ`, for the same reason + as in `Language.Haskell.TH.Syntax` above. Consequently, `tySynInstD` also + changes from `Name -> TySynEqnQ -> DecQ` to `TySynEqnQ -> DecQ`. * Add `Lift` instances for `NonEmpty` and `Void` |