summaryrefslogtreecommitdiff
path: root/ghc/compiler/abstractSyn/HsPat.lhs
blob: 35b54e46d1c6400db4f926059a298873e56f3bf8 (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
349
350
351
352
%
% (c) The GRASP/AQUA Project, Glasgow University, 1992-1994
%
\section[PatSyntax]{Abstract Haskell syntax---patterns}

\begin{code}
#include "HsVersions.h"

module HsPat where

import AbsPrel		( mkTupleTy, mkListTy
			  IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
			  IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
#ifdef DPH
			  , mkProcessorTy
#endif 
			)
import AbsUniType
import HsLit		( Literal )
import HsExpr		( Expr, TypecheckedExpr(..) )
import Id
import IdInfo
import Maybes		( maybeToBool, Maybe(..) )
import Name		( Name )
import ProtoName	( ProtoName(..) ) -- .. for pragmas only
import Outputable
import Pretty
import Unique		( Unique )
import Util
\end{code}

Patterns come in distinct before- and after-typechecking flavo(u)rs.
\begin{code}
data InPat name
  = WildPatIn				--X wild card
  | VarPatIn	    name		--X variable
  | LitPatIn	    Literal		--  literal
  | LazyPatIn	    (InPat name)	--X lazy pattern
  | AsPatIn	    name		--X as pattern
		    (InPat name)
  | ConPatIn	    name		--X constructed type
		    [(InPat name)]
  | ConOpPatIn	    (InPat name)
		    name
		    (InPat name)
  | ListPatIn	    [InPat name]		--X syntactic list
					-- must have >= 1 elements
  | TuplePatIn	    [InPat name]		--X tuple
					-- UnitPat is TuplePat []
  | NPlusKPatIn	    name		--  n+k pattern
		    Literal
#ifdef DPH
  | ProcessorPatIn  [(InPat name)] 
		     (InPat name)	-- (|pat1,...,patK;pat|)
#endif {- Data Parallel Haskell -}

type ProtoNamePat = InPat ProtoName
type RenamedPat = InPat Name

data TypecheckedPat
  = WildPat	    UniType 	    	-- wild card

  | VarPat	    Id			-- variable (type is in the Id)

  | LazyPat	    TypecheckedPat	-- lazy pattern

  | AsPat	    Id		-- as pattern
		    TypecheckedPat

  | ConPat	    Id		-- constructed type;
		    UniType    		-- the type of the pattern
		    [TypecheckedPat]

  | ConOpPat	    TypecheckedPat	-- just a special case...
		    Id
		    TypecheckedPat
		    UniType
  | ListPat		 	    	-- syntactic list
		    UniType		-- the type of the elements
   	    	    [TypecheckedPat]

  | TuplePat	    [TypecheckedPat]	-- tuple
					-- UnitPat is TuplePat []

  | LitPat	    -- Used for *non-overloaded* literal patterns:
		    -- Int#, Char#, Int, Char, String, etc.
		    Literal
		    UniType 	    	-- type of pattern

  | NPat	    -- Used for *overloaded* literal patterns
		    Literal		-- the literal is retained so that
					-- the desugarer can readily identify
					-- equations with identical literal-patterns
		    UniType 	    	-- type of pattern, t
   	    	    TypecheckedExpr 	-- Of type t -> Bool; detects match

  | NPlusKPat	    Id
		    Literal		-- Same reason as for LitPat
					-- (This could be an Integer, but then
					-- it's harder to partitionEqnsByLit
					-- in the desugarer.)
		    UniType 	    	-- Type of pattern, t
		    TypecheckedExpr	-- "fromInteger literal"; of type t
   	    	    TypecheckedExpr 	-- Of type t-> t -> Bool; detects match
   	    	    TypecheckedExpr 	-- Of type t -> t -> t; subtracts k
#ifdef DPH
  | ProcessorPat   
		    [TypecheckedPat]	-- Typechecked Pattern 
		    [TypecheckedExpr]	-- Of type t-> Integer; conversion
		    TypecheckedPat	-- Data at that processor
#endif {- Data Parallel Haskell -}
\end{code}

Note: If @typeOfPat@ doesn't bear a strong resemblance to @typeOfCoreExpr@,
then something is wrong.
\begin{code}
typeOfPat :: TypecheckedPat -> UniType
typeOfPat (WildPat ty)		= ty
typeOfPat (VarPat var)		= getIdUniType var
typeOfPat (LazyPat pat)		= typeOfPat pat
typeOfPat (AsPat var pat)	= getIdUniType var
typeOfPat (ConPat _ ty _)	= ty
typeOfPat (ConOpPat _ _ _ ty)	= ty
typeOfPat (ListPat ty _)	= mkListTy ty
typeOfPat (TuplePat pats)	= mkTupleTy (length pats) (map typeOfPat pats)
typeOfPat (LitPat lit ty)	= ty
typeOfPat (NPat	  lit ty _)	= ty
typeOfPat (NPlusKPat n k ty _ _ _) = ty
#ifdef DPH
-- Should be more efficient to find type of pid than pats 
typeOfPat (ProcessorPat pats _ pat) 
   = mkProcessorTy (map typeOfPat pats) (typeOfPat pat)
#endif {- Data Parallel Haskell -}
\end{code}

\begin{code}
instance (NamedThing name) => NamedThing (InPat name) where
    hasType pat		= False
#ifdef DEBUG
    getExportFlag 	= panic "NamedThing.InPat.getExportFlag"
    isLocallyDefined	= panic "NamedThing.InPat.isLocallyDefined"
    getOrigName		= panic "NamedThing.InPat.getOrigName"
    getOccurrenceName	= panic "NamedThing.InPat.getOccurrenceName"
    getInformingModules	= panic "NamedThing.InPat.getOccurrenceName"
    getSrcLoc		= panic "NamedThing.InPat.getSrcLoc"
    getTheUnique	= panic "NamedThing.InPat.getTheUnique"
    getType pat		= panic "NamedThing.InPat.getType"
    fromPreludeCore	= panic "NamedThing.InPat.fromPreludeCore"
#endif

instance NamedThing TypecheckedPat where
    hasType pat		= True
    getType		= typeOfPat
#ifdef DEBUG
    getExportFlag 	= panic "NamedThing.TypecheckedPat.getExportFlag"
    isLocallyDefined	= panic "NamedThing.TypecheckedPat.isLocallyDefined"
    getOrigName		= panic "NamedThing.TypecheckedPat.getOrigName"
    getOccurrenceName	= panic "NamedThing.TypecheckedPat.getOccurrenceName"
    getInformingModules	= panic "NamedThing.TypecheckedPat.getOccurrenceName"
    getSrcLoc		= panic "NamedThing.TypecheckedPat.getSrcLoc"
    getTheUnique	= panic "NamedThing.TypecheckedPat.getTheUnique"
    fromPreludeCore	= panic "NamedThing.TypecheckedPat.fromPreludeCore"
#endif
\end{code}

\begin{code}
instance (Outputable name) => Outputable (InPat name) where
    ppr = pprInPat

pprInPat :: (Outputable name) => PprStyle -> InPat name -> Pretty
pprInPat sty (WildPatIn)	= ppStr "_"
pprInPat sty (VarPatIn var)	= ppr sty var
pprInPat sty (LitPatIn s)	= ppr sty s
pprInPat sty (LazyPatIn pat)	= ppBeside (ppChar '~') (ppr sty pat)
pprInPat sty (AsPatIn name pat)
    = ppBesides [ppLparen, ppr sty name, ppChar '@', ppr sty pat, ppRparen]

pprInPat sty (ConPatIn c pats)
 = if null pats then
      ppr sty c
   else
      ppBesides [ppLparen, ppr sty c, ppSP, interppSP sty pats, ppRparen]


pprInPat sty (ConOpPatIn pat1 op pat2)
 = ppBesides [ppLparen, ppr sty pat1, ppSP, ppr sty op, ppSP, ppr sty pat2, ppRparen]

-- ToDo: use pprOp to print op (but this involves fiddling various
-- contexts & I'm lazy...); *PatIns are *rarely* printed anyway... (WDP)

pprInPat sty (ListPatIn pats)
  = ppBesides [ppLbrack, interpp'SP sty pats, ppRbrack]
pprInPat sty (TuplePatIn pats)
  = ppBesides [ppLparen, interpp'SP sty pats, ppRparen]
pprInPat sty (NPlusKPatIn n k)
  = ppBesides [ppLparen, ppr sty n, ppChar '+', ppr sty k, ppRparen]
#ifdef DPH
pprInPat sty (ProcessorPatIn pats pat)
      = ppBesides [ppStr "(|", interpp'SP sty pats,ppSemi ,
		   ppr sty pat , ppStr "|)"]
#endif {- Data Parallel Haskell -}
\end{code}

Problems with @Outputable@ instance for @TypecheckedPat@ when no
original names.
\begin{code}
instance Outputable TypecheckedPat where
    ppr = pprTypecheckedPat
\end{code}

\begin{code}
pprTypecheckedPat sty (WildPat ty)	= ppChar '_'
pprTypecheckedPat sty (VarPat var)	= ppr sty var
pprTypecheckedPat sty (LazyPat pat)	= ppBesides [ppChar '~', ppr sty pat]
pprTypecheckedPat sty (AsPat name pat)
  = ppBesides [ppLparen, ppr sty name, ppChar '@', ppr sty pat, ppRparen]

pprTypecheckedPat sty (ConPat name ty [])
  = ppBeside (ppr sty name)
	(ifPprShowAll sty (pprConPatTy sty ty))

pprTypecheckedPat sty (ConPat name ty pats)
  = ppBesides [ppLparen, ppr sty name, ppSP,
    	 interppSP sty pats, ppRparen,
    	 ifPprShowAll sty (pprConPatTy sty ty) ]

pprTypecheckedPat sty (ConOpPat pat1 op pat2 ty)
  = ppBesides [ppLparen, ppr sty pat1, ppSP, pprOp sty op, ppSP, ppr sty pat2, ppRparen]

pprTypecheckedPat sty (ListPat ty pats)
  = ppBesides [ppLbrack, interpp'SP sty pats, ppRbrack]
pprTypecheckedPat sty (TuplePat pats)
  = ppBesides [ppLparen, interpp'SP sty pats, ppRparen]

pprTypecheckedPat sty (LitPat l ty) 	= ppr sty l	-- ToDo: print more
pprTypecheckedPat sty (NPat   l ty e)	= ppr sty l	-- ToDo: print more

pprTypecheckedPat sty (NPlusKPat n k ty e1 e2 e3)
  = case sty of
      PprForUser -> basic_ppr
      _		 -> ppHang basic_ppr 4 exprs_ppr
  where
    basic_ppr = ppBesides [ppLparen, ppr sty n, ppChar '+', ppr sty k, ppRparen]
    exprs_ppr = ppSep [ ppBeside (ppStr "{- ") (ppr sty ty),
			ppr sty e1, ppr sty e2,
			ppBeside (ppr sty e3) (ppStr " -}")]
#ifdef DPH
pprTypecheckedPat sty (ProcessorPat pats convs pat)
   = case sty of
      PprForUser -> basic_ppr
      _		 -> ppHang basic_ppr 4 exprs_ppr
  where
    basic_ppr = ppBesides [ppStr "(|", interpp'SP sty pats,ppSemi ,
		   	   ppr sty pat , ppStr "|)"]
    exprs_ppr = ppBesides [ppStr "{- " ,
			   ppr sty convs,
			   ppStr " -}"]
#endif {- Data Parallel Haskell -}

pprConPatTy :: PprStyle -> UniType -> Pretty
pprConPatTy sty ty
 = ppBesides [ppLparen, ppr sty ty, ppRparen]
\end{code}

%************************************************************************
%*									*
%* predicates for checking things about pattern-lists in EquationInfo	*
%*									*
%************************************************************************
\subsection[Pat-list-predicates]{Look for interesting things in patterns}

Unlike in the Wadler chapter, where patterns are either ``variables''
or ``constructors,'' here we distinguish between:
\begin{description}
\item[unfailable:]
Patterns that cannot fail to match: variables, wildcards, and lazy
patterns.

These are the irrefutable patterns; the two other categories
are refutable patterns.

\item[constructor:]
A non-literal constructor pattern (see next category).

\item[literal (including n+k patterns):]
At least the numeric ones may be overloaded.
\end{description}

A pattern is in {\em exactly one} of the above three categories; `as'
patterns are treated specially, of course.

\begin{code}
unfailablePats :: [TypecheckedPat] -> Bool
unfailablePats pat_list = all unfailablePat pat_list

unfailablePat (AsPat	_ pat)	= unfailablePat pat
unfailablePat (WildPat	_)	= True
unfailablePat (VarPat	_)	= True
unfailablePat (LazyPat	_)	= True
unfailablePat other		= False

patsAreAllCons :: [TypecheckedPat] -> Bool
patsAreAllCons pat_list = all isConPat pat_list

isConPat (AsPat _ pat)		= isConPat pat
isConPat (ConPat _ _ _)		= True
isConPat (ConOpPat _ _ _ _)	= True
isConPat (ListPat _ _)		= True
isConPat (TuplePat _)		= True
#ifdef DPH
isConPat (ProcessorPat _ _ _)	= True

#endif {- Data Parallel Haskell -}
isConPat other			= False

patsAreAllLits :: [TypecheckedPat] -> Bool
patsAreAllLits pat_list = all isLitPat pat_list

isLitPat (AsPat _ pat)		= isLitPat pat
isLitPat (LitPat _ _)		= True
isLitPat (NPat   _ _ _)		= True
isLitPat (NPlusKPat _ _ _ _ _ _)= True
isLitPat other			= False

#ifdef DPH
patsAreAllProcessor :: [TypecheckedPat] -> Bool
patsAreAllProcessor pat_list = all isProcessorPat pat_list
   where
      isProcessorPat (ProcessorPat _ _ _) = True
      isProcessorPat _			  = False
#endif 
\end{code}

\begin{code}
-- A pattern is irrefutable if a match on it cannot fail
-- (at any depth)
irrefutablePat :: TypecheckedPat -> Bool

irrefutablePat (WildPat _) 		  = True
irrefutablePat (VarPat _)  		  = True
irrefutablePat (LazyPat	_) 		  = True
irrefutablePat (AsPat _ pat)		  = irrefutablePat pat
irrefutablePat (ConPat con tys pats)	  = all irrefutablePat pats && only_con con
irrefutablePat (ConOpPat pat1 con pat2 _) = irrefutablePat pat1 && irrefutablePat pat1 && only_con con
irrefutablePat (ListPat _ _)		  = False
irrefutablePat (TuplePat pats)		  = all irrefutablePat pats
irrefutablePat other_pat		  = False	-- Literals, NPlusK, NPat

only_con con = maybeToBool (maybeSingleConstructorTyCon tycon)
 	       where
		 (_,_,_, tycon) = getDataConSig con
\end{code}