From 4cdf8b5ef923e4b860b2d7e61d034817cb81ddbc Mon Sep 17 00:00:00 2001 From: Cale Gibbard <cgibbard@gmail.com> Date: Mon, 22 Feb 2021 15:56:22 -0500 Subject: [PATCH] Bring back COMPLETE sets filtered by result TyCon (#14422) Commit 2a94228 dramatically simplified the implementation and improved the performance of COMPLETE sets while making them applicable in more scenarios at the same time. But it turned out that there was a change in semantics that (to me unexpectedly) broke users' expectations (see #14422): They relied on the "type signature" of a COMPLETE pragma to restrict the scrutinee types of a pattern match for which they are applicable. This patch brings back that filtering, so the semantics is the same as it was in GHC 9.0. See the updated Note [Implementation of COMPLETE pragmas]. There are a few testsuite output changes (`completesig13`, `T14422`) which assert this change. Co-authored-by: Sebastian Graf <sebastian.graf@kit.edu> --- compiler/GHC/Hs/Binds.hs | 2 +- compiler/GHC/HsToCore/Pmc/Solver.hs | 77 ++++++++++++++----- compiler/GHC/HsToCore/Pmc/Solver/Types.hs | 10 +-- compiler/GHC/Iface/Make.hs | 5 +- compiler/GHC/Iface/Syntax.hs | 16 ++-- compiler/GHC/IfaceToCore.hs | 7 +- compiler/GHC/IfaceToCore.hs-boot | 2 +- compiler/GHC/Tc/Gen/Bind.hs | 15 ++-- compiler/GHC/ThToHs.hs | 2 +- compiler/GHC/Types/CompleteMatch.hs | 35 +++++++-- docs/users_guide/exts/pragmas.rst | 53 +++++++++++++ .../tests/pmcheck/complete_sigs/T14422.hs | 32 +++++++- .../tests/pmcheck/complete_sigs/T14422.stderr | 8 ++ .../pmcheck/complete_sigs/T18960b.stderr | 12 +-- .../pmcheck/complete_sigs/completesig13.hs | 2 +- 15 files changed, 220 insertions(+), 58 deletions(-) create mode 100644 testsuite/tests/pmcheck/complete_sigs/T14422.stderr diff --git a/compiler/GHC/Hs/Binds.hs b/compiler/GHC/Hs/Binds.hs index 5316046880a0..91b5dd7724e9 100644 --- a/compiler/GHC/Hs/Binds.hs +++ b/compiler/GHC/Hs/Binds.hs @@ -604,7 +604,7 @@ ppr_sig (CompleteMatchSig _ src cs mty) ((hsep (punctuate comma (map ppr (unLoc cs)))) <+> opt_sig) where - opt_sig = maybe empty ((\t -> dcolon <+> ppr t) . unLoc) mty + opt_sig = maybe empty (\t -> dcolon <+> ppr t) mty instance OutputableBndrId p => Outputable (FixitySig (GhcPass p)) where diff --git a/compiler/GHC/HsToCore/Pmc/Solver.hs b/compiler/GHC/HsToCore/Pmc/Solver.hs index 7635d0bb2527..b128cc93fdc4 100644 --- a/compiler/GHC/HsToCore/Pmc/Solver.hs +++ b/compiler/GHC/HsToCore/Pmc/Solver.hs @@ -48,6 +48,7 @@ import GHC.Utils.Error ( pprMsgEnvelopeBagWithLoc ) import GHC.Utils.Misc import GHC.Utils.Panic import GHC.Data.Bag +import GHC.Types.CompleteMatch import GHC.Types.Error import GHC.Types.Unique.Set import GHC.Types.Unique.DSet @@ -147,7 +148,7 @@ vanillaCompleteMatchTC tc = -- special case. mb_dcs | tc == tYPETyCon = Just [] | otherwise = tyConDataCons_maybe tc - in mkUniqDSet . map RealDataCon <$> mb_dcs + in vanillaCompleteMatch . mkUniqDSet . map RealDataCon <$> mb_dcs -- | Initialise from 'dsGetCompleteMatches' (containing all COMPLETE pragmas) -- if the given 'ResidualCompleteMatches' were empty. @@ -180,9 +181,9 @@ markMatched :: PmAltCon -> ResidualCompleteMatches -> DsM (Maybe ResidualComplet markMatched (PmAltLit _) _ = pure Nothing -- lits are never part of a COMPLETE set markMatched (PmAltConLike cl) rcm = do rcm' <- addConLikeMatches cl rcm - let go cm = case lookupUniqDSet cm cl of + let go cm = case lookupUniqDSet (cmConLikes cm) cl of Nothing -> (False, cm) - Just _ -> (True, delOneFromUniqDSet cm cl) + Just _ -> (True, cm { cmConLikes = delOneFromUniqDSet (cmConLikes cm) cl }) pure $ updRcm go rcm' {- @@ -203,10 +204,34 @@ function, it gives rise to a total function. An example is: booleanToInt F = 0 booleanToInt T = 1 -COMPLETE sets are represented internally in GHC a set of 'ConLike's. For +COMPLETE sets are represented internally in GHC as a set of 'ConLike's. For example, the pragma {-# COMPLETE F, T #-} would be represented as: - {F, T} + CompleteMatch {F, T} Nothing + +What is the Maybe for? Answer: COMPLETE pragmas may optionally specify a +result *type constructor* (cf. T14422): + + class C f where + foo :: f a -> () + pattern P :: C f => f a + pattern P <- (foo -> ()) + + instance C State where + foo _ = () + {-# COMPLETE P :: State #-} + + f :: State a -> () + f P = () + g :: C f => f a -> () + g P = () + +The @:: State@ here means that the types at which the COMPLETE pragma *applies* +is restricted to scrutinee types that are applications of the 'State' TyCon. So +it applies to the match in @f@ but not in @g@ above, resulting in a warning for +the latter but not for the former. The pragma is represented as + + CompleteMatch {P} (Just State) GHC collects all COMPLETE pragmas from the current module and from imports into a field in the DsM environment, which can be accessed with @@ -228,18 +253,20 @@ we know a particular variable can't be (through negative constructor constraints testing). If *any* of the COMPLETE sets become empty, we know that the match was exhaustive. -We assume that a COMPLETE set is non-empty if for one of its ConLikes -we fail to 'guessConLikeUnivTyArgsFromResTy'. That accounts for ill-typed -COMPLETE sets. So why don't we simply prune those ill-typed COMPLETE sets from -'ResidualCompleteMatches'? The answer is that additional type constraints might -make more COMPLETE sets applicable! Example: +We assume that a COMPLETE set does not apply if for one of its +ConLikes we fail to 'guessConLikeUnivTyArgsFromResTy' or the +type of the match variable isn't an application of the optional +result type constructor from the pragma. Why don't we simply +prune inapplicable COMPLETE sets from 'ResidualCompleteMatches'? +The answer is that additional type constraints might make more +COMPLETE sets applicable! Example: - f :: a -> a :~: Boolean -> () - f x Refl | T <- x = () + h :: a -> a :~: Boolean -> () + h x Refl | T <- x = () | F <- x = () If we eagerly prune {F,T} from the residual matches of @x@, then we don't see -that the match in the guards of @f@ is exhaustive, where the COMPLETE set +that the match in the guards of @h@ is exhaustive, where the COMPLETE set applies due to refined type information. -} @@ -1338,7 +1365,7 @@ anyConLikeSolution p = any (go . paca_con) go (PmAltConLike cl) = p cl go _ = False --- | @instCompleteSet fuel nabla nabla cls@ iterates over @cls@ until it finds +-- | @instCompleteSet fuel nabla x cls@ iterates over @cls@ until it finds -- the first inhabited ConLike (as per 'instCon'). Any failed instantiation -- attempts of a ConLike are recorded as negative information in the returned -- 'Nabla', so that later calls to this function can skip repeatedly fruitless @@ -1350,23 +1377,26 @@ anyConLikeSolution p = any (go . paca_con) -- entirely as an optimisation. instCompleteSet :: Int -> Nabla -> Id -> CompleteMatch -> MaybeT DsM Nabla instCompleteSet fuel nabla x cs - | anyConLikeSolution (`elementOfUniqDSet` cs) (vi_pos vi) + | anyConLikeSolution (`elementOfUniqDSet` (cmConLikes cs)) (vi_pos vi) -- No need to instantiate a constructor of this COMPLETE set if we already -- have a solution! = pure nabla + | not (completeMatchAppliesAtType (varType x) cs) + = pure nabla | otherwise = go nabla (sorted_candidates cs) where vi = lookupVarInfo (nabla_tm_st nabla) x sorted_candidates :: CompleteMatch -> [ConLike] - sorted_candidates cs + sorted_candidates cm -- If there aren't many candidates, we can try to sort them by number of -- strict fields, type constraints, etc., so that we are fast in the -- common case -- (either many simple constructors *or* few "complicated" ones). | sizeUniqDSet cs <= 5 = sortBy compareConLikeTestability (uniqDSetToList cs) | otherwise = uniqDSetToList cs + where cs = cmConLikes cm go :: Nabla -> [ConLike] -> MaybeT DsM Nabla go _ [] = mzero @@ -1780,7 +1810,7 @@ generateInhabitingPatterns (x:xs) n nabla = do -- Test all COMPLETE sets for inhabitants (n inhs at max). Take care of ⊥. clss <- pickApplicableCompleteSets rep_ty rcm - case NE.nonEmpty (uniqDSetToList <$> clss) of + case NE.nonEmpty (uniqDSetToList . cmConLikes <$> clss) of Nothing -> -- No COMPLETE sets ==> inhabited generateInhabitingPatterns xs n newty_nabla @@ -1831,9 +1861,20 @@ generateInhabitingPatterns (x:xs) n nabla = do pure (con_nablas ++ other_cons_nablas) pickApplicableCompleteSets :: Type -> ResidualCompleteMatches -> DsM [CompleteMatch] +-- See Note [Implementation of COMPLETE pragmas] on what "applicable" means pickApplicableCompleteSets ty rcm = do env <- dsGetFamInstEnvs - pure $ filter (all (is_valid env) . uniqDSetToList) (getRcm rcm) + let applicable :: CompleteMatch -> Bool + applicable cm = all (is_valid env) (uniqDSetToList (cmConLikes cm)) + && completeMatchAppliesAtType ty cm + applicableMatches = filter applicable (getRcm rcm) + tracePm "pickApplicableCompleteSets:" $ + vcat + [ ppr ty + , ppr rcm + , ppr applicableMatches + ] + return applicableMatches where is_valid :: FamInstEnvs -> ConLike -> Bool is_valid env cl = isJust (guessConLikeUnivTyArgsFromResTy env ty cl) diff --git a/compiler/GHC/HsToCore/Pmc/Solver/Types.hs b/compiler/GHC/HsToCore/Pmc/Solver/Types.hs index 1e4e67258395..7516a56995ee 100644 --- a/compiler/GHC/HsToCore/Pmc/Solver/Types.hs +++ b/compiler/GHC/HsToCore/Pmc/Solver/Types.hs @@ -61,10 +61,10 @@ import GHC.Builtin.Types import GHC.Builtin.Types.Prim import GHC.Tc.Solver.Monad (InertSet, emptyInert) import GHC.Tc.Utils.TcType (isStringTy) -import GHC.Types.CompleteMatch (CompleteMatch) -import GHC.Types.SourceText (mkFractionalLit, FractionalLit, fractionalLitFromRational, - FractionalExponentBase(..), SourceText(..)) - +import GHC.Types.CompleteMatch (CompleteMatch(..)) +import GHC.Types.SourceText (SourceText(..), mkFractionalLit, FractionalLit + , fractionalLitFromRational + , FractionalExponentBase(..)) import Numeric (fromRat) import Data.Foldable (find) import Data.Ratio @@ -368,7 +368,7 @@ eqConLike _ _ = PossiblyOverlap data PmAltCon = PmAltConLike ConLike | PmAltLit PmLit -data PmAltConSet = PACS !CompleteMatch ![PmLit] +data PmAltConSet = PACS !(UniqDSet ConLike) ![PmLit] emptyPmAltConSet :: PmAltConSet emptyPmAltConSet = PACS emptyUniqDSet [] diff --git a/compiler/GHC/Iface/Make.hs b/compiler/GHC/Iface/Make.hs index 1c43e3e6e697..53f0032f284f 100644 --- a/compiler/GHC/Iface/Make.hs +++ b/compiler/GHC/Iface/Make.hs @@ -73,6 +73,7 @@ import GHC.Types.TypeEnv import GHC.Types.SourceFile import GHC.Types.TyThing import GHC.Types.HpcInfo +import GHC.Types.CompleteMatch import GHC.Utils.Outputable import GHC.Utils.Panic @@ -347,8 +348,8 @@ mkIface_ hsc_env -} mkIfaceCompleteMatch :: CompleteMatch -> IfaceCompleteMatch -mkIfaceCompleteMatch cls = - IfaceCompleteMatch (map conLikeName (uniqDSetToList cls)) +mkIfaceCompleteMatch (CompleteMatch cls mtc) = + IfaceCompleteMatch (map conLikeName (uniqDSetToList cls)) (toIfaceTyCon <$> mtc) {- diff --git a/compiler/GHC/Iface/Syntax.hs b/compiler/GHC/Iface/Syntax.hs index 73e852558933..21b4274cc7a9 100644 --- a/compiler/GHC/Iface/Syntax.hs +++ b/compiler/GHC/Iface/Syntax.hs @@ -325,14 +325,12 @@ data IfaceAnnotation type IfaceAnnTarget = AnnTarget OccName -newtype IfaceCompleteMatch = IfaceCompleteMatch [IfExtName] +data IfaceCompleteMatch = IfaceCompleteMatch [IfExtName] (Maybe IfaceTyCon) instance Outputable IfaceCompleteMatch where - ppr (IfaceCompleteMatch cls) = text "COMPLETE" <> colon <+> ppr cls - - - - + ppr (IfaceCompleteMatch cls mtc) = text "COMPLETE" <> colon <+> ppr cls <+> case mtc of + Nothing -> empty + Just tc -> dcolon <+> ppr tc -- Here's a tricky case: -- * Compile with -O module A, and B which imports A.f @@ -2493,8 +2491,8 @@ instance Binary IfaceTyConParent where return $ IfDataInstance ax pr ty instance Binary IfaceCompleteMatch where - put_ bh (IfaceCompleteMatch cs) = put_ bh cs - get bh = IfaceCompleteMatch <$> get bh + put_ bh (IfaceCompleteMatch cs mtc) = put_ bh cs >> put_ bh mtc + get bh = IfaceCompleteMatch <$> get bh <*> get bh {- @@ -2653,7 +2651,7 @@ instance NFData IfaceConAlt where IfaceLitAlt lit -> lit `seq` () instance NFData IfaceCompleteMatch where - rnf (IfaceCompleteMatch f1) = rnf f1 + rnf (IfaceCompleteMatch f1 mtc) = rnf f1 `seq` rnf mtc instance NFData IfaceRule where rnf (IfaceRule f1 f2 f3 f4 f5 f6 f7 f8) = diff --git a/compiler/GHC/IfaceToCore.hs b/compiler/GHC/IfaceToCore.hs index 5a843c5e7e01..76079ae8ff88 100644 --- a/compiler/GHC/IfaceToCore.hs +++ b/compiler/GHC/IfaceToCore.hs @@ -85,6 +85,7 @@ import GHC.Types.Annotations import GHC.Types.SourceFile import GHC.Types.SourceText import GHC.Types.Basic hiding ( SuccessFlag(..) ) +import GHC.Types.CompleteMatch import GHC.Types.SrcLoc import GHC.Types.TypeEnv import GHC.Types.Unique.FM @@ -1280,8 +1281,10 @@ tcIfaceCompleteMatches :: [IfaceCompleteMatch] -> IfL [CompleteMatch] tcIfaceCompleteMatches = mapM tcIfaceCompleteMatch tcIfaceCompleteMatch :: IfaceCompleteMatch -> IfL CompleteMatch -tcIfaceCompleteMatch (IfaceCompleteMatch ms) = - mkUniqDSet <$> mapM (forkM doc . tcIfaceConLike) ms +tcIfaceCompleteMatch (IfaceCompleteMatch ms mtc) = do + conlikes <- mkUniqDSet <$> mapM (forkM doc . tcIfaceConLike) ms + mtc' <- traverse tcIfaceTyCon mtc + return (CompleteMatch conlikes mtc') where doc = text "COMPLETE sig" <+> ppr ms diff --git a/compiler/GHC/IfaceToCore.hs-boot b/compiler/GHC/IfaceToCore.hs-boot index c21c4a3acbbd..97124237c795 100644 --- a/compiler/GHC/IfaceToCore.hs-boot +++ b/compiler/GHC/IfaceToCore.hs-boot @@ -8,7 +8,7 @@ import GHC.Tc.Types ( IfL ) import GHC.Core.InstEnv ( ClsInst ) import GHC.Core.FamInstEnv ( FamInst ) import GHC.Core ( CoreRule ) -import GHC.Types.CompleteMatch ( CompleteMatch ) +import GHC.Types.CompleteMatch import GHC.Types.Annotations ( Annotation ) import GHC.Types.Name import GHC.Fingerprint.Type diff --git a/compiler/GHC/Tc/Gen/Bind.hs b/compiler/GHC/Tc/Gen/Bind.hs index caaa8b489435..0ab561a0a7ea 100644 --- a/compiler/GHC/Tc/Gen/Bind.hs +++ b/compiler/GHC/Tc/Gen/Bind.hs @@ -2,6 +2,7 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {- @@ -65,6 +66,7 @@ import GHC.Data.Graph.Directed import GHC.Data.Maybe import GHC.Utils.Misc import GHC.Types.Basic +import GHC.Types.CompleteMatch import GHC.Utils.Outputable as Outputable import GHC.Utils.Panic import GHC.Builtin.Names( ipClassName ) @@ -203,11 +205,14 @@ tcCompleteSigs sigs = let doOne :: LSig GhcRn -> TcM (Maybe CompleteMatch) -- We don't need to "type-check" COMPLETE signatures anymore; if their - -- combinations are invalid it will be found so at match sites. Hence we - -- keep '_mtc' only for backwards compatibility. - doOne (L loc c@(CompleteMatchSig _ext _src_txt (L _ ns) _mtc)) - = fmap Just $ setSrcSpan loc $ addErrCtxt (text "In" <+> ppr c) $ - mkUniqDSet <$> mapM (addLocM tcLookupConLike) ns + -- combinations are invalid it will be found so at match sites. + -- There it is also where we consider if the type of the pattern match is + -- compatible with the result type constructor 'mb_tc'. + doOne (L loc c@(CompleteMatchSig _ext _src_txt (L _ ns) mb_tc_nm)) + = fmap Just $ setSrcSpan loc $ addErrCtxt (text "In" <+> ppr c) $ do + cls <- mkUniqDSet <$> mapM (addLocM tcLookupConLike) ns + mb_tc <- traverse @Maybe tcLookupLocatedTyCon mb_tc_nm + pure CompleteMatch { cmConLikes = cls, cmResultTyCon = mb_tc } doOne _ = return Nothing -- For some reason I haven't investigated further, the signatures come in diff --git a/compiler/GHC/ThToHs.hs b/compiler/GHC/ThToHs.hs index dc10c6fed534..12f65d36cab3 100644 --- a/compiler/GHC/ThToHs.hs +++ b/compiler/GHC/ThToHs.hs @@ -827,7 +827,7 @@ cvtPragmaD (LineP line file) } cvtPragmaD (CompleteP cls mty) = do { cls' <- noLoc <$> mapM cNameL cls - ; mty' <- traverse tconNameL mty + ; mty' <- traverse tconNameL mty ; returnJustL $ Hs.SigD noExtField $ CompleteMatchSig noExtField NoSourceText cls' mty' } diff --git a/compiler/GHC/Types/CompleteMatch.hs b/compiler/GHC/Types/CompleteMatch.hs index 7ad521f73875..43216eba12c9 100644 --- a/compiler/GHC/Types/CompleteMatch.hs +++ b/compiler/GHC/Types/CompleteMatch.hs @@ -1,17 +1,40 @@ +{-# LANGUAGE TypeApplications #-} + -- | COMPLETE signature -module GHC.Types.CompleteMatch - ( CompleteMatch - , CompleteMatches - ) -where +module GHC.Types.CompleteMatch where +import GHC.Prelude +import GHC.Core.TyCo.Rep import GHC.Types.Unique.DSet import GHC.Core.ConLike +import GHC.Core.TyCon +import GHC.Core.Type ( splitTyConApp_maybe ) +import GHC.Utils.Outputable -- | A list of conlikes which represents a complete pattern match. -- These arise from @COMPLETE@ signatures. -- See also Note [Implementation of COMPLETE pragmas]. -type CompleteMatch = UniqDSet ConLike +data CompleteMatch = CompleteMatch + { cmConLikes :: UniqDSet ConLike -- ^ The set of `ConLike` values + , cmResultTyCon :: Maybe TyCon -- ^ The optional, concrete result TyCon the set applies to + } + +vanillaCompleteMatch :: UniqDSet ConLike -> CompleteMatch +vanillaCompleteMatch cls = CompleteMatch { cmConLikes = cls, cmResultTyCon = Nothing } + +instance Outputable CompleteMatch where + ppr (CompleteMatch cls mty) = case mty of + Nothing -> ppr cls + Just ty -> ppr cls <> text "@" <> parens (ppr ty) type CompleteMatches = [CompleteMatch] +completeMatchAppliesAtType :: Type -> CompleteMatch -> Bool +completeMatchAppliesAtType ty cm = all @Maybe ty_matches (cmResultTyCon cm) + where + ty_matches sig_tc + | Just (tc, _arg_tys) <- splitTyConApp_maybe ty + , tc == sig_tc + = True + | otherwise + = False diff --git a/docs/users_guide/exts/pragmas.rst b/docs/users_guide/exts/pragmas.rst index 1f6399fb7b4a..fd0127f54ab2 100644 --- a/docs/users_guide/exts/pragmas.rst +++ b/docs/users_guide/exts/pragmas.rst @@ -887,6 +887,59 @@ modules. ``COMPLETE`` pragmas should be thought of as asserting a universal truth about a set of patterns and as a result, should not be used to silence context specific incomplete match warnings. +It is also possible to restrict the types to which a ``COMPLETE`` pragma applies +by putting a double colon ``::`` after the list of constructors, followed by a +result type constructor, which will be used to restrict the cases in which the +pragma applies. GHC will compare the annotated result type constructor with the +type constructor in the head of the scrutinee type in a pattern match to see if +the ``COMPLETE`` pragma is meant to apply to it. + +This is especially useful in cases that the constructors specified are +polymorphic, e.g.:: + + data Proxy a = Proxy + + class IsEmpty a where + isEmpty :: a -> Bool + + class IsCons a where + type Elt a + isCons :: a -> Maybe (Elt a, a) + + pattern Empty :: IsEmpty a => a + pattern Empty <- (isEmpty -> True) + + pattern Cons :: IsCons a => Elt a -> a -> a + pattern Cons x xs <- (isCons -> Just (x,xs)) + + instance IsEmpty (Proxy a) where + isEmpty Proxy = True + + instance IsEmpty [a] where + isEmpty = null + + instance IsCons [a] where + type Elt [a] = a + isCons [] = Nothing + isCons (x:xs) = Just (x,xs) + + {-# COMPLETE Empty :: Proxy #-} + {-# COMPLETE Empty, Cons :: [] #-} + + foo :: Proxy a -> Int + foo Empty = 0 + + bar :: [a] -> Int + bar Empty = 0 + bar (Cons _ _) = 1 + + baz :: [a] -> Int + baz Empty = 0 + +In this example, ``foo`` and ``bar`` will not be warned about, as their +pattern matches are covered by the two ``COMPLETE`` pragmas above, but +``baz`` will be warned about as incomplete. + .. _overlap-pragma: ``OVERLAPPING``, ``OVERLAPPABLE``, ``OVERLAPS``, and ``INCOHERENT`` pragmas diff --git a/testsuite/tests/pmcheck/complete_sigs/T14422.hs b/testsuite/tests/pmcheck/complete_sigs/T14422.hs index be879f4b131c..8e371fd5e015 100644 --- a/testsuite/tests/pmcheck/complete_sigs/T14422.hs +++ b/testsuite/tests/pmcheck/complete_sigs/T14422.hs @@ -1,7 +1,7 @@ {-# OPTIONS_GHC -Wall #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE ViewPatterns #-} -module Completesig15 where +module T14422 where class C f where foo :: f a -> () @@ -13,3 +13,33 @@ pattern P <- (foo -> ()) f :: C f => f a -> () f P = () -- A complete match + +-- But we also have to be able to constrain applicability of a COMPLETE sig. +-- Hence another example: + +class D f where + bar :: f a -> () + +pattern Q :: D f => f a +pattern Q <- (bar -> ()) + +instance D [] where + bar _ = () +{-# COMPLETE Q :: [] #-} + +g :: D f => f a -> () +g Q = () -- Should warn! The sig shouldn't apply in a polymorphic context. + +h :: [a] -> () +h Q = () -- A complete match + +-- What currently isn't possible (although, yet): +class D f => E f where + -- Law: every match on 'Q' is COMPLETE + +-- Commented out, because it's invalid syntax ATM. +-- {-# COMPLETE Q :: E f => f a #-} + +i :: E f => f a -> () +i Q = () -- Would be a complete match with GHC proposal #400 + diff --git a/testsuite/tests/pmcheck/complete_sigs/T14422.stderr b/testsuite/tests/pmcheck/complete_sigs/T14422.stderr new file mode 100644 index 000000000000..26a03573ae28 --- /dev/null +++ b/testsuite/tests/pmcheck/complete_sigs/T14422.stderr @@ -0,0 +1,8 @@ + +T14422.hs:31:1: warning: [-Wincomplete-patterns (in -Wextra)] + Pattern match(es) are non-exhaustive + In an equation for ‘g’: Patterns of type ‘f a’ not matched: P + +T14422.hs:44:1: warning: [-Wincomplete-patterns (in -Wextra)] + Pattern match(es) are non-exhaustive + In an equation for ‘i’: Patterns of type ‘f a’ not matched: P diff --git a/testsuite/tests/pmcheck/complete_sigs/T18960b.stderr b/testsuite/tests/pmcheck/complete_sigs/T18960b.stderr index 6af7fa7bc13d..fd27f0853ed7 100644 --- a/testsuite/tests/pmcheck/complete_sigs/T18960b.stderr +++ b/testsuite/tests/pmcheck/complete_sigs/T18960b.stderr @@ -3,18 +3,18 @@ T18960b.hs:11:7: warning: [-Wincomplete-patterns (in -Wextra)] Pattern match(es) are non-exhaustive In a case alternative: Patterns of type ‘((), String)’ not matched: + (_, _) P ((), []) - P ((), (p : P _)) where p is not one of {'h'} - P ((), ['h']) - P ((), ('h' : p : P _)) where p is not one of {'e'} + P ((), [p]) where p is not one of {'h'} + P ((), (p:_:_)) where p is not one of {'h'} ... T18960b.hs:18:7: warning: [-Wincomplete-patterns (in -Wextra)] Pattern match(es) are non-exhaustive In a case alternative: Patterns of type ‘((), String)’ not matched: + (_, _) P ((), []) - P ((), (p : P _)) where p is not one of {'h'} - P ((), ['h']) - P ((), ('h' : p : P _)) where p is not one of {'e'} + P ((), [p]) where p is not one of {'h'} + P ((), (p:_:_)) where p is not one of {'h'} ... diff --git a/testsuite/tests/pmcheck/complete_sigs/completesig13.hs b/testsuite/tests/pmcheck/complete_sigs/completesig13.hs index ac87baf9f082..e545ef8d9bae 100644 --- a/testsuite/tests/pmcheck/complete_sigs/completesig13.hs +++ b/testsuite/tests/pmcheck/complete_sigs/completesig13.hs @@ -2,7 +2,7 @@ {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -Wall #-} -module Completesig11 where +module Completesig13 where class LL f where go :: f a -> () -- GitLab