{-# LANGUAGE CPP #-} {-# LANGUAGE TypeFamilies #-} {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} {- (c) The University of Glasgow 2006 (c) The GRASP/AQUA Project, Glasgow University, 1992-1998 Pattern-matching constructors -} module GHC.HsToCore.Match.Constructor ( matchConFamily, matchPatSyn ) where #include "HsVersions.h" import GHC.Prelude import {-# SOURCE #-} GHC.HsToCore.Match ( match ) import GHC.Hs import GHC.HsToCore.Binds import GHC.Core.ConLike import GHC.Types.Basic ( Origin(..) ) import GHC.Tc.Utils.TcType import GHC.Core.Multiplicity import GHC.HsToCore.Monad import GHC.HsToCore.Utils import GHC.Core ( CoreExpr ) import GHC.Core.Make ( mkCoreLets ) import GHC.Utils.Misc import GHC.Types.Id import GHC.Types.Name.Env import GHC.Types.FieldLabel ( flSelector ) import GHC.Types.SrcLoc import GHC.Utils.Outputable import GHC.Utils.Panic import Control.Monad(liftM) import Data.List (groupBy) import Data.List.NonEmpty (NonEmpty(..)) {- We are confronted with the first column of patterns in a set of equations, all beginning with constructors from one ``family'' (e.g., @[]@ and @:@ make up the @List@ ``family''). We want to generate the alternatives for a @Case@ expression. There are several choices: \begin{enumerate} \item Generate an alternative for every constructor in the family, whether they are used in this set of equations or not; this is what the Wadler chapter does. \begin{description} \item[Advantages:] (a)~Simple. (b)~It may also be that large sparsely-used constructor families are mainly handled by the code for literals. \item[Disadvantages:] (a)~Not practical for large sparsely-used constructor families, e.g., the ASCII character set. (b)~Have to look up a list of what constructors make up the whole family. \end{description} \item Generate an alternative for each constructor used, then add a default alternative in case some constructors in the family weren't used. \begin{description} \item[Advantages:] (a)~Alternatives aren't generated for unused constructors. (b)~The STG is quite happy with defaults. (c)~No lookup in an environment needed. \item[Disadvantages:] (a)~A spurious default alternative may be generated. \end{description} \item ``Do it right:'' generate an alternative for each constructor used, and add a default alternative if all constructors in the family weren't used. \begin{description} \item[Advantages:] (a)~You will get cases with only one alternative (and no default), which should be amenable to optimisation. Tuples are a common example. \item[Disadvantages:] (b)~Have to look up constructor families in TDE (as above). \end{description} \end{enumerate} We are implementing the ``do-it-right'' option for now. The arguments to @matchConFamily@ are the same as to @match@; the extra @Int@ returned is the number of constructors in the family. The function @matchConFamily@ is concerned with this have-we-used-all-the-constructors? question; the local function @match_cons_used@ does all the real work. -} matchConFamily :: NonEmpty Id -> Type -> NonEmpty (NonEmpty EquationInfo) -> DsM (MatchResult CoreExpr) -- Each group of eqns is for a single constructor matchConFamily (var :| vars) ty groups = do let mult = idMult var -- Each variable in the argument list correspond to one column in the -- pattern matching equations. Its multiplicity is the context -- multiplicity of the pattern. We extract that multiplicity, so that -- 'matchOneconLike' knows the context multiplicity, in case it needs -- to come up with new variables. alts <- mapM (fmap toRealAlt . matchOneConLike vars ty mult) groups return (mkCoAlgCaseMatchResult var ty alts) where toRealAlt alt = case alt_pat alt of RealDataCon dcon -> alt{ alt_pat = dcon } _ -> panic "matchConFamily: not RealDataCon" matchPatSyn :: NonEmpty Id -> Type -> NonEmpty EquationInfo -> DsM (MatchResult CoreExpr) matchPatSyn (var :| vars) ty eqns = do let mult = idMult var alt <- fmap toSynAlt $ matchOneConLike vars ty mult eqns return (mkCoSynCaseMatchResult var ty alt) where toSynAlt alt = case alt_pat alt of PatSynCon psyn -> alt{ alt_pat = psyn } _ -> panic "matchPatSyn: not PatSynCon" type ConArgPats = HsConPatDetails GhcTc matchOneConLike :: [Id] -> Type -> Mult -> NonEmpty EquationInfo -> DsM (CaseAlt ConLike) matchOneConLike vars ty mult (eqn1 :| eqns) -- All eqns for a single constructor = do { let inst_tys = ASSERT( all tcIsTcTyVar ex_tvs ) -- ex_tvs can only be tyvars as data types in source -- Haskell cannot mention covar yet (Aug 2018). ASSERT( tvs1 `equalLength` ex_tvs ) arg_tys ++ mkTyVarTys tvs1 val_arg_tys = conLikeInstOrigArgTys con1 inst_tys -- dataConInstOrigArgTys takes the univ and existential tyvars -- and returns the types of the *value* args, which is what we want match_group :: [Id] -> [(ConArgPats, EquationInfo)] -> DsM (MatchResult CoreExpr) -- All members of the group have compatible ConArgPats match_group arg_vars arg_eqn_prs = ASSERT( notNull arg_eqn_prs ) do { (wraps, eqns') <- liftM unzip (mapM shift arg_eqn_prs) ; let group_arg_vars = select_arg_vars arg_vars arg_eqn_prs ; match_result <- match (group_arg_vars ++ vars) ty eqns' ; return $ foldr1 (.) wraps <$> match_result } shift (_, eqn@(EqnInfo { eqn_pats = ConPat { pat_args = args , pat_con_ext = ConPatTc { cpt_tvs = tvs , cpt_dicts = ds , cpt_binds = bind } } : pats })) = do ds_bind <- dsTcEvBinds bind return ( wrapBinds (tvs `zip` tvs1) . wrapBinds (ds `zip` dicts1) . mkCoreLets ds_bind , eqn { eqn_orig = Generated , eqn_pats = conArgPats val_arg_tys args ++ pats } ) shift (_, (EqnInfo { eqn_pats = ps })) = pprPanic "matchOneCon/shift" (ppr ps) ; let scaled_arg_tys = map (scaleScaled mult) val_arg_tys -- The 'val_arg_tys' are taken from the data type definition, they -- do not take into account the context multiplicity, therefore we -- need to scale them back to get the correct context multiplicity -- to desugar the sub-pattern in each field. We need to know these -- multiplicity because of the invariant that, in Core, binders in a -- constructor pattern must be scaled by the multiplicity of the -- case. See Note [Case expression invariants]. ; arg_vars <- selectConMatchVars scaled_arg_tys args1 -- Use the first equation as a source of -- suggestions for the new variables -- Divide into sub-groups; see Note [Record patterns] ; let groups :: [[(ConArgPats, EquationInfo)]] groups = groupBy compatible_pats [ (pat_args (firstPat eqn), eqn) | eqn <- eqn1:eqns ] ; match_results <- mapM (match_group arg_vars) groups ; return $ MkCaseAlt{ alt_pat = con1, alt_bndrs = tvs1 ++ dicts1 ++ arg_vars, alt_wrapper = wrapper1, alt_result = foldr1 combineMatchResults match_results } } where ConPat { pat_con = L _ con1 , pat_args = args1 , pat_con_ext = ConPatTc { cpt_arg_tys = arg_tys , cpt_wrap = wrapper1 , cpt_tvs = tvs1 , cpt_dicts = dicts1 } } = firstPat eqn1 fields1 = map flSelector (conLikeFieldLabels con1) ex_tvs = conLikeExTyCoVars con1 -- Choose the right arg_vars in the right order for this group -- Note [Record patterns] select_arg_vars :: [Id] -> [(ConArgPats, EquationInfo)] -> [Id] select_arg_vars arg_vars ((arg_pats, _) : _) | RecCon flds <- arg_pats , let rpats = rec_flds flds , not (null rpats) -- Treated specially; cf conArgPats = ASSERT2( fields1 `equalLength` arg_vars, ppr con1 $$ ppr fields1 $$ ppr arg_vars ) map lookup_fld rpats | otherwise = arg_vars where fld_var_env = mkNameEnv $ zipEqual "get_arg_vars" fields1 arg_vars lookup_fld (L _ rpat) = lookupNameEnv_NF fld_var_env (idName (unLoc (hsRecFieldId rpat))) select_arg_vars _ [] = panic "matchOneCon/select_arg_vars []" ----------------- compatible_pats :: (ConArgPats,a) -> (ConArgPats,a) -> Bool -- Two constructors have compatible argument patterns if the number -- and order of sub-matches is the same in both cases compatible_pats (RecCon flds1, _) (RecCon flds2, _) = same_fields flds1 flds2 compatible_pats (RecCon flds1, _) _ = null (rec_flds flds1) compatible_pats _ (RecCon flds2, _) = null (rec_flds flds2) compatible_pats _ _ = True -- Prefix or infix con same_fields :: HsRecFields GhcTc (LPat GhcTc) -> HsRecFields GhcTc (LPat GhcTc) -> Bool same_fields flds1 flds2 = all2 (\(L _ f1) (L _ f2) -> unLoc (hsRecFieldId f1) == unLoc (hsRecFieldId f2)) (rec_flds flds1) (rec_flds flds2) ----------------- selectConMatchVars :: [Scaled Type] -> ConArgPats -> DsM [Id] selectConMatchVars arg_tys con = case con of (RecCon {}) -> newSysLocalsDsNoLP arg_tys (PrefixCon _ ps) -> selectMatchVars (zipMults arg_tys ps) (InfixCon p1 p2) -> selectMatchVars (zipMults arg_tys [p1, p2]) where zipMults = zipWithEqual "selectConMatchVar" (\a b -> (scaledMult a, unLoc b)) conArgPats :: [Scaled Type]-- Instantiated argument types -- Used only to fill in the types of WildPats, which -- are probably never looked at anyway -> ConArgPats -> [Pat GhcTc] conArgPats _arg_tys (PrefixCon _ ps) = map unLoc ps conArgPats _arg_tys (InfixCon p1 p2) = [unLoc p1, unLoc p2] conArgPats arg_tys (RecCon (HsRecFields { rec_flds = rpats })) | null rpats = map WildPat (map scaledThing arg_tys) -- Important special case for C {}, which can be used for a -- datacon that isn't declared to have fields at all | otherwise = map (unLoc . hsRecFieldArg . unLoc) rpats {- Note [Record patterns] ~~~~~~~~~~~~~~~~~~~~~~ Consider data T = T { x,y,z :: Bool } f (T { y=True, x=False }) = ... We must match the patterns IN THE ORDER GIVEN, thus for the first one we match y=True before x=False. See #246; or imagine matching against (T { y=False, x=undefined }): should fail without touching the undefined. Now consider: f (T { y=True, x=False }) = ... f (T { x=True, y= False}) = ... In the first we must test y first; in the second we must test x first. So we must divide even the equations for a single constructor T into sub-groups, based on whether they match the same field in the same order. That's what the (groupBy compatible_pats) grouping. All non-record patterns are "compatible" in this sense, because the positional patterns (T a b) and (a `T` b) all match the arguments in order. Also T {} is special because it's equivalent to (T _ _). Hence the (null rpats) checks here and there. -}