diff options
Diffstat (limited to 'compiler/GHC/Hs/Decls.hs')
-rw-r--r-- | compiler/GHC/Hs/Decls.hs | 198 |
1 files changed, 157 insertions, 41 deletions
diff --git a/compiler/GHC/Hs/Decls.hs b/compiler/GHC/Hs/Decls.hs index 9edd0ff871..f800d934b6 100644 --- a/compiler/GHC/Hs/Decls.hs +++ b/compiler/GHC/Hs/Decls.hs @@ -5,6 +5,7 @@ {-# LANGUAGE DeriveDataTypeable, DeriveFunctor, DeriveFoldable, DeriveTraversable #-} +{-# LANGUAGE CPP #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} @@ -70,7 +71,7 @@ module GHC.Hs.Decls ( ForeignDecl(..), LForeignDecl, ForeignImport(..), ForeignExport(..), CImportSpec(..), -- ** Data-constructor declarations - ConDecl(..), LConDecl, + ConDecl(..), LConDecl, ConDeclGADTPrefixPs(..), HsConDeclDetails, hsConDeclArgTys, hsConDeclTheta, getConNames, getConArgs, -- ** Document comments @@ -109,6 +110,7 @@ import GHC.Core.Coercion import GHC.Types.ForeignCall import GHC.Hs.Extension import GHC.Types.Name +import GHC.Types.Name.Reader import GHC.Types.Name.Set -- others: @@ -1422,54 +1424,144 @@ type instance XConDeclGADT GhcRn = [Name] -- Implicitly bound type variables type instance XConDeclGADT GhcTc = NoExtField type instance XConDeclH98 (GhcPass _) = NoExtField -type instance XXConDecl (GhcPass _) = NoExtCon + +type instance XXConDecl GhcPs = ConDeclGADTPrefixPs +type instance XXConDecl GhcRn = NoExtCon +type instance XXConDecl GhcTc = NoExtCon + +-- | Stores the types of prefix GADT constructors in the parser. This is used +-- in lieu of ConDeclGADT, which requires knowing the specific argument and +-- result types, as this is difficult to determine in general in the parser. +-- See @Note [GADT abstract syntax]@. +data ConDeclGADTPrefixPs = ConDeclGADTPrefixPs + { con_gp_names :: [Located RdrName] + -- ^ The GADT constructor declaration's names. + , con_gp_ty :: LHsSigType GhcPs + -- ^ The type after the @::@. + , con_gp_doc :: Maybe LHsDocString + -- ^ A possible Haddock comment. + } {- Note [GADT abstract syntax] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -There's a wrinkle in ConDeclGADT - -* For record syntax, it's all uniform. Given: - data T a where - K :: forall a. Ord a => { x :: [a], ... } -> T a - we make the a ConDeclGADT for K with - con_qvars = {a} - con_mb_cxt = Just [Ord a] - con_args = RecCon <the record fields> - con_res_ty = T a - - We need the RecCon before the reanmer, so we can find the record field - binders in GHC.Hs.Utils.hsConDeclsBinders. - -* However for a GADT constr declaration which is not a record, it can - be hard parse until we know operator fixities. Consider for example - C :: a :*: b -> a :*: b -> a :+: b - Initially this type will parse as - a :*: (b -> (a :*: (b -> (a :+: b)))) - so it's hard to split up the arguments until we've done the precedence - resolution (in the renamer). - - So: - In the parser (GHC.Parser.PostProcess.mkGadtDecl), we put the whole constr - type into the res_ty for a ConDeclGADT for now, and use - PrefixCon [] - con_args = PrefixCon [] - con_res_ty = a :*: (b -> (a :*: (b -> (a :+: b)))) - - - In the renamer (GHC.Rename.Module.rnConDecl), we unravel it after - operator fixities are sorted. So we generate. So we end - up with - con_args = PrefixCon [ a :*: b, a :*: b ] - con_res_ty = a :+: b +There are two broad ways to classify GADT constructors: + +* Record-syntax constructors. For example: + + data T a where + K :: forall a. Ord a => { x :: [a], ... } -> T a + +* Prefix constructors, which do not use record syntax. For example: + + data T a where + K :: forall a. Ord a => [a] -> ... -> T a + +Initially, both forms of GADT constructors are initially parsed as a single +LHsType. However, GADTs have a certain structure, requiring distinct argument +and result types, as well as imposing restrictions on where `forall`s and +contexts can be (see "Wrinkle: No nested foralls or contexts" below). As a +result, it is convenient to split up the LHsType into its individual +components, which are stored in the ConDeclGADT constructor of ConDecl. + +Where should this splitting occur? For GADT constructors with record syntax, +we split in the parser (in GHC.Parser.PostProcess.mkGadtDecl). We must do this +splitting before the renamer, as we need the record field names for use in +GHC.Hs.Utils.hsConDeclsBinders. + +For prefix GADT constructors, however, the situation is more complicated. It +can be difficult to split a prefix GADT type until we know type operator +fixities. Consider this, for example: + + C :: a :*: b -> a :*: b -> a :+: b + +Initially, the type of C will parse as: + + a :*: (b -> (a :*: (b -> (a :+: b)))) + +So it's hard to split up the arguments until we've done the precedence +resolution (in the renamer). (Unlike prefix GADT types, record GADT types +do not have this problem because of their uniform syntax.) + +As a result, we deliberately avoid splitting prefix GADT types in the parser. +Instead, we store the entire LHsType in ConDeclGADTPrefixPs, a GHC-specific +extension constructor to ConDecl. Later, in the renamer +(in GHC.Rename.Module.rnConDecl), we resolve the fixities of all type operators +in the LHsType, which facilitates splitting it into argument and result types +accurately. We finish renaming a ConDeclGADTPrefixPs by putting the split +components into a ConDeclGADT. This is why ConDeclGADTPrefixPs has the suffix +-Ps, as it is only used by the parser. + +Note that the existence of ConDeclGADTPrefixPs does not imply that ConDeclGADT +goes completely unused by the parser. Other consumers of GHC's abstract syntax +are still free to use ConDeclGADT. Indeed, both Haddock and Template Haskell +construct values of type `ConDecl GhcPs` by way of ConDeclGADT, as neither of +them have the same difficulties with operator precedence that GHC's parser +does. As an example, see GHC.ThToHs.cvtConstr, which converts Template Haskell +syntax into GHC syntax. + +----- +-- Wrinkle: No nested foralls or contexts +----- + +GADT constructors provide some freedom to change the order of foralls in their +types (see Note [DataCon user type variable binders] in GHC.Core.DataCon), but +this freedom is still limited. GADTs still require that all quantification +occurs "prenex". That is, any explicitly quantified type variables must occur +at the front of the GADT type, followed by any contexts, followed by the body of +the GADT type, in precisely that order. For instance: + + data T where + MkT1 :: forall a b. (Eq a, Eq b) => a -> b -> T + -- OK + MkT2 :: forall a. Eq a => forall b. a -> b -> T + -- Rejected, `forall b` is nested + MkT3 :: forall a b. Eq a => Eq b => a -> b -> T + -- Rejected, `Eq b` is nested + MkT4 :: Int -> forall a. a -> T + -- Rejected, `forall a` is nested + MkT5 :: forall a. Int -> Eq a => a -> T + -- Rejected, `Eq a` is nested + MkT6 :: (forall a. a -> T) + -- Rejected, `forall a` is nested due to the surrounding parentheses + MkT7 :: (Eq a => a -> t) + -- Rejected, `Eq a` is nested due to the surrounding parentheses + +For the full details, see the "Formal syntax for GADTs" section of the GHC +User's Guide. GHC enforces that GADT constructors do not have nested `forall`s +or contexts in two parts: + +1. GHC, in the process of splitting apart a GADT's type, + extracts out the leading `forall` and context (if they are provided). To + accomplish this splitting, the renamer uses the + GHC.Hs.Type.splitLHsGADTPrefixTy function, which is careful not to remove + parentheses surrounding the leading `forall` or context (as these + parentheses can be syntactically significant). If the third result returned + by splitLHsGADTPrefixTy contains any `forall`s or contexts, then they must + be nested, so they will be rejected. + + Note that this step applies to both prefix and record GADTs alike, as they + both have syntax which permits `forall`s and contexts. The difference is + where this step happens: + + * For prefix GADTs, this happens in the renamer (in rnConDecl), as we cannot + split until after the type operator fixities have been resolved. + * For record GADTs, this happens in the parser (in mkGadtDecl). +2. If the GADT type is prefix, the renamer (in the ConDeclGADTPrefixPs case of + rnConDecl) will then check for nested `forall`s/contexts in the body of a + prefix GADT type, after it has determined what all of the argument types are. + This step is necessary to catch examples like MkT4 above, where the nested + quantification occurs after a visible argument type. -} -- | Haskell data Constructor Declaration Details type HsConDeclDetails pass = HsConDetails (LBangType pass) (Located [LConDeclField pass]) -getConNames :: ConDecl (GhcPass p) -> [Located (IdP (GhcPass p))] +getConNames :: ConDecl GhcRn -> [Located Name] getConNames ConDeclH98 {con_name = name} = [name] getConNames ConDeclGADT {con_names = names} = names -getConArgs :: ConDecl pass -> HsConDeclDetails pass +getConArgs :: ConDecl GhcRn -> HsConDeclDetails GhcRn getConArgs d = con_args d hsConDeclArgTys :: HsConDeclDetails pass -> [LBangType pass] @@ -1518,16 +1610,30 @@ instance Outputable NewOrData where ppr NewType = text "newtype" ppr DataType = text "data" -pp_condecls :: (OutputableBndrId p) => [LConDecl (GhcPass p)] -> SDoc -pp_condecls cs@(L _ ConDeclGADT{} : _) -- In GADT syntax +pp_condecls :: forall p. OutputableBndrId p => [LConDecl (GhcPass p)] -> SDoc +pp_condecls cs + | gadt_syntax -- In GADT syntax = hang (text "where") 2 (vcat (map ppr cs)) -pp_condecls cs -- In H98 syntax + | otherwise -- In H98 syntax = equals <+> sep (punctuate (text " |") (map ppr cs)) + where + gadt_syntax = case cs of + [] -> False + (L _ ConDeclH98{} : _) -> False + (L _ ConDeclGADT{} : _) -> True + (L _ (XConDecl x) : _) -> + case ghcPass @p of + GhcPs | ConDeclGADTPrefixPs{} <- x + -> True +#if __GLASGOW_HASKELL__ < 811 + GhcRn -> noExtCon x + GhcTc -> noExtCon x +#endif instance (OutputableBndrId p) => Outputable (ConDecl (GhcPass p)) where ppr = pprConDecl -pprConDecl :: (OutputableBndrId p) => ConDecl (GhcPass p) -> SDoc +pprConDecl :: forall p. OutputableBndrId p => ConDecl (GhcPass p) -> SDoc pprConDecl (ConDeclH98 { con_name = L _ con , con_ex_tvs = ex_tvs , con_mb_cxt = mcxt @@ -1558,6 +1664,16 @@ pprConDecl (ConDeclGADT { con_names = cons, con_qvars = qvars ppr_arrow_chain (a:as) = sep (a : map (arrow <+>) as) ppr_arrow_chain [] = empty +pprConDecl (XConDecl x) = + case ghcPass @p of + GhcPs | ConDeclGADTPrefixPs { con_gp_names = cons, con_gp_ty = ty + , con_gp_doc = doc } <- x + -> ppr_mbDoc doc <+> ppr_con_names cons <+> dcolon <+> ppr ty +#if __GLASGOW_HASKELL__ < 811 + GhcRn -> noExtCon x + GhcTc -> noExtCon x +#endif + ppr_con_names :: (OutputableBndr a) => [Located a] -> SDoc ppr_con_names = pprWithCommas (pprPrefixOcc . unLoc) |