summaryrefslogtreecommitdiff
path: root/compiler/basicTypes/BasicTypes.hs
diff options
context:
space:
mode:
authorVladislav Zavialov <vlad.z.4096@gmail.com>2019-12-02 23:10:33 +0300
committerMarge Bot <ben+marge-bot@smart-cactus.org>2019-12-05 16:07:49 -0500
commit3354c68ec6c90bbccc0f361aa7973eeb75ea229c (patch)
treeb9c5e2f9627b25b6d7bdf745b281b6771b8d5990 /compiler/basicTypes/BasicTypes.hs
parentc4ca29c796fa86ad9d5cd4dfa1a5cdd4e0565fb0 (diff)
downloadhaskell-3354c68ec6c90bbccc0f361aa7973eeb75ea229c.tar.gz
Pretty-printing of the * kind
Before this patch, GHC always printed the * kind unparenthesized. This led to two issues: 1. Sometimes GHC printed invalid or incorrect code. For example, GHC would print: type F @* x = x when it meant to print: type F @(*) x = x In the former case, instead of a kind application we were getting a type operator (@*). 2. Sometimes GHC printed kinds that were correct but hard to read. Should Either * Int be read as Either (*) Int or as (*) Either Int ? This depends on whether -XStarIsType is enabled, but it would be easier if we didn't have to check for the flag when reading the code. We can solve both problems by assigning (*) a different precedence. Note that Haskell98 kinds are not affected: ((* -> *) -> *) -> * does NOT become (((*) -> (*)) -> (*)) -> (*) The parentheses are added when (*) is used in a function argument position: F * * * becomes F (*) (*) (*) F A * B becomes F A (*) B Proxy * becomes Proxy (*) a * -> * becomes a (*) -> *
Diffstat (limited to 'compiler/basicTypes/BasicTypes.hs')
-rw-r--r--compiler/basicTypes/BasicTypes.hs36
1 files changed, 33 insertions, 3 deletions
diff --git a/compiler/basicTypes/BasicTypes.hs b/compiler/basicTypes/BasicTypes.hs
index 7513e08f82..ce449b3562 100644
--- a/compiler/basicTypes/BasicTypes.hs
+++ b/compiler/basicTypes/BasicTypes.hs
@@ -51,7 +51,8 @@ module BasicTypes(
Boxity(..), isBoxed,
- PprPrec(..), topPrec, sigPrec, opPrec, funPrec, appPrec, maybeParen,
+ PprPrec(..), topPrec, sigPrec, opPrec, funPrec, starPrec, appPrec,
+ maybeParen,
TupleSort(..), tupleSortBoxity, boxityTupleSort,
tupleParens,
@@ -729,14 +730,16 @@ pprSafeOverlap False = empty
newtype PprPrec = PprPrec Int deriving (Eq, Ord, Show)
-- See Note [Precedence in types]
-topPrec, sigPrec, funPrec, opPrec, appPrec :: PprPrec
+topPrec, sigPrec, funPrec, opPrec, starPrec, appPrec :: PprPrec
topPrec = PprPrec 0 -- No parens
sigPrec = PprPrec 1 -- Explicit type signatures
funPrec = PprPrec 2 -- Function args; no parens for constructor apps
-- See [Type operator precedence] for why both
-- funPrec and opPrec exist.
opPrec = PprPrec 2 -- Infix operator
-appPrec = PprPrec 3 -- Constructor args; no parens for atomic
+starPrec = PprPrec 3 -- Star syntax for the type of types, i.e. the * in (* -> *)
+ -- See Note [Star kind precedence]
+appPrec = PprPrec 4 -- Constructor args; no parens for atomic
maybeParen :: PprPrec -> PprPrec -> SDoc -> SDoc
maybeParen ctxt_prec inner_prec pretty
@@ -775,6 +778,33 @@ By treating opPrec = funPrec we end up with more parens
But the two are different constructors of PprPrec so we could make
(->) bind more or less tightly if we wanted.
+
+Note [Star kind precedence]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We parenthesize the (*) kind to avoid two issues:
+
+1. Printing invalid or incorrect code.
+ For example, instead of type F @(*) x = x
+ GHC used to print type F @* x = x
+ However, (@*) is a type operator, not a kind application.
+
+2. Printing kinds that are correct but hard to read.
+ Should Either * Int be read as Either (*) Int
+ or as (*) Either Int ?
+ This depends on whether -XStarIsType is enabled, but it would be
+ easier if we didn't have to check for the flag when reading the code.
+
+At the same time, we cannot parenthesize (*) blindly.
+Consider this Haskell98 kind: ((* -> *) -> *) -> *
+With parentheses, it is less readable: (((*) -> (*)) -> (*)) -> (*)
+
+The solution is to assign a special precedence to (*), 'starPrec', which is
+higher than 'funPrec' but lower than 'appPrec':
+
+ F * * * becomes F (*) (*) (*)
+ F A * B becomes F A (*) B
+ Proxy * becomes Proxy (*)
+ a * -> * becomes a (*) -> *
-}
{-