summaryrefslogtreecommitdiff
path: root/compiler/main/PprTyThing.hs
blob: 1fd5d0cbcfcedccb61239ea22eda05a22c0281e6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
-----------------------------------------------------------------------------
--
-- Pretty-printing TyThings
--
-- (c) The GHC Team 2005
--
-----------------------------------------------------------------------------

{-# OPTIONS -fno-warn-tabs #-}
-- The above warning supression flag is a temporary kludge.
-- While working on this module you are encouraged to remove it and
-- detab the module (please do the detabbing in a separate patch). See
--     http://ghc.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
-- for details

module PprTyThing (
	pprTyThing,
	pprTyThingInContext,
	pprTyThingLoc,
	pprTyThingInContextLoc,
	pprTyThingHdr,
  	pprTypeForUser
  ) where

import TypeRep ( TyThing(..) )
import DataCon
import Id
import TyCon
import Class
import Coercion( pprCoAxBranch )
import CoAxiom( CoAxiom(..), brListMap )
import HscTypes( tyThingParent_maybe )
import Type( tidyTopType, tidyOpenType, splitForAllTys, funResultTy )
import Kind( synTyConResKind )
import TypeRep( pprTvBndrs, pprForAll, suppressKinds )
import TysPrim( alphaTyVars )
import MkIface ( tyThingToIfaceDecl )
import TcType
import Name
import VarEnv( emptyTidyEnv )
import StaticFlags( opt_PprStyle_Debug )
import DynFlags
import Outputable
import FastString

-- -----------------------------------------------------------------------------
-- Pretty-printing entities that we get from the GHC API

-- This should be a good source of sample code for using the GHC API to
-- inspect source code entities.

type ShowSub = [Name]
--   []     <=> print all sub-components of the current thing
--   (n:ns) <=> print sub-component 'n' with ShowSub=ns
--              elide other sub-components to "..."
showAll :: ShowSub
showAll = []

showSub :: NamedThing n => ShowSub -> n -> Bool
showSub []    _     = True
showSub (n:_) thing = n == getName thing

showSub_maybe :: NamedThing n => ShowSub -> n -> Maybe ShowSub
showSub_maybe []     _     = Just []
showSub_maybe (n:ns) thing = if n == getName thing then Just ns
                                                   else Nothing

----------------------------
-- | Pretty-prints a 'TyThing' with its defining location.
pprTyThingLoc :: TyThing -> SDoc
pprTyThingLoc tyThing
  = showWithLoc (pprDefinedAt (getName tyThing)) (pprTyThing tyThing)

-- | Pretty-prints a 'TyThing'.
pprTyThing :: TyThing -> SDoc
pprTyThing thing = ppr_ty_thing (Just showAll) thing

-- | Pretty-prints a 'TyThing' in context: that is, if the entity
-- is a data constructor, record selector, or class method, then
-- the entity's parent declaration is pretty-printed with irrelevant
-- parts omitted.
pprTyThingInContext :: TyThing -> SDoc
pprTyThingInContext thing
  = go [] thing
  where
    go ss thing = case tyThingParent_maybe thing of
                    Just parent -> go (getName thing : ss) parent
                    Nothing     -> ppr_ty_thing (Just ss) thing

-- | Like 'pprTyThingInContext', but adds the defining location.
pprTyThingInContextLoc :: TyThing -> SDoc
pprTyThingInContextLoc tyThing
  = showWithLoc (pprDefinedAt (getName tyThing))
                (pprTyThingInContext tyThing)

-- | Pretty-prints the 'TyThing' header. For functions and data constructors
-- the function is equivalent to 'pprTyThing' but for type constructors
-- and classes it prints only the header part of the declaration.
pprTyThingHdr :: TyThing -> SDoc
pprTyThingHdr = ppr_ty_thing Nothing

------------------------
-- NOTE: We pretty-print 'TyThing' via 'IfaceDecl' so that we can reuse the
-- 'TyCon' tidying happening in 'tyThingToIfaceDecl'. See #8776 for details.
ppr_ty_thing :: Maybe ShowSub -> TyThing -> SDoc
ppr_ty_thing mss tyThing = case tyThing of
    AnId id -> pprId id
    ATyCon tyCon -> case mss of
        Nothing -> pprTyConHdr tyCon
        Just ss -> pprTyCon ss tyCon
    _ -> ppr $ tyThingToIfaceDecl tyThing

pprTyConHdr :: TyCon -> SDoc
pprTyConHdr tyCon
  | Just (fam_tc, tys) <- tyConFamInst_maybe tyCon
  = ptext keyword <+> ptext (sLit "instance") <+> pprTypeApp fam_tc tys
  | Just cls <- tyConClass_maybe tyCon
  = pprClassHdr cls
  | otherwise
  = sdocWithDynFlags $ \dflags ->
    ptext keyword <+> opt_family <+> opt_stupid <+> ppr_bndr tyCon
    <+> pprTvBndrs (suppressKinds dflags (tyConKind tyCon) vars)
  where
    vars | isPrimTyCon tyCon ||
	   isFunTyCon tyCon = take (tyConArity tyCon) alphaTyVars
	 | otherwise = tyConTyVars tyCon

    keyword | isSynTyCon tyCon = sLit "type"
            | isNewTyCon tyCon = sLit "newtype"
            | otherwise            = sLit "data"

    opt_family
      | isFamilyTyCon tyCon = ptext (sLit "family")
      | otherwise             = empty

    opt_stupid 	-- The "stupid theta" part of the declaration
	| isAlgTyCon tyCon = pprThetaArrowTy (tyConStupidTheta tyCon)
	| otherwise	   = empty	-- Returns 'empty' if null theta

pprClassHdr :: Class -> SDoc
pprClassHdr cls
  = sdocWithDynFlags $ \dflags ->
    ptext (sLit "class") <+>
    sep [ pprThetaArrowTy (classSCTheta cls)
        , ppr_bndr cls
          <+> pprTvBndrs (suppressKinds dflags (tyConKind (classTyCon cls)) tvs)
        , pprFundeps funDeps ]
  where
     (tvs, funDeps) = classTvsFds cls

pprId :: Var -> SDoc
pprId ident
  = hang (ppr_bndr ident <+> dcolon)
	 2 (pprTypeForUser (idType ident))

pprTypeForUser :: Type -> SDoc
-- We do two things here.
-- a) We tidy the type, regardless
-- b) If Opt_PrintExplicitForAlls is True, we discard the foralls
-- 	but we do so `deeply'
-- Prime example: a class op might have type
--	forall a. C a => forall b. Ord b => stuff
-- Then we want to display
--	(C a, Ord b) => stuff
pprTypeForUser ty
  = sdocWithDynFlags $ \ dflags ->
    if gopt Opt_PrintExplicitForalls dflags
    then ppr tidy_ty
    else ppr (mkPhiTy ctxt ty')
  where
    (_, ctxt, ty') = tcSplitSigmaTy tidy_ty
    (_, tidy_ty)   = tidyOpenType emptyTidyEnv ty
     -- Often the types/kinds we print in ghci are fully generalised
     -- and have no free variables, but it turns out that we sometimes
     -- print un-generalised kinds (eg when doing :k T), so it's
     -- better to use tidyOpenType here

pprTyCon :: ShowSub -> TyCon -> SDoc
pprTyCon ss tyCon
  | Just syn_rhs <- synTyConRhs_maybe tyCon
  = case syn_rhs of
      OpenSynFamilyTyCon    -> pp_tc_with_kind
      BuiltInSynFamTyCon {} -> pp_tc_with_kind

      ClosedSynFamilyTyCon (CoAxiom { co_ax_branches = branches })
         -> hang closed_family_header
              2  (vcat (brListMap (pprCoAxBranch tyCon) branches))

      AbstractClosedSynFamilyTyCon
         -> closed_family_header <+> ptext (sLit "..")

      SynonymTyCon rhs_ty
         -> hang (pprTyConHdr tyCon <+> equals)
               2 (ppr rhs_ty)   -- Don't suppress foralls on RHS type!

                                                 -- e.g. type T = forall a. a->a
  | Just cls <- tyConClass_maybe tyCon
  = (pp_roles (== Nominal)) $$ pprClass ss cls

  | otherwise
  = (pp_roles (== Representational)) $$ pprAlgTyCon ss tyCon

  where
      -- if, for each role, suppress_if role is True, then suppress the role
      -- output
    pp_roles :: (Role -> Bool) -> SDoc
    pp_roles suppress_if
      = sdocWithDynFlags $ \dflags ->
        let roles = suppressKinds dflags (tyConKind tyCon) (tyConRoles tyCon)
        in ppUnless (isFamInstTyCon tyCon || all suppress_if roles) $
             -- Don't display roles for data family instances (yet)
             -- See discussion on Trac #8672.
           ptext (sLit "type role") <+> ppr tyCon <+> hsep (map ppr roles)

    pp_tc_with_kind = vcat [ pp_roles (const True)
                           , pprTyConHdr tyCon <+> dcolon
                             <+> pprTypeForUser (synTyConResKind tyCon) ]
    closed_family_header
       = pp_tc_with_kind <+> ptext (sLit "where")

pprAlgTyCon :: ShowSub -> TyCon -> SDoc
pprAlgTyCon ss tyCon
  | gadt      = pprTyConHdr tyCon <+> ptext (sLit "where") $$
		   nest 2 (vcat (ppr_trim (map show_con datacons)))
  | otherwise = hang (pprTyConHdr tyCon)
    		   2 (add_bars (ppr_trim (map show_con datacons)))
  where
    datacons = tyConDataCons tyCon
    gadt = any (not . isVanillaDataCon) datacons

    ok_con dc = showSub ss dc || any (showSub ss) (dataConFieldLabels dc)
    show_con dc
      | ok_con dc = Just (pprDataConDecl ss gadt dc)
      | otherwise = Nothing

pprDataConDecl :: ShowSub -> Bool -> DataCon -> SDoc
pprDataConDecl ss gadt_style dataCon
  | not gadt_style = ppr_fields tys_w_strs
  | otherwise      = ppr_bndr dataCon <+> dcolon <+>
			sep [ pp_foralls, pprThetaArrowTy theta, pp_tau ]
	-- Printing out the dataCon as a type signature, in GADT style
  where
    (forall_tvs, theta, tau) = tcSplitSigmaTy (dataConUserType dataCon)
    (arg_tys, res_ty)        = tcSplitFunTys tau
    labels     = dataConFieldLabels dataCon
    stricts    = dataConStrictMarks dataCon
    tys_w_strs = zip (map user_ify stricts) arg_tys
    pp_foralls = sdocWithDynFlags $ \dflags ->
                 ppWhen (gopt Opt_PrintExplicitForalls dflags)
                        (pprForAll forall_tvs)

    pp_tau = foldr add (ppr res_ty) tys_w_strs
    add str_ty pp_ty = pprParendBangTy str_ty <+> arrow <+> pp_ty

    pprParendBangTy (bang,ty) = ppr bang <> pprParendType ty
    pprBangTy       (bang,ty) = ppr bang <> ppr ty

    -- See Note [Printing bangs on data constructors]
    user_ify :: HsBang -> HsBang
    user_ify bang | opt_PprStyle_Debug = bang
    user_ify HsStrict                  = HsUserBang Nothing     True
    user_ify (HsUnpack {})             = HsUserBang (Just True) True
    user_ify bang                      = bang

    maybe_show_label (lbl,bty)
	| showSub ss lbl = Just (ppr_bndr lbl <+> dcolon <+> pprBangTy bty)
	| otherwise      = Nothing

    ppr_fields [ty1, ty2]
	| dataConIsInfix dataCon && null labels
	= sep [pprParendBangTy ty1, pprInfixName dataCon, pprParendBangTy ty2]
    ppr_fields fields
	| null labels
	= ppr_bndr dataCon <+> sep (map pprParendBangTy fields)
	| otherwise
	= ppr_bndr dataCon
	  <+> (braces $ sep $ punctuate comma $ ppr_trim $
               map maybe_show_label (zip labels fields))

pprClass :: ShowSub -> Class -> SDoc
pprClass ss cls
  | null methods && null assoc_ts
  = pprClassHdr cls
  | otherwise
  = vcat [ pprClassHdr cls <+> ptext (sLit "where")
         , nest 2 (vcat $ ppr_trim $ 
                   map show_at assoc_ts ++ map show_meth methods)]
  where
    methods  = classMethods cls
    assoc_ts = classATs cls
    show_meth id | showSub ss id  = Just (pprClassMethod id)
	         | otherwise      = Nothing
    show_at tc = case showSub_maybe ss tc of
                      Just ss' -> Just (pprTyCon ss' tc)
                      Nothing  -> Nothing

pprClassMethod :: Id -> SDoc
pprClassMethod id
  = hang (ppr_bndr id <+> dcolon) 2 (pprTypeForUser op_ty)
  where
  -- Here's the magic incantation to strip off the dictionary
  -- from the class op type.  Stolen from IfaceSyn.tyThingToIfaceDecl.
  --
  -- It's important to tidy it *before* splitting it up, so that if
  -- we have	class C a b where
  --	          op :: forall a. a -> b
  -- then the inner forall on op gets renamed to a1, and we print
  -- (when dropping foralls)
  --		class C a b where
  --		  op :: a1 -> b

  tidy_sel_ty = tidyTopType (idType id)
  (_sel_tyvars, rho_ty) = splitForAllTys tidy_sel_ty
  op_ty = funResultTy rho_ty

ppr_trim :: [Maybe SDoc] -> [SDoc]
-- Collapse a group of Nothings to a single "..."
ppr_trim xs
  = snd (foldr go (False, []) xs)
  where
    go (Just doc) (_,     so_far) = (False, doc : so_far)
    go Nothing    (True,  so_far) = (True, so_far)
    go Nothing    (False, so_far) = (True, ptext (sLit "...") : so_far)

add_bars :: [SDoc] -> SDoc
add_bars []      = empty
add_bars [c]     = equals <+> c
add_bars (c:cs)  = sep ((equals <+> c) : map (char '|' <+>) cs)

-- Wrap operators in ()
ppr_bndr :: NamedThing a => a -> SDoc
ppr_bndr a = parenSymOcc (getOccName a) (ppr (getName a))

showWithLoc :: SDoc -> SDoc -> SDoc
showWithLoc loc doc
    = hang doc 2 (char '\t' <> comment <+> loc)
		-- The tab tries to make them line up a bit
  where
    comment = ptext (sLit "--")

{-
Note [Printing bangs on data constructors]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For imported data constructors the dataConStrictMarks are the
representation choices (see Note [Bangs on data constructor arguments]
in DataCon.lhs). So we have to fiddle a little bit here to turn them
back into user-printable form.
-}