From 5b49434484d86b2dfad682d5eb26ef7f3e2e2b56 Mon Sep 17 00:00:00 2001 From: "simonpj@microsoft.com" Date: Wed, 22 Jul 2009 05:09:33 +0000 Subject: [PATCH] Take account of GADTs when reporting patterm-match overlap When matching against a GADT, some of the constructors may be impossible. For example data T a where T1 :: T Int T2 :: T Bool T3 :: T a f :: T Int -> Int f T1 = 3 f T3 = 4 Here, does not have any missing cases, despite omittting T2, because T2 :: T Bool. This patch teaches the overlap checker about GADTs, which happily turned out to be rather easy even though the overlap checker needs a serious rewrite. --- compiler/deSugar/Check.lhs | 15 +++++++++------ compiler/typecheck/TcTyClsDecls.lhs | 9 ++++++++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/compiler/deSugar/Check.lhs b/compiler/deSugar/Check.lhs index c5b13eb..6244b37 100644 --- a/compiler/deSugar/Check.lhs +++ b/compiler/deSugar/Check.lhs @@ -26,6 +26,8 @@ import Name import TysWiredIn import PrelNames import TyCon +import Type +import Unify( dataConCannotMatch ) import SrcLoc import UniqSet import Util @@ -446,12 +448,13 @@ mb_neg (Just _) v = -v get_unused_cons :: [Pat Id] -> [DataCon] get_unused_cons used_cons = ASSERT( not (null used_cons) ) unused_cons where - (ConPatOut { pat_con = l_con }) = head used_cons - ty_con = dataConTyCon (unLoc l_con) -- Newtype observable - all_cons = tyConDataCons ty_con - used_cons_as_id = map (\ (ConPatOut{ pat_con = L _ d}) -> d) used_cons - unused_cons = uniqSetToList - (mkUniqSet all_cons `minusUniqSet` mkUniqSet used_cons_as_id) + used_set :: UniqSet DataCon + used_set = mkUniqSet [d | ConPatOut{ pat_con = L _ d} <- used_cons] + (ConPatOut { pat_ty = ty }) = head used_cons + Just (ty_con, inst_tys) = splitTyConApp_maybe ty + unused_cons = filterOut is_used (tyConDataCons ty_con) + is_used con = con `elementOfUniqSet` used_set + || dataConCannotMatch inst_tys con all_vars :: [Pat Id] -> Bool all_vars [] = True diff --git a/compiler/typecheck/TcTyClsDecls.lhs b/compiler/typecheck/TcTyClsDecls.lhs index 0e59f01..049276d 100644 --- a/compiler/typecheck/TcTyClsDecls.lhs +++ b/compiler/typecheck/TcTyClsDecls.lhs @@ -1257,11 +1257,18 @@ mkRecSelBind (tycon, sel_name) -- Add catch-all default case unless the case is exhaustive -- We do this explicitly so that we get a nice error message that -- mentions this particular record selector - deflt | length cons_w_field == length all_cons = [] + deflt | not (any is_unused all_cons) = [] | otherwise = [mkSimpleMatch [nlWildPat] (nlHsApp (nlHsVar (getName rEC_SEL_ERROR_ID)) (nlHsLit msg_lit))] + -- Do not add a default case unless there are unmatched + -- constructors. We must take account of GADTs, else we + -- get overlap warning messages from the pattern-match checker + is_unused con = not (con `elem` cons_w_field + || dataConCannotMatch inst_tys con) + inst_tys = tyConAppArgs data_ty + unit_rhs = L loc $ ExplicitTuple [] Boxed msg_lit = HsStringPrim $ mkFastString $ occNameString (getOccName sel_name) -- 1.7.10.4