-- Copyright (c) Facebook, Inc. and its affiliates. -- -- This source code is licensed under the MIT license found in the -- LICENSE file in the root directory of this source tree. -- {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE InstanceSigs #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ViewPatterns #-} module Retrie.PatternMap.Instances where import Control.Monad import Data.ByteString (ByteString) import Data.Maybe import Retrie.AlphaEnv import Retrie.ExactPrint import Retrie.GHC import Retrie.PatternMap.Bag import Retrie.PatternMap.Class import Retrie.Quantifiers import Retrie.Substitution import Retrie.Util ------------------------------------------------------------------------ data TupArgMap a = TupArgMap { tamPresent :: EMap a, tamMissing :: MaybeMap a } deriving (Functor) instance PatternMap TupArgMap where -- type Key TupArgMap = Located (HsTupArg GhcPs) type Key TupArgMap = HsTupArg GhcPs mEmpty :: TupArgMap a mEmpty = TupArgMap mEmpty mEmpty mUnion :: TupArgMap a -> TupArgMap a -> TupArgMap a mUnion m1 m2 = TupArgMap { tamPresent = unionOn tamPresent m1 m2 , tamMissing = unionOn tamMissing m1 m2 } mAlter :: AlphaEnv -> Quantifiers -> Key TupArgMap -> A a -> TupArgMap a -> TupArgMap a mAlter env vs tupArg f m = go tupArg where go (Present _ e) = m { tamPresent = mAlter env vs e f (tamPresent m) } #if __GLASGOW_HASKELL__ < 900 go XTupArg{} = missingSyntax "XTupArg" #endif go (Missing _) = m { tamMissing = mAlter env vs () f (tamMissing m) } mMatch :: MatchEnv -> Key TupArgMap -> (Substitution, TupArgMap a) -> [(Substitution, a)] mMatch env = go where go (Present _ e) = mapFor tamPresent >=> mMatch env e #if __GLASGOW_HASKELL__ < 900 go XTupArg{} = const [] #endif go (Missing _) = mapFor tamMissing >=> mMatch env () ------------------------------------------------------------------------ data BoxityMap a = BoxityMap { boxBoxed :: MaybeMap a, boxUnboxed :: MaybeMap a } deriving (Functor) instance PatternMap BoxityMap where type Key BoxityMap = Boxity mEmpty :: BoxityMap a mEmpty = BoxityMap mEmpty mEmpty mUnion :: BoxityMap a -> BoxityMap a -> BoxityMap a mUnion m1 m2 = BoxityMap { boxBoxed = unionOn boxBoxed m1 m2 , boxUnboxed = unionOn boxUnboxed m1 m2 } mAlter :: AlphaEnv -> Quantifiers -> Key BoxityMap -> A a -> BoxityMap a -> BoxityMap a mAlter env vs Boxed f m = m { boxBoxed = mAlter env vs () f (boxBoxed m) } mAlter env vs Unboxed f m = m { boxUnboxed = mAlter env vs () f (boxUnboxed m) } mMatch :: MatchEnv -> Key BoxityMap -> (Substitution, BoxityMap a) -> [(Substitution, a)] mMatch env Boxed = mapFor boxBoxed >=> mMatch env () mMatch env Unboxed = mapFor boxUnboxed >=> mMatch env () ------------------------------------------------------------------------ data VMap a = VM { bvmap :: IntMap a, fvmap :: FSEnv a } | VMEmpty deriving (Functor) instance PatternMap VMap where type Key VMap = RdrName mEmpty :: VMap a mEmpty = VMEmpty mUnion :: VMap a -> VMap a -> VMap a mUnion VMEmpty m = m mUnion m VMEmpty = m mUnion m1 m2 = VM { bvmap = unionOn bvmap m1 m2 , fvmap = unionOn fvmap m1 m2 } mAlter :: AlphaEnv -> Quantifiers -> Key VMap -> A a -> VMap a -> VMap a mAlter env vs v f VMEmpty = mAlter env vs v f (VM mEmpty mEmpty) mAlter env vs v f m@VM{} | Just bv <- lookupAlphaEnv v env = m { bvmap = mAlter env vs bv f (bvmap m) } | otherwise = m { fvmap = mAlter env vs (rdrFS v) f (fvmap m) } mMatch :: MatchEnv -> Key VMap -> (Substitution, VMap a) -> [(Substitution, a)] mMatch _ _ (_,VMEmpty) = [] mMatch env v (hs,m@VM{}) | Just bv <- lookupAlphaEnv v (meAlphaEnv env) = mMatch env bv (hs, bvmap m) | otherwise = mMatch env (rdrFS v) (hs, fvmap m) ------------------------------------------------------------------------ data LMap a = LMEmpty | LM { lmChar :: Map Char a , lmCharPrim :: Map Char a , lmString :: FSEnv a , lmStringPrim :: Map ByteString a , lmInt :: BoolMap (Map Integer a) , lmIntPrim :: Map Integer a , lmWordPrim :: Map Integer a , lmInt64Prim :: Map Integer a , lmWord64Prim :: Map Integer a } deriving (Functor) emptyLMapWrapper :: LMap a emptyLMapWrapper = LM mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty instance PatternMap LMap where type Key LMap = HsLit GhcPs mEmpty :: LMap a mEmpty = LMEmpty mUnion :: LMap a -> LMap a -> LMap a mUnion LMEmpty m = m mUnion m LMEmpty = m mUnion m1 m2 = LM { lmChar = unionOn lmChar m1 m2 , lmCharPrim = unionOn lmCharPrim m1 m2 , lmString = unionOn lmString m1 m2 , lmStringPrim = unionOn lmStringPrim m1 m2 , lmInt = unionOn lmInt m1 m2 , lmIntPrim = unionOn lmIntPrim m1 m2 , lmWordPrim = unionOn lmWordPrim m1 m2 , lmInt64Prim = unionOn lmInt64Prim m1 m2 , lmWord64Prim = unionOn lmWord64Prim m1 m2 } mAlter :: AlphaEnv -> Quantifiers -> Key LMap -> A a -> LMap a -> LMap a mAlter env vs lit f LMEmpty = mAlter env vs lit f emptyLMapWrapper mAlter env vs lit f m@LM{} = go lit where go (HsChar _ c) = m { lmChar = mAlter env vs c f (lmChar m) } go (HsCharPrim _ c) = m { lmCharPrim = mAlter env vs c f (lmCharPrim m) } go (HsString _ fs) = m { lmString = mAlter env vs fs f (lmString m) } go (HsStringPrim _ bs) = m { lmStringPrim = mAlter env vs bs f (lmStringPrim m) } go (HsInt _ (IL _ b i)) = m { lmInt = mAlter env vs b (toA (mAlter env vs i f)) (lmInt m) } go (HsIntPrim _ i) = m { lmIntPrim = mAlter env vs i f (lmIntPrim m) } go (HsWordPrim _ i) = m { lmWordPrim = mAlter env vs i f (lmWordPrim m) } go (HsInt64Prim _ i) = m { lmInt64Prim = mAlter env vs i f (lmInt64Prim m) } go (HsWord64Prim _ i) = m { lmWord64Prim = mAlter env vs i f (lmWord64Prim m) } go (HsInteger _ _ _) = missingSyntax "HsInteger" go HsRat{} = missingSyntax "HsRat" go HsFloatPrim{} = missingSyntax "HsFloatPrim" go HsDoublePrim{} = missingSyntax "HsDoublePrim" #if __GLASGOW_HASKELL__ < 900 go XLit{} = missingSyntax "XLit" #endif mMatch :: MatchEnv -> Key LMap -> (Substitution, LMap a) -> [(Substitution, a)] mMatch _ _ (_,LMEmpty) = [] mMatch env lit (hs,m@LM{}) = go lit (hs,m) where go (HsChar _ c) = mapFor lmChar >=> mMatch env c go (HsCharPrim _ c) = mapFor lmCharPrim >=> mMatch env c go (HsString _ fs) = mapFor lmString >=> mMatch env fs go (HsStringPrim _ bs) = mapFor lmStringPrim >=> mMatch env bs go (HsInt _ (IL _ b i)) = mapFor lmInt >=> mMatch env b >=> mMatch env i go (HsIntPrim _ i) = mapFor lmIntPrim >=> mMatch env i go (HsWordPrim _ i) = mapFor lmWordPrim >=> mMatch env i go (HsInt64Prim _ i) = mapFor lmInt64Prim >=> mMatch env i go (HsWord64Prim _ i) = mapFor lmWord64Prim >=> mMatch env i go _ = const [] -- TODO ------------------------------------------------------------------------ data OLMap a = OLMEmpty | OLM { olmIntegral :: BoolMap (Map Integer a) -- ++AZ++:TODO: Fractional has *much* more than Rational now , olmFractional :: Map Rational a , olmIsString :: FSEnv a } deriving (Functor) emptyOLMapWrapper :: OLMap a emptyOLMapWrapper = OLM mEmpty mEmpty mEmpty instance PatternMap OLMap where type Key OLMap = OverLitVal mEmpty :: OLMap a mEmpty = OLMEmpty mUnion :: OLMap a -> OLMap a -> OLMap a mUnion OLMEmpty m = m mUnion m OLMEmpty = m mUnion m1 m2 = OLM { olmIntegral = unionOn olmIntegral m1 m2 , olmFractional = unionOn olmFractional m1 m2 , olmIsString = unionOn olmIsString m1 m2 } mAlter :: AlphaEnv -> Quantifiers -> Key OLMap -> A a -> OLMap a -> OLMap a mAlter env vs lv f OLMEmpty = mAlter env vs lv f emptyOLMapWrapper mAlter env vs lv f m@OLM{} = go lv where go (HsIntegral (IL _ b i)) = m { olmIntegral = mAlter env vs b (toA (mAlter env vs i f)) (olmIntegral m) } go (HsFractional fl) = m { olmFractional = mAlter env vs (fl_signi fl) f (olmFractional m) } go (HsIsString _ fs) = m { olmIsString = mAlter env vs fs f (olmIsString m) } mMatch :: MatchEnv -> Key OLMap -> (Substitution, OLMap a) -> [(Substitution, a)] mMatch _ _ (_,OLMEmpty) = [] mMatch env lv (hs,m@OLM{}) = go lv (hs,m) where go (HsIntegral (IL _ b i)) = mapFor olmIntegral >=> mMatch env b >=> mMatch env i go (HsFractional fl) = mapFor olmFractional >=> mMatch env (fl_signi fl) go (HsIsString _ fs) = mapFor olmIsString >=> mMatch env fs ------------------------------------------------------------------------ -- Note [Holes] -- Holes are distinguished variables which can match any expression. (The -- universally quantified variables in an Equality.) Ideally, they would be -- stored as a TyMap, so the type of the expression can be checked against the -- type of the hole. Fixing this is a TODO. This wraps a map from RdrName to -- result. We use a regular map instead of a OccEnv so we can get the RdrName -- back, which allows us to assign it to the expression when building the -- result. -- Note [Lambdas] -- This currently stores both HsLam and HsLamCase -- Note [Stmt Lists] -- Statement lists bind to the right, so we need to extend the environment -- as we move down it. Thus we cannot simply store them as ListMap SMap a. data EMap a = EMEmpty | EM { emHole :: Map RdrName a -- See Note [Holes] , emVar :: VMap a , emIPVar :: FSEnv a , emOverLit :: OLMap a , emLit :: LMap a , emLam :: MGMap a -- See Note [Lambdas] , emApp :: EMap (EMap a) , emOpApp :: EMap (EMap (EMap a)) -- op, lhs, rhs , emNegApp :: EMap a , emPar :: EMap a , emExplicitTuple :: BoxityMap (ListMap TupArgMap a) , emCase :: EMap (MGMap a) , emSecL :: EMap (EMap a) -- operator, operand (flipped) , emSecR :: EMap (EMap a) -- operator, operand , emIf :: EMap (EMap (EMap a)) -- cond, true, false , emLet :: LBMap (EMap a) , emDo :: SCMap (SLMap a) -- See Note [Stmt Lists] , emExplicitList :: ListMap EMap a , emRecordCon :: VMap (ListMap RFMap a) , emRecordUpd :: EMap (ListMap RFMap a) , emExprWithTySig :: EMap (TyMap a) } deriving (Functor) emptyEMapWrapper :: EMap a emptyEMapWrapper = EM mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty instance PatternMap EMap where type Key EMap = LocatedA (HsExpr GhcPs) mEmpty :: EMap a mEmpty = EMEmpty mUnion :: EMap a -> EMap a -> EMap a mUnion EMEmpty m = m mUnion m EMEmpty = m mUnion m1 m2 = EM { emHole = unionOn emHole m1 m2 , emVar = unionOn emVar m1 m2 , emIPVar = unionOn emIPVar m1 m2 , emOverLit = unionOn emOverLit m1 m2 , emLit = unionOn emLit m1 m2 , emLam = unionOn emLam m1 m2 , emApp = unionOn emApp m1 m2 , emOpApp = unionOn emOpApp m1 m2 , emNegApp = unionOn emNegApp m1 m2 , emPar = unionOn emPar m1 m2 , emExplicitTuple = unionOn emExplicitTuple m1 m2 , emCase = unionOn emCase m1 m2 , emSecL = unionOn emSecL m1 m2 , emSecR = unionOn emSecR m1 m2 , emIf = unionOn emIf m1 m2 , emLet = unionOn emLet m1 m2 , emDo = unionOn emDo m1 m2 , emExplicitList = unionOn emExplicitList m1 m2 , emRecordCon = unionOn emRecordCon m1 m2 , emRecordUpd = unionOn emRecordUpd m1 m2 , emExprWithTySig = unionOn emExprWithTySig m1 m2 } mAlter :: AlphaEnv -> Quantifiers -> Key EMap -> A a -> EMap a -> EMap a mAlter env vs e f EMEmpty = mAlter env vs e f emptyEMapWrapper mAlter env vs e f m@EM{} = go (unLoc e) where go (HsVar _ v) | unLoc v `isQ` vs = m { emHole = mAlter env vs (unLoc v) f (emHole m) } | otherwise = m { emVar = mAlter env vs (unLoc v) f (emVar m) } go (ExplicitTuple _ as b) = m { emExplicitTuple = mAlter env vs b (toA (mAlter env vs as f)) (emExplicitTuple m) } go (HsApp _ l r) = m { emApp = mAlter env vs l (toA (mAlter env vs r f)) (emApp m) } go (HsCase _ s mg) = m { emCase = mAlter env vs s (toA (mAlter env vs mg f)) (emCase m) } go (HsDo _ sc ss) = m { emDo = mAlter env vs sc (toA (mAlter env vs (unLoc ss) f)) (emDo m) } #if __GLASGOW_HASKELL__ < 900 go (HsIf _ _ c tr fl) = #else go (HsIf _ c tr fl) = #endif m { emIf = mAlter env vs c (toA (mAlter env vs tr (toA (mAlter env vs fl f)))) (emIf m) } go (HsIPVar _ (HsIPName ip)) = m { emIPVar = mAlter env vs ip f (emIPVar m) } go (HsLit _ l) = m { emLit = mAlter env vs l f (emLit m) } go (HsLam _ mg) = m { emLam = mAlter env vs mg f (emLam m) } go (HsOverLit _ ol) = m { emOverLit = mAlter env vs (ol_val ol) f (emOverLit m) } go (NegApp _ e' _) = m { emNegApp = mAlter env vs e' f (emNegApp m) } go (HsPar _ e') = m { emPar = mAlter env vs e' f (emPar m) } go (OpApp _ l o r) = m { emOpApp = mAlter env vs o (toA (mAlter env vs l (toA (mAlter env vs r f)))) (emOpApp m) } go (RecordCon _ v fs) = m { emRecordCon = mAlter env vs (unLoc v) (toA (mAlter env vs (fieldsToRdrNames $ rec_flds fs) f)) (emRecordCon m) } go (RecordUpd _ e' fs) = m { emRecordUpd = mAlter env vs e' (toA (mAlter env vs (fieldsToRdrNamesUpd fs) f)) (emRecordUpd m) } go (SectionL _ lhs o) = m { emSecL = mAlter env vs o (toA (mAlter env vs lhs f)) (emSecL m) } go (SectionR _ o rhs) = m { emSecR = mAlter env vs o (toA (mAlter env vs rhs f)) (emSecR m) } go (HsLet _ lbs e') = let bs = collectLocalBinders CollNoDictBinders lbs env' = foldr extendAlphaEnvInternal env bs vs' = vs `exceptQ` bs in m { emLet = mAlter env vs lbs (toA (mAlter env' vs' e' f)) (emLet m) } go HsLamCase{} = missingSyntax "HsLamCase" go HsMultiIf{} = missingSyntax "HsMultiIf" go (ExplicitList _ es) = m { emExplicitList = mAlter env vs es f (emExplicitList m) } go ArithSeq{} = missingSyntax "ArithSeq" go (ExprWithTySig _ e' (HsWC _ (L _ (HsSig _ _ ty)))) = m { emExprWithTySig = mAlter env vs e' (toA (mAlter env vs ty f)) (emExprWithTySig m) } #if __GLASGOW_HASKELL__ < 900 go XExpr{} = missingSyntax "XExpr" go ExprWithTySig{} = missingSyntax "ExprWithTySig" go HsSCC{} = missingSyntax "HsSCC" go HsCoreAnn{} = missingSyntax "HsCoreAnn" go HsTickPragma{} = missingSyntax "HsTickPragma" go HsWrap{} = missingSyntax "HsWrap" #else go HsPragE{} = missingSyntax "HsPragE" #endif go HsBracket{} = missingSyntax "HsBracket" go HsRnBracketOut{} = missingSyntax "HsRnBracketOut" go HsTcBracketOut{} = missingSyntax "HsTcBracketOut" go HsSpliceE{} = missingSyntax "HsSpliceE" go HsProc{} = missingSyntax "HsProc" go HsStatic{} = missingSyntax "HsStatic" #if __GLASGOW_HASKELL__ < 810 go HsArrApp{} = missingSyntax "HsArrApp" go HsArrForm{} = missingSyntax "HsArrForm" go EWildPat{} = missingSyntax "EWildPat" go EAsPat{} = missingSyntax "EAsPat" go EViewPat{} = missingSyntax "EViewPat" go ELazyPat{} = missingSyntax "ELazyPat" #endif go HsTick{} = missingSyntax "HsTick" go HsBinTick{} = missingSyntax "HsBinTick" go HsUnboundVar{} = missingSyntax "HsUnboundVar" go HsRecFld{} = missingSyntax "HsRecFld" go HsOverLabel{} = missingSyntax "HsOverLabel" go HsAppType{} = missingSyntax "HsAppType" go HsConLikeOut{} = missingSyntax "HsConLikeOut" go ExplicitSum{} = missingSyntax "ExplicitSum" mMatch :: MatchEnv -> Key EMap -> (Substitution, EMap a) -> [(Substitution, a)] mMatch _ _ (_,EMEmpty) = [] mMatch env e (hs,m@EM{}) = hss ++ go (unLoc e) (hs,m) where hss = extendResult (emHole m) (HoleExpr $ mePruneA env e) hs go (ExplicitTuple _ as b) = mapFor emExplicitTuple >=> mMatch env b >=> mMatch env as go (HsApp _ l r) = mapFor emApp >=> mMatch env l >=> mMatch env r go (HsCase _ s mg) = mapFor emCase >=> mMatch env s >=> mMatch env mg go (HsDo _ sc ss) = mapFor emDo >=> mMatch env sc >=> mMatch env (unLoc ss) #if __GLASGOW_HASKELL__ < 900 go (HsIf _ _ c tr fl) = #else go (HsIf _ c tr fl) = #endif mapFor emIf >=> mMatch env c >=> mMatch env tr >=> mMatch env fl go (HsIPVar _ (HsIPName ip)) = mapFor emIPVar >=> mMatch env ip go (HsLam _ mg) = mapFor emLam >=> mMatch env mg go (HsLit _ l) = mapFor emLit >=> mMatch env l go (HsOverLit _ ol) = mapFor emOverLit >=> mMatch env (ol_val ol) go (HsPar _ e') = mapFor emPar >=> mMatch env e' go (HsVar _ v) = mapFor emVar >=> mMatch env (unLoc v) go (OpApp _ l o r) = mapFor emOpApp >=> mMatch env o >=> mMatch env l >=> mMatch env r go (NegApp _ e' _) = mapFor emNegApp >=> mMatch env e' go (RecordCon _ v fs) = mapFor emRecordCon >=> mMatch env (unLoc v) >=> mMatch env (fieldsToRdrNames $ rec_flds fs) go (RecordUpd _ e' fs) = mapFor emRecordUpd >=> mMatch env e' >=> mMatch env (fieldsToRdrNamesUpd fs) go (SectionL _ lhs o) = mapFor emSecL >=> mMatch env o >=> mMatch env lhs go (SectionR _ o rhs) = mapFor emSecR >=> mMatch env o >=> mMatch env rhs go (HsLet _ lbs e') = let bs = collectLocalBinders CollNoDictBinders lbs env' = extendMatchEnv env bs in mapFor emLet >=> mMatch env lbs >=> mMatch env' e' go (ExplicitList _ es) = mapFor emExplicitList >=> mMatch env es go (ExprWithTySig _ e' (HsWC _ (L _ (HsSig _ _ ty)))) = mapFor emExprWithTySig >=> mMatch env e' >=> mMatch env ty go _ = const [] -- TODO remove -- Add the matched expression to the holes map, fails if expression differs from one already in hole. extendResult :: Map RdrName a -> HoleVal -> Substitution -> [(Substitution, a)] extendResult hm v sub = catMaybes [ case lookupSubst n sub of Nothing -> return (extendSubst sub n v, x) Just v' -> sameHoleValue v v' >> return (sub, x) | (nm,x) <- mapAssocs hm, let n = rdrFS nm ] singleton :: [a] -> Maybe a singleton [x] = Just x singleton _ = Nothing -- | Determine if two expressions are alpha-equivalent. sameHoleValue :: HoleVal -> HoleVal -> Maybe () sameHoleValue (HoleExpr e1) (HoleExpr e2) = alphaEquivalent (astA e1) (astA e2) EMEmpty sameHoleValue (HolePat p1) (HolePat p2) = alphaEquivalent (cLPat $ astA p1) (cLPat $ astA p2) PatEmpty sameHoleValue (HoleType ty1) (HoleType ty2) = alphaEquivalent (astA ty1) (astA ty2) TyEmpty sameHoleValue _ _ = Nothing alphaEquivalent :: PatternMap m => Key m -> Key m -> m () -> Maybe () alphaEquivalent v1 v2 e = snd <$> singleton (findMatch env v2 m) where m = insertMatch emptyAlphaEnv emptyQs v1 () e env = ME emptyAlphaEnv err err _ = error "hole prune during alpha-equivalence check is impossible!" ------------------------------------------------------------------------ data SCMap a = SCEmpty | SCM { scmListComp :: MaybeMap a , scmMonadComp :: MaybeMap a #if __GLASGOW_HASKELL__ < 900 , scmDoExpr :: MaybeMap a #else , scmDoExpr :: FSEnv a -- We use empty string when modulename is Nothing #endif -- TODO: the rest } deriving (Functor) emptySCMapWrapper :: SCMap a emptySCMapWrapper = SCM mEmpty mEmpty mEmpty instance PatternMap SCMap where #if __GLASGOW_HASKELL__ < 900 type Key SCMap = HsStmtContext Name -- see comment on HsDo in GHC #elif __GLASGOW_HASKELL__ < 920 type Key SCMap = HsStmtContext GhcRn #else type Key SCMap = HsStmtContext (HsDoRn GhcPs) #endif mEmpty :: SCMap a mEmpty = SCEmpty mUnion :: SCMap a -> SCMap a -> SCMap a mUnion SCEmpty m = m mUnion m SCEmpty = m mUnion m1 m2 = SCM { scmListComp = unionOn scmListComp m1 m2 , scmMonadComp = unionOn scmMonadComp m1 m2 , scmDoExpr = unionOn scmDoExpr m1 m2 } mAlter :: AlphaEnv -> Quantifiers -> Key SCMap -> A a -> SCMap a -> SCMap a mAlter env vs sc f SCEmpty = mAlter env vs sc f emptySCMapWrapper mAlter env vs sc f m@SCM{} = go sc where go ListComp = m { scmListComp = mAlter env vs () f (scmListComp m) } go MonadComp = m { scmMonadComp = mAlter env vs () f (scmMonadComp m) } #if __GLASGOW_HASKELL__ < 900 go DoExpr = m { scmDoExpr = mAlter env vs () f (scmDoExpr m) } #else go (DoExpr mname) = m { scmDoExpr = mAlter env vs (maybe "" moduleNameFS mname) f (scmDoExpr m) } #endif go MDoExpr{} = missingSyntax "MDoExpr" go ArrowExpr = missingSyntax "ArrowExpr" go GhciStmtCtxt = missingSyntax "GhciStmtCtxt" go (PatGuard _) = missingSyntax "PatGuard" go (ParStmtCtxt _) = missingSyntax "ParStmtCtxt" go (TransStmtCtxt _) = missingSyntax "TransStmtCtxt" mMatch :: MatchEnv -> Key SCMap -> (Substitution, SCMap a) -> [(Substitution, a)] mMatch _ _ (_,SCEmpty) = [] mMatch env sc (hs,m@SCM{}) = go sc (hs,m) where go ListComp = mapFor scmListComp >=> mMatch env () go MonadComp = mapFor scmMonadComp >=> mMatch env () #if __GLASGOW_HASKELL__ < 900 go DoExpr = mapFor scmDoExpr >=> mMatch env () #else go (DoExpr mname) = mapFor scmDoExpr >=> mMatch env (maybe "" moduleNameFS mname) #endif go _ = const [] -- TODO ------------------------------------------------------------------------ -- Note [MatchGroup] -- A MatchGroup contains a list of argument types and a result type, but -- these aren't available until after typechecking, so they are all placeholders -- at this point. Also, don't care about the origin. newtype MGMap a = MGMap { unMGMap :: ListMap MMap a } deriving (Functor) instance PatternMap MGMap where type Key MGMap = MatchGroup GhcPs (LocatedA (HsExpr GhcPs)) mEmpty :: MGMap a mEmpty = MGMap mEmpty mUnion :: MGMap a -> MGMap a -> MGMap a mUnion (MGMap m1) (MGMap m2) = MGMap (mUnion m1 m2) mAlter :: AlphaEnv -> Quantifiers -> Key MGMap -> A a -> MGMap a -> MGMap a mAlter env vs mg f (MGMap m) = MGMap (mAlter env vs alts f m) where alts = map unLoc (unLoc $ mg_alts mg) mMatch :: MatchEnv -> Key MGMap -> (Substitution, MGMap a) -> [(Substitution, a)] mMatch env mg = mapFor unMGMap >=> mMatch env alts where alts = map unLoc (unLoc $ mg_alts mg) ------------------------------------------------------------------------ newtype MMap a = MMap { unMMap :: ListMap PatMap (GRHSSMap a) } deriving (Functor) instance PatternMap MMap where type Key MMap = Match GhcPs (LocatedA (HsExpr GhcPs)) mEmpty :: MMap a mEmpty = MMap mEmpty mUnion :: MMap a -> MMap a -> MMap a mUnion (MMap m1) (MMap m2) = MMap (mUnion m1 m2) mAlter :: AlphaEnv -> Quantifiers -> Key MMap -> A a -> MMap a -> MMap a mAlter env vs match f (MMap m) = let lpats = m_pats match pbs = collectPatsBinders CollNoDictBinders lpats env' = foldr extendAlphaEnvInternal env pbs vs' = vs `exceptQ` pbs in MMap (mAlter env vs lpats (toA (mAlter env' vs' (m_grhss match) f)) m) mMatch :: MatchEnv -> Key MMap -> (Substitution, MMap a) -> [(Substitution, a)] mMatch env match = mapFor unMMap >=> mMatch env lpats >=> mMatch env' (m_grhss match) where lpats = m_pats match pbs = collectPatsBinders CollNoDictBinders lpats env' = extendMatchEnv env pbs ------------------------------------------------------------------------ data CDMap a = CDEmpty | CDMap { cdPrefixCon :: ListMap PatMap a -- TODO , cdRecCon :: MaybeMap a , cdInfixCon :: PatMap (PatMap a) } deriving (Functor) emptyCDMapWrapper :: CDMap a emptyCDMapWrapper = CDMap mEmpty mEmpty instance PatternMap CDMap where #if __GLASGOW_HASKELL__ < 810 type Key CDMap = HsConDetails (LPat GhcPs) (HsRecFields GhcPs (LPat GhcPs)) #else -- We must manually expand 'LPat' to avoid UndecidableInstances in GHC 8.10+ type Key CDMap = HsConDetails (HsPatSigType GhcPs) (LocatedA (Pat GhcPs)) (HsRecFields GhcPs (LocatedA (Pat GhcPs))) -- type HsConPatDetails p = HsConDetails (HsPatSigType (NoGhcTc p)) (LPat p) (HsRecFields p (LPat p)) #endif mEmpty :: CDMap a mEmpty = CDEmpty mUnion :: CDMap a -> CDMap a -> CDMap a mUnion CDEmpty m = m mUnion m CDEmpty = m mUnion m1 m2 = CDMap { cdPrefixCon = unionOn cdPrefixCon m1 m2 , cdInfixCon = unionOn cdInfixCon m1 m2 } mAlter :: AlphaEnv -> Quantifiers -> Key CDMap -> A a -> CDMap a -> CDMap a mAlter env vs d f CDEmpty = mAlter env vs d f emptyCDMapWrapper mAlter env vs d f m@CDMap{} = go d where go (PrefixCon tyargs ps) = m { cdPrefixCon = mAlter env vs ps f (cdPrefixCon m) } go (RecCon _) = missingSyntax "RecCon" go (InfixCon p1 p2) = m { cdInfixCon = mAlter env vs p1 (toA (mAlter env vs p2 f)) (cdInfixCon m) } mMatch :: MatchEnv -> Key CDMap -> (Substitution, CDMap a) -> [(Substitution, a)] mMatch _ _ (_ ,CDEmpty) = [] mMatch env d (hs,m@CDMap{}) = go d (hs,m) where go (PrefixCon tyargs ps) = mapFor cdPrefixCon >=> mMatch env ps go (InfixCon p1 p2) = mapFor cdInfixCon >=> mMatch env p1 >=> mMatch env p2 go _ = const [] -- TODO ------------------------------------------------------------------------ -- Note [Variable Binders] -- We don't actually care about the variable name, since we are checking for -- alpha-equivalence. data PatMap a = PatEmpty | PatMap { pmHole :: Map RdrName a -- See Note [Holes] , pmWild :: MaybeMap a , pmVar :: MaybeMap a -- See Note [Variable Binders] , pmParPat :: PatMap a , pmTuplePat :: BoxityMap (ListMap PatMap a) , pmConPatIn :: FSEnv (CDMap a) -- TODO: the rest } deriving (Functor) emptyPatMapWrapper :: PatMap a emptyPatMapWrapper = PatMap mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty instance PatternMap PatMap where #if __GLASGOW_HASKELL__ < 810 type Key PatMap = LPat GhcPs #else -- We must manually expand 'LPat' to avoid UndecidableInstances in GHC 8.10+ type Key PatMap = LocatedA (Pat GhcPs) #endif mEmpty :: PatMap a mEmpty = PatEmpty mUnion :: PatMap a -> PatMap a -> PatMap a mUnion PatEmpty m = m mUnion m PatEmpty = m mUnion m1 m2 = PatMap { pmHole = unionOn pmHole m1 m2 , pmWild = unionOn pmWild m1 m2 , pmVar = unionOn pmVar m1 m2 , pmParPat = unionOn pmParPat m1 m2 , pmTuplePat = unionOn pmTuplePat m1 m2 , pmConPatIn = unionOn pmConPatIn m1 m2 } mAlter :: AlphaEnv -> Quantifiers -> Key PatMap -> A a -> PatMap a -> PatMap a mAlter env vs pat f PatEmpty = mAlter env vs pat f emptyPatMapWrapper mAlter env vs pat f m@PatMap{} = go (unLoc pat) where go (WildPat _) = m { pmWild = mAlter env vs () f (pmWild m) } go (VarPat _ v) | unLoc v `isQ` vs = m { pmHole = mAlter env vs (unLoc v) f (pmHole m) } | otherwise = m { pmVar = mAlter env vs () f (pmVar m) } -- See Note [Variable Binders] go LazyPat{} = missingSyntax "LazyPat" go AsPat{} = missingSyntax "AsPat" go BangPat{} = missingSyntax "BangPat" go ListPat{} = missingSyntax "ListPat" #if __GLASGOW_HASKELL__ < 900 go XPat{} = missingSyntax "XPat" go CoPat{} = missingSyntax "CoPat" go ConPatOut{} = missingSyntax "ConPatOut" go (ConPatIn c d) = #else go (ConPat _ c d) = #endif m { pmConPatIn = mAlter env vs (rdrFS (unLoc c)) (toA (mAlter env vs d f)) (pmConPatIn m) } go ViewPat{} = missingSyntax "ViewPat" go SplicePat{} = missingSyntax "SplicePat" go LitPat{} = missingSyntax "LitPat" go NPat{} = missingSyntax "NPat" go NPlusKPat{} = missingSyntax "NPlusKPat" go (ParPat _ p) = m { pmParPat = mAlter env vs p f (pmParPat m) } go (TuplePat _ ps b) = m { pmTuplePat = mAlter env vs b (toA (mAlter env vs ps f)) (pmTuplePat m) } go SigPat{} = missingSyntax "SigPat" go SumPat{} = missingSyntax "SumPat" mMatch :: MatchEnv -> Key PatMap -> (Substitution, PatMap a) -> [(Substitution, a)] mMatch _ _ (_, PatEmpty) = [] mMatch env pat (hs,m@PatMap{}) | Just lp@(L _ p) <- dLPat pat = hss lp ++ go p (hs,m) | otherwise = [] where hss lp = extendResult (pmHole m) (HolePat $ mePruneA env lp) hs go (WildPat _) = mapFor pmWild >=> mMatch env () go (ParPat _ p) = mapFor pmParPat >=> mMatch env p go (TuplePat _ ps b) = mapFor pmTuplePat >=> mMatch env b >=> mMatch env ps go (VarPat _ _) = mapFor pmVar >=> mMatch env () #if __GLASGOW_HASKELL__ < 900 go (ConPatIn c d) = #else go (ConPat _ c d) = #endif mapFor pmConPatIn >=> mMatch env (rdrFS (unLoc c)) >=> mMatch env d go _ = const [] -- TODO ------------------------------------------------------------------------ newtype GRHSSMap a = GRHSSMap { unGRHSSMap :: LBMap (ListMap GRHSMap a) } deriving (Functor) instance PatternMap GRHSSMap where type Key GRHSSMap = GRHSs GhcPs (LocatedA (HsExpr GhcPs)) mEmpty :: GRHSSMap a mEmpty = GRHSSMap mEmpty mUnion :: GRHSSMap a -> GRHSSMap a -> GRHSSMap a mUnion (GRHSSMap m1) (GRHSSMap m2) = GRHSSMap (mUnion m1 m2) mAlter :: AlphaEnv -> Quantifiers -> Key GRHSSMap -> A a -> GRHSSMap a -> GRHSSMap a mAlter env vs grhss f (GRHSSMap m) = let lbs = grhssLocalBinds grhss bs = collectLocalBinders CollNoDictBinders lbs env' = foldr extendAlphaEnvInternal env bs vs' = vs `exceptQ` bs in GRHSSMap (mAlter env vs lbs (toA (mAlter env' vs' (map unLoc $ grhssGRHSs grhss) f)) m) mMatch :: MatchEnv -> Key GRHSSMap -> (Substitution, GRHSSMap a) -> [(Substitution, a)] mMatch env grhss = mapFor unGRHSSMap >=> mMatch env lbs >=> mMatch env' (map unLoc $ grhssGRHSs grhss) where lbs = grhssLocalBinds grhss bs = collectLocalBinders CollNoDictBinders lbs env' = extendMatchEnv env bs ------------------------------------------------------------------------ newtype GRHSMap a = GRHSMap { unGRHSMap :: SLMap (EMap a) } deriving (Functor) instance PatternMap GRHSMap where type Key GRHSMap = GRHS GhcPs (LocatedA (HsExpr GhcPs)) mEmpty :: GRHSMap a mEmpty = GRHSMap mEmpty mUnion :: GRHSMap a -> GRHSMap a -> GRHSMap a mUnion (GRHSMap m1) (GRHSMap m2) = GRHSMap (mUnion m1 m2) mAlter :: AlphaEnv -> Quantifiers -> Key GRHSMap -> A a -> GRHSMap a -> GRHSMap a #if __GLASGOW_HASKELL__ < 900 mAlter _ _ XGRHS{} _ _ = missingSyntax "XGRHS" #endif mAlter env vs (GRHS _ gs b) f (GRHSMap m) = let bs = collectLStmtsBinders CollNoDictBinders gs env' = foldr extendAlphaEnvInternal env bs vs' = vs `exceptQ` bs in GRHSMap (mAlter env vs gs (toA (mAlter env' vs' b f)) m) mMatch :: MatchEnv -> Key GRHSMap -> (Substitution, GRHSMap a) -> [(Substitution, a)] #if __GLASGOW_HASKELL__ < 900 mMatch _ XGRHS{} = const [] #endif mMatch env (GRHS _ gs b) = mapFor unGRHSMap >=> mMatch env gs >=> mMatch env' b where bs = collectLStmtsBinders CollNoDictBinders gs env' = extendMatchEnv env bs ------------------------------------------------------------------------ data SLMap a = SLEmpty | SLM { slmNil :: MaybeMap a , slmCons :: SMap (SLMap a) } deriving (Functor) emptySLMapWrapper :: SLMap a emptySLMapWrapper = SLM mEmpty mEmpty instance PatternMap SLMap where type Key SLMap = [LocatedA (Stmt GhcPs (LocatedA (HsExpr GhcPs)))] mEmpty :: SLMap a mEmpty = SLEmpty mUnion :: SLMap a -> SLMap a -> SLMap a mUnion SLEmpty m = m mUnion m SLEmpty = m mUnion m1 m2 = SLM { slmNil = unionOn slmNil m1 m2 , slmCons = unionOn slmCons m1 m2 } mAlter :: AlphaEnv -> Quantifiers -> Key SLMap -> A a -> SLMap a -> SLMap a mAlter env vs ss f SLEmpty = mAlter env vs ss f emptySLMapWrapper mAlter env vs ss f m@SLM{} = go ss where go [] = m { slmNil = mAlter env vs () f (slmNil m) } go (s:ss') = let bs = collectLStmtBinders CollNoDictBinders s env' = foldr extendAlphaEnvInternal env bs vs' = vs `exceptQ` bs in m { slmCons = mAlter env vs s (toA (mAlter env' vs' ss' f)) (slmCons m) } mMatch :: MatchEnv -> Key SLMap -> (Substitution, SLMap a) -> [(Substitution, a)] mMatch _ _ (_,SLEmpty) = [] mMatch env ss (hs,m@SLM{}) = go ss (hs,m) where go [] = mapFor slmNil >=> mMatch env () go (s:ss') = let bs = collectLStmtBinders CollNoDictBinders s env' = extendMatchEnv env bs in mapFor slmCons >=> mMatch env s >=> mMatch env' ss' ------------------------------------------------------------------------ -- Note [Local Binds] -- We simplify this a bit here, assuming always ValBindsIn (because ValBindsOut -- only shows up after renaming. Also we ignore the [LSig] for now. data LBMap a = LBEmpty | LB { lbValBinds :: ListMap BMap a -- see Note [Local Binds] -- TODO: , lbIPBinds :: , lbEmpty :: MaybeMap a } deriving (Functor) emptyLBMapWrapper :: LBMap a emptyLBMapWrapper = LB mEmpty mEmpty instance PatternMap LBMap where type Key LBMap = HsLocalBinds GhcPs mEmpty :: LBMap a mEmpty = LBEmpty mUnion :: LBMap a -> LBMap a -> LBMap a mUnion LBEmpty m = m mUnion m LBEmpty = m mUnion m1 m2 = LB { lbValBinds = unionOn lbValBinds m1 m2 , lbEmpty = unionOn lbEmpty m1 m2 } mAlter :: AlphaEnv -> Quantifiers -> Key LBMap -> A a -> LBMap a -> LBMap a mAlter env vs lbs f LBEmpty = mAlter env vs lbs f emptyLBMapWrapper mAlter env vs lbs f m@LB{} = go lbs where go (EmptyLocalBinds _) = m { lbEmpty = mAlter env vs () f (lbEmpty m) } #if __GLASGOW_HASKELL__ < 900 go XHsLocalBindsLR{} = missingSyntax "XHsLocalBindsLR" #endif go (HsValBinds _ vbs) = let bs = collectHsValBinders CollNoDictBinders vbs env' = foldr extendAlphaEnvInternal env bs vs' = vs `exceptQ` bs in m { lbValBinds = mAlter env' vs' (deValBinds vbs) f (lbValBinds m) } go HsIPBinds{} = missingSyntax "HsIPBinds" mMatch :: MatchEnv -> Key LBMap -> (Substitution, LBMap a) -> [(Substitution, a)] mMatch _ _ (_,LBEmpty) = [] mMatch env lbs (hs,m@LB{}) = go lbs (hs,m) where go (EmptyLocalBinds _) = mapFor lbEmpty >=> mMatch env () go (HsValBinds _ vbs) = let bs = collectHsValBinders CollNoDictBinders vbs env' = extendMatchEnv env bs in mapFor lbValBinds >=> mMatch env' (deValBinds vbs) go _ = const [] -- TODO deValBinds :: HsValBinds GhcPs -> [HsBind GhcPs] deValBinds (ValBinds _ lbs _) = map unLoc (bagToList lbs) deValBinds _ = error "deValBinds ValBindsOut" ------------------------------------------------------------------------ -- Note [Bind env] -- We don't extend the env because it was already done at the LBMap level -- (because all bindings are available to the recursive group). data BMap a = BMEmpty | BM { bmFunBind :: MGMap a , bmVarBind :: EMap a , bmPatBind :: PatMap (GRHSSMap a) -- TODO: rest } deriving (Functor) emptyBMapWrapper :: BMap a emptyBMapWrapper = BM mEmpty mEmpty mEmpty instance PatternMap BMap where type Key BMap = HsBind GhcPs mEmpty :: BMap a mEmpty = BMEmpty mUnion :: BMap a -> BMap a -> BMap a mUnion BMEmpty m = m mUnion m BMEmpty = m mUnion m1 m2 = BM { bmFunBind = unionOn bmFunBind m1 m2 , bmVarBind = unionOn bmVarBind m1 m2 , bmPatBind = unionOn bmPatBind m1 m2 } mAlter :: AlphaEnv -> Quantifiers -> Key BMap -> A a -> BMap a -> BMap a mAlter env vs b f BMEmpty = mAlter env vs b f emptyBMapWrapper mAlter env vs b f m@BM{} = go b where -- see Note [Bind env] #if __GLASGOW_HASKELL__ < 900 go XHsBindsLR{} = missingSyntax "XHsBindsLR" go (FunBind _ _ mg _ _) = m { bmFunBind = mAlter env vs mg f (bmFunBind m) } go (VarBind _ _ e _) = m { bmVarBind = mAlter env vs e f (bmVarBind m) } #else go (FunBind _ _ mg _) = m { bmFunBind = mAlter env vs mg f (bmFunBind m) } go (VarBind _ _ e) = m { bmVarBind = mAlter env vs e f (bmVarBind m) } #endif go (PatBind _ lhs rhs _) = m { bmPatBind = mAlter env vs lhs (toA $ mAlter env vs rhs f) (bmPatBind m) } go AbsBinds{} = missingSyntax "AbsBinds" go PatSynBind{} = missingSyntax "PatSynBind" mMatch :: MatchEnv -> Key BMap -> (Substitution, BMap a) -> [(Substitution, a)] mMatch _ _ (_,BMEmpty) = [] mMatch env b (hs,m@BM{}) = go b (hs,m) where #if __GLASGOW_HASKELL__ < 900 go (FunBind _ _ mg _ _) = mapFor bmFunBind >=> mMatch env mg go (VarBind _ _ e _) = mapFor bmVarBind >=> mMatch env e #else go (FunBind _ _ mg _) = mapFor bmFunBind >=> mMatch env mg go (VarBind _ _ e) = mapFor bmVarBind >=> mMatch env e #endif go (PatBind _ lhs rhs _) = mapFor bmPatBind >=> mMatch env lhs >=> mMatch env rhs go _ = const [] -- TODO ------------------------------------------------------------------------ data SMap a = SMEmpty | SM { smLastStmt :: EMap a , smBindStmt :: PatMap (EMap a) , smBodyStmt :: EMap a -- TODO: the rest } deriving (Functor) emptySMapWrapper :: SMap a emptySMapWrapper = SM mEmpty mEmpty mEmpty instance PatternMap SMap where type Key SMap = LocatedA (Stmt GhcPs (LocatedA (HsExpr GhcPs))) mEmpty :: SMap a mEmpty = SMEmpty mUnion :: SMap a -> SMap a -> SMap a mUnion SMEmpty m = m mUnion m SMEmpty = m mUnion m1 m2 = SM { smLastStmt = unionOn smLastStmt m1 m2 , smBindStmt = unionOn smBindStmt m1 m2 , smBodyStmt = unionOn smBodyStmt m1 m2 } mAlter :: AlphaEnv -> Quantifiers -> Key SMap -> A a -> SMap a -> SMap a mAlter env vs s f SMEmpty = mAlter env vs s f emptySMapWrapper mAlter env vs s f m@(SM {}) = go (unLoc s) where go (BodyStmt _ e _ _) = m { smBodyStmt = mAlter env vs e f (smBodyStmt m) } go (LastStmt _ e _ _) = m { smLastStmt = mAlter env vs e f (smLastStmt m) } #if __GLASGOW_HASKELL__ < 900 go XStmtLR{} = missingSyntax "XStmtLR" go (BindStmt _ p e _ _) = #else go (BindStmt _ p e) = #endif let bs = collectPatBinders CollNoDictBinders p env' = foldr extendAlphaEnvInternal env bs vs' = vs `exceptQ` bs in m { smBindStmt = mAlter env vs p (toA (mAlter env' vs' e f)) (smBindStmt m) } go LetStmt{} = missingSyntax "LetStmt" go ParStmt{} = missingSyntax "ParStmt" go TransStmt{} = missingSyntax "TransStmt" go RecStmt{} = missingSyntax "RecStmt" go ApplicativeStmt{} = missingSyntax "ApplicativeStmt" mMatch :: MatchEnv -> Key SMap -> (Substitution, SMap a) -> [(Substitution, a)] mMatch _ _ (_,SMEmpty) = [] mMatch env s (hs,m) = go (unLoc s) (hs,m) where go (BodyStmt _ e _ _) = mapFor smBodyStmt >=> mMatch env e go (LastStmt _ e _ _) = mapFor smLastStmt >=> mMatch env e #if __GLASGOW_HASKELL__ < 900 go (BindStmt _ p e _ _) = #else go (BindStmt _ p e) = #endif let bs = collectPatBinders CollNoDictBinders p env' = extendMatchEnv env bs in mapFor smBindStmt >=> mMatch env p >=> mMatch env' e go _ = const [] -- TODO ------------------------------------------------------------------------ data TyMap a = TyEmpty | TM { tyHole :: Map RdrName a -- See Note [Holes] , tyHsTyVar :: VMap a , tyHsAppTy :: TyMap (TyMap a) #if __GLASGOW_HASKELL__ < 810 , tyHsForAllTy :: ForAllTyMap a -- See Note [Telescope] #else , tyHsForAllTy :: ForallVisMap (ForAllTyMap a) -- See Note [Telescope] #endif , tyHsFunTy :: TyMap (TyMap a) , tyHsListTy :: TyMap a , tyHsParTy :: TyMap a , tyHsQualTy :: TyMap (ListMap TyMap a) , tyHsSumTy :: ListMap TyMap a , tyHsTupleTy :: TupleSortMap (ListMap TyMap a) -- TODO: the rest } deriving (Functor) emptyTyMapWrapper :: TyMap a emptyTyMapWrapper = TM mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty mEmpty instance PatternMap TyMap where type Key TyMap = LocatedA (HsType GhcPs) mEmpty :: TyMap a mEmpty = TyEmpty mUnion :: TyMap a -> TyMap a -> TyMap a mUnion TyEmpty m = m mUnion m TyEmpty = m mUnion m1 m2 = TM { tyHole = unionOn tyHole m1 m2 , tyHsTyVar = unionOn tyHsTyVar m1 m2 , tyHsAppTy = unionOn tyHsAppTy m1 m2 , tyHsForAllTy = unionOn tyHsForAllTy m1 m2 , tyHsFunTy = unionOn tyHsFunTy m1 m2 , tyHsListTy = unionOn tyHsListTy m1 m2 , tyHsParTy = unionOn tyHsParTy m1 m2 , tyHsQualTy = unionOn tyHsQualTy m1 m2 , tyHsSumTy = unionOn tyHsSumTy m1 m2 , tyHsTupleTy = unionOn tyHsTupleTy m1 m2 } mAlter :: AlphaEnv -> Quantifiers -> Key TyMap -> A a -> TyMap a -> TyMap a mAlter env vs ty f TyEmpty = mAlter env vs ty f emptyTyMapWrapper mAlter env vs ty f m@(TM {}) = go (unLoc ty) -- See Note [TyVar Quantifiers] where go (HsTyVar _ _ (L _ v)) | v `isQ` vs = m { tyHole = mAlter env vs v f (tyHole m) } | otherwise = m { tyHsTyVar = mAlter env vs v f (tyHsTyVar m) } go HsOpTy{} = missingSyntax "HsOpTy" go HsIParamTy{} = missingSyntax "HsIParamTy" go HsKindSig{} = missingSyntax "HsKindSig" go HsSpliceTy{} = missingSyntax "HsSpliceTy" go HsDocTy{} = missingSyntax "HsDocTy" go HsBangTy{} = missingSyntax "HsBangTy" go HsRecTy{} = missingSyntax "HsRecTy" go (HsAppTy _ ty1 ty2) = m { tyHsAppTy = mAlter env vs ty1 (toA (mAlter env vs ty2 f)) (tyHsAppTy m) } #if __GLASGOW_HASKELL__ < 810 go (HsForAllTy _ bndrs ty') = m { tyHsForAllTy = mAlter env vs (map extractBinderInfo bndrs, ty') f (tyHsForAllTy m) } #elif __GLASGOW_HASKELL__ < 900 go (HsForAllTy _ vis bndrs ty') = m { tyHsForAllTy = mAlter env vs (vis == ForallVis) (toA (mAlter env vs (map extractBinderInfo bndrs, ty') f)) (tyHsForAllTy m) } #else go (HsForAllTy _ vis ty') | (isVisible, bndrs) <- splitVisBinders vis = m { tyHsForAllTy = mAlter env vs isVisible (toA (mAlter env vs (bndrs, ty') f)) (tyHsForAllTy m) } #endif #if __GLASGOW_HASKELL__ < 900 go (HsFunTy _ ty1 ty2) = m { tyHsFunTy = mAlter env vs ty1 (toA (mAlter env vs ty2 f)) (tyHsFunTy m) } #else go (HsFunTy _ _ ty1 ty2) = m { tyHsFunTy = mAlter env vs ty1 (toA (mAlter env vs ty2 f)) (tyHsFunTy m) } #endif go (HsListTy _ ty') = m { tyHsListTy = mAlter env vs ty' f (tyHsListTy m) } go (HsParTy _ ty') = m { tyHsParTy = mAlter env vs ty' f (tyHsParTy m) } go (HsQualTy _ cons ty') = m { tyHsQualTy = mAlter env vs ty' (toA (mAlter env vs (fromMaybeContext cons) f)) (tyHsQualTy m) } go HsStarTy{} = missingSyntax "HsStarTy" go (HsSumTy _ tys) = m { tyHsSumTy = mAlter env vs tys f (tyHsSumTy m) } go (HsTupleTy _ ts tys) = m { tyHsTupleTy = mAlter env vs ts (toA (mAlter env vs tys f)) (tyHsTupleTy m) } go XHsType{} = missingSyntax "XHsType" go HsExplicitListTy{} = missingSyntax "HsExplicitListTy" go HsExplicitTupleTy{} = missingSyntax "HsExplicitTupleTy" go HsTyLit{} = missingSyntax "HsTyLit" go HsWildCardTy{} = missingSyntax "HsWildCardTy" go HsAppKindTy{} = missingSyntax "HsAppKindTy" mMatch :: MatchEnv -> Key TyMap -> (Substitution, TyMap a) -> [(Substitution, a)] mMatch _ _ (_,TyEmpty) = [] mMatch env ty (hs,m@TM{}) = hss ++ go (unLoc ty) (hs,m) -- See Note [TyVar Quantifiers] where hss = extendResult (tyHole m) (HoleType $ mePruneA env ty) hs go (HsAppTy _ ty1 ty2) = mapFor tyHsAppTy >=> mMatch env ty1 >=> mMatch env ty2 #if __GLASGOW_HASKELL__ < 810 go (HsForAllTy _ bndrs ty') = mapFor tyHsForAllTy >=> mMatch env (map extractBinderInfo bndrs, ty') #elif __GLASGOW_HASKELL__ < 900 go (HsForAllTy _ vis bndrs ty') = mapFor tyHsForAllTy >=> mMatch env (vis == ForallVis) >=> mMatch env (map extractBinderInfo bndrs, ty') #else go (HsForAllTy _ telescope ty') | (isVisible, bndrs) <- splitVisBinders telescope = mapFor tyHsForAllTy >=> mMatch env isVisible >=> mMatch env (bndrs, ty') #endif #if __GLASGOW_HASKELL__ < 900 go (HsFunTy _ ty1 ty2) = mapFor tyHsFunTy >=> mMatch env ty1 >=> mMatch env ty2 #else go (HsFunTy _ _ ty1 ty2) = mapFor tyHsFunTy >=> mMatch env ty1 >=> mMatch env ty2 #endif go (HsListTy _ ty') = mapFor tyHsListTy >=> mMatch env ty' go (HsParTy _ ty') = mapFor tyHsParTy >=> mMatch env ty' go (HsQualTy _ cons ty') = mapFor tyHsQualTy >=> mMatch env ty' >=> mMatch env (fromMaybeContext cons) go (HsSumTy _ tys) = mapFor tyHsSumTy >=> mMatch env tys go (HsTupleTy _ ts tys) = mapFor tyHsTupleTy >=> mMatch env ts >=> mMatch env tys go (HsTyVar _ _ v) = mapFor tyHsTyVar >=> mMatch env (unLoc v) go _ = const [] -- TODO #if __GLASGOW_HASKELL__ < 900 extractBinderInfo :: LHsTyVarBndr GhcPs -> (RdrName, Maybe (LHsKind GhcPs)) extractBinderInfo = go . unLoc where go (UserTyVar _ v) = (unLoc v, Nothing) go (KindedTyVar _ v k) = (unLoc v, Just k) go XTyVarBndr{} = missingSyntax "XTyVarBndr" #else splitVisBinders :: HsForAllTelescope GhcPs -> (Bool, [(RdrName, Maybe (LHsKind GhcPs))]) splitVisBinders HsForAllVis{..} = (True, map extractBinderInfo hsf_vis_bndrs) splitVisBinders HsForAllInvis{..} = (False, map extractBinderInfo hsf_invis_bndrs) extractBinderInfo :: LHsTyVarBndr flag GhcPs -> (RdrName, Maybe (LHsKind GhcPs)) extractBinderInfo = go . unLoc where go (UserTyVar _ _ v) = (unLoc v, Nothing) go (KindedTyVar _ _ v k) = (unLoc v, Just k) go XTyVarBndr{} = missingSyntax "XTyVarBndr" #endif ------------------------------------------------------------------------ newtype RFMap a = RFM { rfmField :: VMap (EMap a) } deriving (Functor) instance PatternMap RFMap where type Key RFMap = LocatedA (HsRecField' RdrName (LocatedA (HsExpr GhcPs))) mEmpty :: RFMap a mEmpty = RFM mEmpty mUnion :: RFMap a -> RFMap a -> RFMap a mUnion (RFM m1) (RFM m2) = RFM (mUnion m1 m2) mAlter :: AlphaEnv -> Quantifiers -> Key RFMap -> A a -> RFMap a -> RFMap a mAlter env vs lf f m = go (unLoc lf) where go (HsRecField _ lbl arg _pun) = m { rfmField = mAlter env vs (unLoc lbl) (toA (mAlter env vs arg f)) (rfmField m) } mMatch :: MatchEnv -> Key RFMap -> (Substitution, RFMap a) -> [(Substitution, a)] mMatch env lf (hs,m) = go (unLoc lf) (hs,m) where go (HsRecField _ lbl arg _pun) = mapFor rfmField >=> mMatch env (unLoc lbl) >=> mMatch env arg -- Helper class to collapse the complex encoding of record fields into RdrNames. -- (The complexity is to support punning/duplicate/overlapping fields, which -- all happens well after parsing, so is not needed here.) class RecordFieldToRdrName f where recordFieldToRdrName :: f -> RdrName instance RecordFieldToRdrName (AmbiguousFieldOcc GhcPs) where recordFieldToRdrName = rdrNameAmbiguousFieldOcc instance RecordFieldToRdrName (FieldOcc p) where recordFieldToRdrName = unLoc . rdrNameFieldOcc instance RecordFieldToRdrName (FieldLabelStrings GhcPs) where recordFieldToRdrName = error "TBD" -- Either [LHsRecUpdField GhcPs] [LHsRecUpdProj GhcPs] fieldsToRdrNamesUpd :: Either [LHsRecUpdField GhcPs] [LHsRecUpdProj GhcPs] -> [LHsRecField' GhcPs RdrName (LHsExpr GhcPs)] fieldsToRdrNamesUpd (Left fs) = map go fs where go (L l (HsRecField a (L l2 f) arg pun)) = L l (HsRecField a (L l2 (recordFieldToRdrName f)) arg pun) fieldsToRdrNamesUpd (Right fs) = map go fs where go (L l (HsRecField a (L l2 f) arg pun)) = L l (HsRecField a (L l2 (recordFieldToRdrName f)) arg pun) fieldsToRdrNames :: RecordFieldToRdrName f => [LHsRecField' GhcPs f arg] -> [LHsRecField' GhcPs RdrName arg] fieldsToRdrNames = map go where go (L l (HsRecField a (L l2 f) arg pun)) = L l (HsRecField a (L l2 (recordFieldToRdrName f)) arg pun) ------------------------------------------------------------------------ data TupleSortMap a = TupleSortMap { tsUnboxed :: MaybeMap a , tsBoxed :: MaybeMap a , tsConstraint :: MaybeMap a , tsBoxedOrConstraint :: MaybeMap a } deriving (Functor) instance PatternMap TupleSortMap where type Key TupleSortMap = HsTupleSort mEmpty :: TupleSortMap a mEmpty = TupleSortMap mEmpty mEmpty mEmpty mEmpty mUnion :: TupleSortMap a -> TupleSortMap a -> TupleSortMap a mUnion m1 m2 = TupleSortMap { tsUnboxed = unionOn tsUnboxed m1 m2 , tsBoxed = unionOn tsBoxed m1 m2 , tsConstraint = unionOn tsConstraint m1 m2 , tsBoxedOrConstraint = unionOn tsBoxedOrConstraint m1 m2 } mAlter :: AlphaEnv -> Quantifiers -> Key TupleSortMap -> A a -> TupleSortMap a -> TupleSortMap a mAlter env vs HsUnboxedTuple f m = m { tsUnboxed = mAlter env vs () f (tsUnboxed m) } -- mAlter env vs HsBoxedOrConstraintTuple f m = -- m { tsBoxed = mAlter env vs () f (tsBoxed m) } -- mAlter env vs HsConstraintTuple f m = -- m { tsConstraint = mAlter env vs () f (tsConstraint m) } mAlter env vs HsBoxedOrConstraintTuple f m = m { tsBoxedOrConstraint = mAlter env vs () f (tsBoxedOrConstraint m) } mMatch :: MatchEnv -> Key TupleSortMap -> (Substitution, TupleSortMap a) -> [(Substitution, a)] mMatch env HsUnboxedTuple = mapFor tsUnboxed >=> mMatch env () -- mMatch env HsBoxedTuple = mapFor tsBoxed >=> mMatch env () -- mMatch env HsConstraintTuple = mapFor tsConstraint >=> mMatch env () mMatch env HsBoxedOrConstraintTuple = mapFor tsBoxedOrConstraint >=> mMatch env () ------------------------------------------------------------------------ -- Note [Telescope] -- Haskell's forall quantification is a telescope (type binders are in-scope -- to binders to the right. Example: forall r (a :: TYPE r). ... -- -- To support this, we peel off the binders one at a time, extending the -- environment at each layer. data ForAllTyMap a = ForAllTyMap { fatNil :: TyMap a , fatUser :: ForAllTyMap a , fatKinded :: TyMap (ForAllTyMap a) } deriving (Functor) instance PatternMap ForAllTyMap where type Key ForAllTyMap = ([(RdrName, Maybe (LocatedA (HsKind GhcPs)))], LocatedA (HsType GhcPs)) mEmpty :: ForAllTyMap a mEmpty = ForAllTyMap mEmpty mEmpty mEmpty mUnion :: ForAllTyMap a -> ForAllTyMap a -> ForAllTyMap a mUnion m1 m2 = ForAllTyMap { fatNil = unionOn fatNil m1 m2 , fatUser = unionOn fatUser m1 m2 , fatKinded = unionOn fatKinded m1 m2 } mAlter :: AlphaEnv -> Quantifiers -> Key ForAllTyMap -> A a -> ForAllTyMap a -> ForAllTyMap a mAlter env vs ([], ty) f m = m { fatNil = mAlter env vs ty f (fatNil m) } mAlter env vs ((v,mbK):rest, ty) f m | Just k <- mbK = m { fatKinded = mAlter env vs k (toA (mAlter env' vs' (rest, ty) f)) (fatKinded m) } | otherwise = m { fatUser = mAlter env' vs' (rest, ty) f (fatUser m) } where env' = extendAlphaEnvInternal v env vs' = vs `exceptQ` [v] mMatch :: MatchEnv -> Key ForAllTyMap -> (Substitution, ForAllTyMap a) -> [(Substitution, a)] mMatch env ([],ty) = mapFor fatNil >=> mMatch env ty mMatch env ((v,mbK):rest, ty) | Just k <- mbK = mapFor fatKinded >=> mMatch env k >=> mMatch env' (rest, ty) | otherwise = mapFor fatUser >=> mMatch env' (rest, ty) where env' = extendMatchEnv env [v] #if __GLASGOW_HASKELL__ < 810 #else newtype ForallVisMap a = ForallVisMap { favBoolMap :: BoolMap a } deriving (Functor) instance PatternMap ForallVisMap where type Key ForallVisMap = Bool mEmpty :: ForallVisMap a mEmpty = ForallVisMap mEmpty mUnion :: ForallVisMap a -> ForallVisMap a -> ForallVisMap a mUnion m1 m2 = ForallVisMap (unionOn favBoolMap m1 m2) mAlter :: AlphaEnv -> Quantifiers -> Key ForallVisMap -> A a -> ForallVisMap a -> ForallVisMap a mAlter env vs k f (ForallVisMap m) = ForallVisMap $ mAlter env vs k f m mMatch :: MatchEnv -> Key ForallVisMap -> (Substitution, ForallVisMap a) -> [(Substitution, a)] mMatch env b = mapFor favBoolMap >=> mMatch env b #endif