2 % (c) The GRASP/AQUA Project, Glasgow University, 1997-1998
4 % Author: Juan J. Quintela <quintela@krilin.dc.fi.udc.es>
9 module Check ( check , ExhaustivePat, WarningPat, BoxedString(..) ) where
13 import TcHsSyn ( TypecheckedPat )
14 import DsHsSyn ( outPatType )
17 import DsUtils ( EquationInfo(..),
28 import IdInfo ( ArityInfo(..) )
29 import Lex ( isLexConSym )
30 import Name ( occNameString,
41 import TyVar ( TyVar )
42 import TysPrim ( intPrimTy,
49 import TysWiredIn ( nilDataCon, consDataCon,
54 floatTy, floatDataCon,
55 doubleTy, doubleDataCon,
60 import TyCon ( tyConDataCons )
62 import Unique ( Unique )
65 #include "HsVersions.h"
68 This module performs checks about if one list of equations are:
72 To discover that we go through the list of equations in a tree-like fashion.
74 If you like theory, a similar algorithm is described in:
75 Two Techniques for Compiling Lazy Pattern Matching
77 INRIA Rocquencourt (RR-2385, 1994)
79 The algorithm is based in the first Technique, but there are some differences:
80 - We don't generate code
81 - We have constructors and literals (not only literals as in the
83 - We don't use directions, we must select the columns from
86 (By the way the second technique is really similar to the one used in
87 Match.lhs to generate code)
89 This function takes the equations of a pattern and returns:
90 - The patterns that are not recognized
91 - The equations that are not overlapped
93 It simplify the patterns and then call check' (the same semantics),and it
94 needs to reconstruct the patterns again ....
96 The problem appear with things like:
100 We want to put the two patterns with the same syntax, (prefix form) and
101 then all the constructors are equal:
102 f (: x (: y [])) = ....
105 (more about that in simplify_eqns)
107 We would prefer to have a WarningPat of type String, but Strings and the
108 Pretty Printer are not friends.
110 We use InPat in WarningPat instead of OutPat because we need to print the
111 warning messages in the same way they are introduced, i.e. if the user
115 He don't want a warning message written:
117 f (: x (: y [])) ........
119 Then we need to use InPats.
121 Juan Quintela 5 JUL 1998
122 User-friendliness and compiler writers are no friends.
126 newtype BoxedString = BS String
128 type WarningPat = InPat BoxedString
129 type ExhaustivePat = ([WarningPat], [(BoxedString, [HsLit])])
132 instance Outputable BoxedString where
136 check :: [EquationInfo] -> ([ExhaustivePat],EqnSet)
137 check qs = (untidy_warns, incomplete)
139 (warns, incomplete) = check' (simplify_eqns qs)
140 untidy_warns = map untidy_exhaustive warns
142 untidy_exhaustive :: ExhaustivePat -> ExhaustivePat
143 untidy_exhaustive ([pat], messages) =
144 ([untidy_no_pars pat], map untidy_message messages)
145 untidy_exhaustive (pats, messages) =
146 (map untidy_pars pats, map untidy_message messages)
148 untidy_message :: (BoxedString, [HsLit]) -> (BoxedString, [HsLit])
149 untidy_message (string, lits) = (string, map untidy_lit lits)
152 The function @untidy@ does the reverse work of the @simplify_pat@ funcion.
158 untidy_no_pars :: WarningPat -> WarningPat
159 untidy_no_pars p = untidy False p
161 untidy_pars :: WarningPat -> WarningPat
162 untidy_pars p = untidy True p
164 untidy :: NeedPars -> WarningPat -> WarningPat
165 untidy _ p@WildPatIn = p
166 untidy _ p@(VarPatIn name) = p
167 untidy _ (LitPatIn lit) = LitPatIn (untidy_lit lit)
168 untidy _ p@(ConPatIn name []) = p
169 untidy b (ConPatIn name pats) =
170 pars b (ConPatIn name (map untidy_pars pats))
171 untidy b (ConOpPatIn pat1 name fixity pat2) =
172 pars b (ConOpPatIn (untidy_pars pat1) name fixity (untidy_pars pat2))
173 untidy _ (ListPatIn pats) = ListPatIn (map untidy_no_pars pats)
174 untidy _ (TuplePatIn pats) = TuplePatIn (map untidy_no_pars pats)
176 untidy _ (LazyPatIn pat) = panic "Check.untidy: LazyPatIn"
177 untidy _ (AsPatIn name pat) = panic "Check.untidy: AsPatIn"
178 untidy _ (NPlusKPatIn name lit) = panic "Check.untidy: NPlusKPatIn"
179 untidy _ (NegPatIn ipat) = panic "Check.untidy: NegPatIn"
180 untidy _ (ParPatIn pat) = panic "Check.untidy: ParPatIn"
181 untidy _ (RecPatIn name fields) = panic "Check.untidy: RecPatIn"
182 -- [(name, InPat name, Bool)] -- True <=> source used punning
184 pars :: NeedPars -> WarningPat -> WarningPat
185 pars True p = ParPatIn p
188 untidy_lit :: HsLit -> HsLit
189 untidy_lit (HsCharPrim c) = HsChar c
190 --untidy_lit (HsStringPrim s) = HsString s
194 This equation is the same that check, the only difference is that the
195 boring work is done, that work needs to be done only once, this is
196 the reason top have two functions, check is the external interface,
197 check' is called recursively.
199 There are several cases:
202 \item There are no equations: Everything is OK.
203 \item There are only one equation, that can fail, and all the patterns are
204 variables. Then that equation is used and the same equation is
206 \item All the patterns are variables, and the match can fail, there are
207 more equations then the results is the result of the rest of equations
208 and this equation is used also.
210 \item The general case, if all the patterns are variables (here the match
211 can't fail) then the result is that this equation is used and this
212 equation doesn't generate non-exhaustive cases.
214 \item In the general case, there can exist literals ,constructors or only
215 vars in the first column, we actuate in consequence.
222 check' :: [EquationInfo] -> ([ExhaustivePat],EqnSet)
223 check' [] = ([([],[])],emptyUniqSet)
225 check' [EqnInfo n ctx ps (MatchResult CanFail _ _)]
226 | all_vars ps = ([(take (length ps) (repeat new_wild_pat),[])], unitUniqSet n)
228 check' qs@((EqnInfo n ctx ps (MatchResult CanFail _ _)):_)
229 | all_vars ps = (pats, addOneToUniqSet indexs n)
231 (pats,indexs) = check' (tail qs)
233 check' qs@((EqnInfo n ctx ps result):_)
234 | all_vars ps = ([], unitUniqSet n)
235 -- | nplusk = panic "Check.check': Work in progress: nplusk"
236 -- | npat = panic "Check.check': Work in progress: npat ?????"
237 | literals = split_by_literals qs
238 | constructors = split_by_constructor qs
239 | only_vars = first_column_only_vars qs
240 | otherwise = panic "Check.check': Not implemented :-("
242 constructors = or (map is_con qs)
243 literals = or (map is_lit qs)
244 -- npat = or (map is_npat qs)
245 -- nplusk = or (map is_nplusk qs)
246 only_vars = and (map is_var qs)
249 Here begins the code to deal with literals, we need to split the matrix
250 in different matrix beginning by each literal and a last matrix with the
254 split_by_literals :: [EquationInfo] -> ([ExhaustivePat],EqnSet)
255 split_by_literals qs = process_literals used_lits qs
257 used_lits = get_used_lits qs
260 process_explicit_literals is a function that process each literal that appears
261 in the column of the matrix.
264 process_explicit_literals :: [HsLit] -> [EquationInfo] -> ([ExhaustivePat],EqnSet)
265 process_explicit_literals lits qs = (concat pats, unionManyUniqSets indexs)
267 pats_indexs = map (\x -> construct_literal_matrix x qs) lits
268 (pats,indexs) = unzip pats_indexs
273 Process_literals calls process_explicit_literals to deal with the literals
274 that appears in the matrix and deal also with the rest of the cases. It
275 must be one Variable to be complete.
279 process_literals :: [HsLit] -> [EquationInfo] -> ([ExhaustivePat],EqnSet)
280 process_literals used_lits qs
281 | length default_eqns == 0 = ([make_row_vars used_lits (head qs)]++pats,indexs)
282 | otherwise = (pats_default,indexs_default)
284 (pats,indexs) = process_explicit_literals used_lits qs
285 default_eqns = (map remove_var (filter is_var qs))
286 (pats',indexs') = check' default_eqns
287 pats_default = [(new_wild_pat:ps,constraints) | (ps,constraints) <- (pats')] ++ pats
288 indexs_default = unionUniqSets indexs' indexs
291 Here we have selected the literal and we will select all the equations that
292 begins for that literal and create a new matrix.
295 construct_literal_matrix :: HsLit -> [EquationInfo] -> ([ExhaustivePat],EqnSet)
296 construct_literal_matrix lit qs =
297 (map (\ (xs,ys) -> (new_lit:xs,ys)) pats,indexs)
299 (pats,indexs) = (check' (remove_first_column_lit lit qs))
300 new_lit = LitPatIn lit
302 remove_first_column_lit :: HsLit
305 remove_first_column_lit lit qs =
306 map shift_pat (filter (is_var_lit lit) qs)
308 shift_pat (EqnInfo n ctx [] result) = panic "Check.shift_var: no patterns"
309 shift_pat (EqnInfo n ctx (_:ps) result) = EqnInfo n ctx ps result
313 This function splits the equations @qs@ in groups that deal with the
318 split_by_constructor :: [EquationInfo] -> ([ExhaustivePat],EqnSet)
320 split_by_constructor qs | length unused_cons /= 0 = need_default_case used_cons unused_cons qs
321 | otherwise = no_need_default_case used_cons qs
323 used_cons = get_used_cons qs
324 unused_cons = get_unused_cons used_cons
328 The first column of the patterns matrix only have vars, then there is
332 first_column_only_vars :: [EquationInfo] -> ([ExhaustivePat],EqnSet)
333 first_column_only_vars qs = (map (\ (xs,ys) -> (new_wild_pat:xs,ys)) pats,indexs)
335 (pats,indexs) = check' (map remove_var qs)
339 This equation takes a matrix of patterns and split the equations by
340 constructor, using all the constructors that appears in the first column
341 of the pattern matching.
343 We can need a default clause or not ...., it depends if we used all the
344 constructors or not explicitly. The reasoning is similar to process_literals,
345 the difference is that here the default case is not always needed.
348 no_need_default_case :: [TypecheckedPat] -> [EquationInfo] -> ([ExhaustivePat],EqnSet)
349 no_need_default_case cons qs = (concat pats, unionManyUniqSets indexs)
351 pats_indexs = map (\x -> construct_matrix x qs) cons
352 (pats,indexs) = unzip pats_indexs
354 need_default_case :: [TypecheckedPat] -> [Id] -> [EquationInfo] -> ([ExhaustivePat],EqnSet)
355 need_default_case used_cons unused_cons qs
356 | length default_eqns == 0 = (pats_default_no_eqns,indexs)
357 | otherwise = (pats_default,indexs_default)
359 (pats,indexs) = no_need_default_case used_cons qs
360 default_eqns = (map remove_var (filter is_var qs))
361 (pats',indexs') = check' default_eqns
362 pats_default = [(make_whole_con c:ps,constraints) |
363 c <- unused_cons, (ps,constraints) <- pats'] ++ pats
364 new_wilds = make_row_vars_for_constructor (head qs)
365 pats_default_no_eqns = [(make_whole_con c:new_wilds,[]) | c <- unused_cons] ++ pats
366 indexs_default = unionUniqSets indexs' indexs
368 construct_matrix :: TypecheckedPat -> [EquationInfo] -> ([ExhaustivePat],EqnSet)
369 construct_matrix con qs =
371 (map (make_con con) pats,indexs)
373 (pats,indexs) = (check' (remove_first_column con qs))
376 Here remove first column is more difficult that with literals due to the fact
377 that constructors can have arguments.
379 For instance, the matrix
391 remove_first_column :: TypecheckedPat -- Constructor
394 remove_first_column (ConPat con _ con_pats) qs =
395 map shift_var (filter (is_var_con con) qs)
397 new_wilds = [WildPat (outPatType arg_pat) | arg_pat <- con_pats]
398 shift_var (EqnInfo n ctx (ConPat _ _ ps':ps) result) =
399 EqnInfo n ctx (ps'++ps) result
400 shift_var (EqnInfo n ctx (WildPat _ :ps) result) =
401 EqnInfo n ctx (new_wilds ++ ps) result
402 shift_var _ = panic "Check.shift_var: Not implemented"
404 make_row_vars :: [HsLit] -> EquationInfo -> ExhaustivePat
405 make_row_vars used_lits (EqnInfo _ _ pats _ ) =
406 (VarPatIn new_var:take (length (tail pats)) (repeat new_wild_pat),[(new_var,used_lits)])
407 where new_var = BS "#x"
409 make_row_vars_for_constructor :: EquationInfo -> [WarningPat]
410 make_row_vars_for_constructor (EqnInfo _ _ pats _ ) = take (length (tail pats)) (repeat new_wild_pat)
412 compare_cons :: TypecheckedPat -> TypecheckedPat -> Bool
413 compare_cons (ConPat id1 _ _) (ConPat id2 _ _) = id1 == id2
415 remove_dups :: [TypecheckedPat] -> [TypecheckedPat]
417 remove_dups (x:xs) | or (map (\y -> compare_cons x y) xs) = remove_dups xs
418 | otherwise = x : remove_dups xs
420 get_used_cons :: [EquationInfo] -> [TypecheckedPat]
421 get_used_cons qs = remove_dups [con | (EqnInfo _ _ (con@(ConPat _ _ _):_) _) <- qs]
423 remove_dups' :: [HsLit] -> [HsLit]
425 remove_dups' (x:xs) | x `elem` xs = remove_dups' xs
426 | otherwise = x : remove_dups' xs
429 get_used_lits :: [EquationInfo] -> [HsLit]
430 get_used_lits qs = remove_dups' all_literals
432 all_literals = get_used_lits' qs
434 get_used_lits' :: [EquationInfo] -> [HsLit]
435 get_used_lits' [] = []
436 get_used_lits' ((EqnInfo _ _ ((LitPat lit _):_) _):qs) =
437 lit : get_used_lits qs
438 get_used_lits' ((EqnInfo _ _ ((NPat lit _ _):_) _):qs) =
439 lit : get_used_lits qs
440 get_used_lits' (q:qs) =
443 get_unused_cons :: [TypecheckedPat] -> [Id]
444 get_unused_cons used_cons = unused_cons
446 (ConPat _ ty _) = head used_cons
447 Just (ty_con,_) = splitTyConApp_maybe ty
448 all_cons = tyConDataCons ty_con
449 used_cons_as_id = map (\ (ConPat id _ _) -> id) used_cons
450 unused_cons = uniqSetToList (mkUniqSet all_cons `minusUniqSet` mkUniqSet used_cons_as_id)
452 all_vars :: [TypecheckedPat] -> Bool
454 all_vars (WildPat _:ps) = all_vars ps
457 remove_var :: EquationInfo -> EquationInfo
458 remove_var (EqnInfo n ctx (WildPat _:ps) result) = EqnInfo n ctx ps result
459 remove_var _ = panic "Check:remove_var: equation not begin with a variable"
461 is_con :: EquationInfo -> Bool
462 is_con (EqnInfo _ _ ((ConPat _ _ _):_) _) = True
465 is_lit :: EquationInfo -> Bool
466 is_lit (EqnInfo _ _ ((LitPat _ _):_) _) = True
467 is_lit (EqnInfo _ _ ((NPat _ _ _):_) _) = True
470 is_npat :: EquationInfo -> Bool
471 is_npat (EqnInfo _ _ ((NPat _ _ _):_) _) = True
474 is_nplusk :: EquationInfo -> Bool
475 is_nplusk (EqnInfo _ _ ((NPlusKPat _ _ _ _ _):_) _) = True
478 is_var :: EquationInfo -> Bool
479 is_var (EqnInfo _ _ ((WildPat _):_) _) = True
482 is_var_con :: Id -> EquationInfo -> Bool
483 is_var_con con (EqnInfo _ _ ((WildPat _):_) _) = True
484 is_var_con con (EqnInfo _ _ ((ConPat id _ _):_) _) | id == con = True
485 is_var_con con _ = False
487 is_var_lit :: HsLit -> EquationInfo -> Bool
488 is_var_lit lit (EqnInfo _ _ ((WildPat _):_) _) = True
489 is_var_lit lit (EqnInfo _ _ ((LitPat lit' _):_) _) | lit == lit' = True
490 is_var_lit lit (EqnInfo _ _ ((NPat lit' _ _):_) _) | lit == lit' = True
491 is_var_lit lit _ = False
494 The difference between make_con and make_whole_con is that make_whole_con
495 creates a new constructor with all their arguments, and make_con takes a
496 list of arguments, creates the constructor getting their arguments from the
497 list. See where are used for details.
499 We need to reconstruct the patterns (make the constructors infix and
500 similar) at the same time that we create the constructors.
502 You can tell tuple constructors using
506 You can see if one constructor is infix with this clearer code :-))))))))))
508 Lex.isLexConSym (Name.occNameString (Name.getOccName con))
510 Rather clumsy but it works. (Simon Peyton Jones)
513 We don't mind the nilDataCon because it doesn't change the way to print the
514 message, we are searching only for things like: [1,2,3], not x:xs ....
517 In reconstruct_pat we want to "undo" the work that we have done in simplify_pat
519 ((,) x y) returns to be (x, y)
520 ((:) x xs) returns to be (x:xs)
521 (x:(...:[]) returns to be [x,...]
523 The difficult case is the third one because we need to follow all the
524 constructors until the [] to know that we need to use the second case,
529 isInfixCon con = isLexConSym (occNameString (getOccName con))
531 is_nil (ConPatIn (BS con) []) = con == getOccString nilDataCon
534 is_list (ListPatIn _) = True
537 return_list id q = id == consDataCon && (is_nil q || is_list q)
539 make_list p q | is_nil q = ListPatIn [p]
540 make_list p (ListPatIn ps) = ListPatIn (p:ps)
541 make_list _ _ = panic "Check.make_list: Invalid argument"
543 make_con :: TypecheckedPat -> ExhaustivePat -> ExhaustivePat
544 make_con (ConPat id ty pats) (p:q:ps, constraints)
545 | return_list id q = (make_list p q : ps, constraints)
546 | isInfixCon id = ((ConOpPatIn p name fixity q) : ps, constraints)
547 where name = BS (getOccString id)
548 fixity = panic "Check.make_con: Guessing fixity"
549 make_con (ConPat id ty pats) (ps,constraints)
550 | isTupleCon id = (TuplePatIn pats_con : rest_pats, constraints)
551 | otherwise = (ConPatIn name pats_con : rest_pats, constraints)
552 where num_args = length pats
553 name = BS (getOccString id)
554 pats_con = take num_args ps
555 rest_pats = drop num_args ps
558 make_whole_con :: Id -> WarningPat
559 make_whole_con con | isInfixCon con = ConOpPatIn new_wild_pat name fixity new_wild_pat
560 | otherwise = ConPatIn name pats
562 fixity = panic "Check.make_whole_con: Guessing fixity"
563 name = BS (getOccString con)
564 arity = get_int_arity con
565 pats = take arity (repeat new_wild_pat)
568 new_wild_pat :: WarningPat
569 new_wild_pat = WildPatIn
571 get_int_arity :: Id -> Int
572 get_int_arity id = arity_to_int (getIdArity id)
574 arity_to_int (ArityExactly n) = n
575 arity_to_int _ = panic "Check.getIntArity: Unknown arity"
579 This equation makes the same thing that tidy in Match.lhs, the
580 difference is that here we can do all the tidy in one place and in the
581 Match tidy it must be done one column each time due to bookkeeping
586 simplify_eqns :: [EquationInfo] -> [EquationInfo]
587 simplify_eqns [] = []
588 simplify_eqns ((EqnInfo n ctx pats result):qs) =
589 (EqnInfo n ctx pats' result) : simplify_eqns qs
591 pats' = map simplify_pat pats
593 simplify_pat :: TypecheckedPat -> TypecheckedPat
595 simplify_pat pat@(WildPat gt) = pat
596 simplify_pat (VarPat id) = WildPat (idType id)
598 simplify_pat (LazyPat p) = simplify_pat p
600 simplify_pat (AsPat id p) = simplify_pat p
602 simplify_pat (ConPat id ty ps) = ConPat id ty (map simplify_pat ps)
604 simplify_pat (ConOpPat p1 id p2 ty) = ConPat id ty (map simplify_pat [p1,p2])
606 simplify_pat (ListPat ty ps) = foldr (\ x -> \y -> ConPat consDataCon list_ty [x, y])
607 (ConPat nilDataCon list_ty [])
608 (map simplify_pat ps)
609 where list_ty = mkListTy ty
612 simplify_pat (TuplePat ps) = ConPat (tupleCon arity)
613 (mkTupleTy arity (map outPatType ps))
614 (map simplify_pat ps)
618 simplify_pat (RecPat id ty []) = ConPat id ty [wild_pat]
620 wild_pat = WildPat gt
621 gt = panic "Check.symplify_pat: gessing gt"
622 simplify_pat (RecPat id ty idps) = ConPat id ty pats
624 pats = map (\ (id,p,_)-> simplify_pat p) idps
626 simplify_pat pat@(LitPat lit lit_ty)
627 | isUnboxedType lit_ty = pat
629 | lit_ty == charTy = ConPat charDataCon charTy [LitPat (mk_char lit) charPrimTy]
631 | otherwise = pprPanic "Check.simplify_pat: LitPat:" (ppr pat)
633 mk_char (HsChar c) = HsCharPrim c
635 simplify_pat (NPat lit lit_ty hsexpr) = better_pat
638 | lit_ty == charTy = ConPat charDataCon lit_ty [LitPat (mk_char lit) charPrimTy]
639 | lit_ty == intTy = ConPat intDataCon lit_ty [LitPat (mk_int lit) intPrimTy]
640 | lit_ty == wordTy = ConPat wordDataCon lit_ty [LitPat (mk_word lit) wordPrimTy]
641 | lit_ty == addrTy = ConPat addrDataCon lit_ty [LitPat (mk_addr lit) addrPrimTy]
642 | lit_ty == floatTy = ConPat floatDataCon lit_ty [LitPat (mk_float lit) floatPrimTy]
643 | lit_ty == doubleTy = ConPat doubleDataCon lit_ty [LitPat (mk_double lit) doublePrimTy]
645 -- Convert the literal pattern "" to the constructor pattern [].
646 | null_str_lit lit = ConPat nilDataCon lit_ty []
648 | lit_ty == stringTy =
649 foldr (\ x -> \y -> ConPat consDataCon list_ty [x, y])
650 (ConPat nilDataCon list_ty [])
653 | otherwise = NPat lit lit_ty hsexpr
655 list_ty = mkListTy lit_ty
657 mk_int (HsInt i) = HsIntPrim i
658 mk_int l@(HsLitLit s) = l
660 mk_head_char (HsString s) = HsCharPrim (_HEAD_ s)
661 mk_string (HsString s) =
662 map (\ c -> ConPat charDataCon charTy
663 [LitPat (HsCharPrim c) charPrimTy])
666 mk_char (HsChar c) = HsCharPrim c
667 mk_char l@(HsLitLit s) = l
669 mk_word l@(HsLitLit s) = l
671 mk_addr l@(HsLitLit s) = l
673 mk_float (HsInt i) = HsFloatPrim (fromInteger i)
674 mk_float (HsFrac f) = HsFloatPrim f
675 mk_float l@(HsLitLit s) = l
677 mk_double (HsInt i) = HsDoublePrim (fromInteger i)
678 mk_double (HsFrac f) = HsDoublePrim f
679 mk_double l@(HsLitLit s) = l
681 null_str_lit (HsString s) = _NULL_ s
682 null_str_lit other_lit = False
684 one_str_lit (HsString s) = _LENGTH_ s == (1::Int)
685 one_str_lit other_lit = False
687 simplify_pat (NPlusKPat id hslit ty hsexpr1 hsexpr2) =
689 where ty = panic "Check.simplify_pat: Gessing ty"
691 simplify_pat (DictPat dicts methods) =
692 case num_of_d_and_ms of
693 0 -> simplify_pat (TuplePat [])
694 1 -> simplify_pat (head dict_and_method_pats)
695 _ -> simplify_pat (TuplePat dict_and_method_pats)
697 num_of_d_and_ms = length dicts + length methods
698 dict_and_method_pats = map VarPat (dicts ++ methods)