{-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE FlexibleContexts, FlexibleInstances, TemplateHaskell, MultiParamTypeClasses, UndecidableInstances, RankNTypes, ImplicitParams #-} -- MonoLocalBinds extension prevents premature generalization, which -- results in the "default" instance being picked. {-# LANGUAGE MonoLocalBinds #-} module Language.Haskell.Names.Open.Instances where import Language.Haskell.Names.Types import Language.Haskell.Names.Open.Base import Language.Haskell.Names.Open.Derived () import Language.Haskell.Names.GetBound import Language.Haskell.Names.RecordWildcards import Language.Haskell.Exts import Language.Haskell.Names.SyntaxUtils import qualified Data.Data as D import Data.Typeable import Data.Lens.Light import Data.List import qualified Data.Traversable as T c :: Applicative w => c -> w c c = pure (<|) :: (Applicative w, Resolvable b, ?alg :: Alg w) => w (b -> c) -> (b, Scope) -> w c (<|) k (b, sc) = k <*> alg b sc infixl 4 <| (-:) :: Scope -> a -> (a, Scope) sc -: b = (b, sc) infix 5 -: instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (Decl l) where rtraverse e sc = case e of -- N.B. We do not add pat to the local scope. -- -- If this is a top-level binding, then we shouldn't do so, lest -- global values are marked as local. -- (see https://github.com/haskell-suite/haskell-names/issues/35) -- -- If this is a local binding, then we have already introduced these -- variables when processing the enclosing Binds. PatBind l pat rhs mbWhere -> let scWithWhere = intro mbWhere sc in c PatBind <| sc -: l <| sc -: pat <| exprV scWithWhere -: rhs <| sc -: mbWhere p@(PatSyn l pat rpat dir) -> let scWithPatSyn = intro p sc scWithPat = intro pat scWithPatSyn in c PatSyn <| sc -: l <| (setPatSynMode PatSynLeftHandSide sc) -: pat <| (setPatSynMode PatSynRightHandSide scWithPat) -: rpat <| sc -: dir TypeSig l names ty -> c TypeSig <| sc -: l <| signatureV sc -: names <| sc -: ty InfixDecl l assoc mp ops -> c InfixDecl <| sc -: l <| sc -: assoc <| sc -: mp <| exprV sc -: ops InstDecl l mOverlap rule mInstDecls -> let sc' = setInstClassName (Just (dropAnn (instanceRuleClass rule))) sc in c InstDecl <| sc' -: l <| sc' -: mOverlap <| sc' -: rule <| sc' -: mInstDecls _ -> defaultRtraverse e sc instanceRuleClass :: InstRule l -> QName l instanceRuleClass (IParen _ instRule) = instanceRuleClass instRule instanceRuleClass (IRule _ _ _ instHead) = instanceHeadClass instHead instanceHeadClass :: InstHead l -> QName l instanceHeadClass (IHCon _ qn) = qn instanceHeadClass (IHInfix _ _ qn) = qn instanceHeadClass (IHParen _ instHead) = instanceHeadClass instHead instanceHeadClass (IHApp _ instHead _) = instanceHeadClass instHead instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (Type l) where rtraverse e sc = defaultRtraverse e (exprT sc) instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (DeclHead l) where rtraverse e sc = case e of DHead l name -> c DHead <| sc -: l <| binderT sc -: name DHInfix l v1 name -> c DHInfix <| sc -: l <| sc -: v1 <| binderT sc -: name _ -> defaultRtraverse e sc instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (ConDecl l) where rtraverse e sc = case e of ConDecl l name tys -> c ConDecl <| sc -: l <| binderV sc -: name <| sc -: tys InfixConDecl l t1 name t2 -> c InfixConDecl <| sc -: l <| sc -: t1 <| binderV sc -: name <| sc -: t2 RecDecl l name fields -> c RecDecl <| sc -: l <| binderV sc -: name <| sc -: fields instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (FieldDecl l) where rtraverse e sc = case e of FieldDecl l name tys -> c FieldDecl <| sc -: l <| binderV sc -: name <| sc -: tys instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (Pat l) where rtraverse e sc = case e of PVar l name -> c PVar <| sc -: l <| binderV sc -: name PNPlusK l name i -> c PNPlusK <| sc -: l <| binderV sc -: name <| sc -: i PInfixApp l pat1 name pat2 -> c PInfixApp <| sc -: l <| sc -: pat1 <| exprV sc -: name <| sc -: pat2 PApp l qn pat -> c PApp <| sc -: l <| exprV sc -: qn <| sc -: pat PRec l qn pfs -> let scWc = setWcNames (patWcNames (sc ^. gTable) qn pfs) sc in c PRec <| sc -: l <| exprV sc -: qn <| scWc -: pfs PAsPat l n pat -> c PAsPat <| sc -: l <| binderV sc -: n <| sc -: pat PViewPat l exp pat -> c PViewPat <| sc -: l <| exprV sc -: exp <| sc -: pat _ -> defaultRtraverse e sc instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (PatField l) where rtraverse e sc = case e of PFieldPat l qn pat -> c PFieldPat <| sc -: l <| exprRS sc -: qn <| sc -: pat PFieldPun l qn -> c PFieldPun <| sc -: l <| exprRS sc -: qn PFieldWildcard {} -> defaultRtraverse e sc -- | Chain a sequence of nodes where every node may introduce some -- variables into scope for the subsequent nodes. Examples: patterns (see -- note [Nested pattern scopes]), statements. chain :: ( Resolvable (a l) , GetBound (a l) l , Applicative w , SrcInfo l , D.Data l , ?alg :: Alg w) => [a l] -> Scope -> (w [a l], Scope) chain pats sc = case pats of [] -> (pure [], sc) p:ps -> let sc' = intro p sc p' = alg p sc (ps', sc'') = chain ps sc' in ((:) <$> p' <*> ps', sc'') instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (Match l) where rtraverse e sc = case e of Match l name pats rhs mbWhere -> -- f x y z = ... -- where ... let (pats', scWithPats) = chain pats sc scWithWhere = intro mbWhere scWithPats in c Match <| sc -: l <| binderV sc -: name <*> pats' -- has been already traversed <| exprV scWithWhere -: rhs <| scWithPats -: mbWhere InfixMatch l pat1 name patsRest rhs mbWhere -> let equivalentMatch = Match l name (pat1:patsRest) rhs mbWhere back (Match l name (pat1:patsRest) rhs mbWhere) = InfixMatch l pat1 name patsRest rhs mbWhere back _ = error "InfixMatch" in back <$> rtraverse equivalentMatch sc -- NB: there is an inefficiency here (and in similar places), because we -- call intro on the same subtree several times. Maybe tackle it later. instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (Binds l) where rtraverse e sc = case e of BDecls l decls -> let scWithBinds = intro decls sc in c BDecls <| sc -: l <| scWithBinds -: decls _ -> defaultRtraverse e sc instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (Exp l) where rtraverse e sc = case e of Let l bnds body -> let scWithBinds = intro bnds sc in c Let <| sc -: l <| scWithBinds -: bnds <| scWithBinds -: body Lambda l pats body -> let (pats', scWithPats) = chain pats sc in c Lambda <| sc -: l <*> pats' <| scWithPats -: body ListComp l e stmts -> let (stmts', scWithStmts) = chain stmts sc in c ListComp <| sc -: l <| scWithStmts -: e <*> stmts' ParComp l e stmtss -> let (stmtss', scsWithStmts) = unzip $ map (\stmts -> chain stmts sc) stmtss scWithAllStmtss = foldl1' mergeLocalScopes scsWithStmts in c ParComp <| sc -: l <| scWithAllStmtss -: e <*> T.sequenceA stmtss' Proc l pat e -> let scWithPat = intro pat sc in c Proc <| sc -: l <| sc -: pat <| scWithPat -: e RecConstr l qn fields -> let scWc = setWcNames (expWcNames (sc ^. gTable) (sc ^. lTable) qn fields) sc in c RecConstr <| sc -: l <| sc -: qn <| scWc -: fields _ -> defaultRtraverse e sc instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (FieldUpdate l) where rtraverse e sc = case e of FieldUpdate l qn exp -> c FieldUpdate <| sc -: l <| exprRS sc -: qn <| sc -: exp FieldPun l qn -> c FieldPun <| sc -: l <| exprRS sc -: qn FieldWildcard {} -> defaultRtraverse e sc instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (Alt l) where rtraverse e sc = case e of Alt l pat guardedAlts mbWhere -> let scWithPat = intro pat sc scWithBinds = intro mbWhere scWithPat in c Alt <| sc -: l <| sc -: pat <| scWithBinds -: guardedAlts <| scWithBinds -: mbWhere instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (GuardedRhs l) where rtraverse e sc = case e of GuardedRhs l stmts exp -> let (stmts', scWithStmts) = chain stmts sc in c GuardedRhs <| sc -: l <*> stmts' <| scWithStmts -: exp instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable [Stmt l] where rtraverse e sc = fst $ chain e sc instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (QualStmt l) where rtraverse e sc = case e of QualStmt {} -> defaultRtraverse e sc _ -> error "haskell-names: TransformListComp is not supported yet" instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (InstRule l) where rtraverse e sc = case e of IRule l mtv mc ih -> c IRule <| sc -: l <| sc -: mtv <| sc -: mc <| exprT sc -: ih _ -> defaultRtraverse e sc instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (Context l) where rtraverse e sc = defaultRtraverse e (exprT sc) instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (InstDecl l) where rtraverse e sc = case e of InsDecl dl (PatBind l (PVar pl name) rhs mbWhere) -> let scWithWhere = intro mbWhere sc in c InsDecl <| sc -: dl <*> (c PatBind <| sc -: l <*> (c PVar <| sc -: pl <| exprUV sc -: name) <| exprV scWithWhere -: rhs <| sc -: mbWhere) InsDecl dl (FunBind bl ms) -> c InsDecl <| sc -: dl <*> (c FunBind <| sc -: bl <*> T.for ms (\m -> case m of Match l name pats rhs mbWhere -> -- f x y z = ... -- where ... let (pats', scWithPats) = chain pats sc scWithWhere = intro mbWhere scWithPats in c Match <| sc -: l <| exprUV sc -: name <*> pats' -- has been already traversed <| exprV scWithWhere -: rhs <| scWithPats -: mbWhere InfixMatch l pat1 name patsRest rhs mbWhere -> -- x <*> y = ... -- where ... let (pats', scWithPats) = chain (pat1:patsRest) sc pat1' = fmap head pats' patsRest' = fmap tail pats' scWithWhere = intro mbWhere scWithPats in c InfixMatch <| sc -: l <*> pat1' -- has been already traversed <| exprUV sc -: name <*> patsRest' -- has been already traversed <| exprV scWithWhere -: rhs <| scWithPats -: mbWhere)) InsType dl (TyApp al (TyCon cl qn) aa) rhs -> c InsType <| sc -: dl <*> (c TyApp <| sc -: al <*> (c TyCon <| sc -: cl <| exprUT sc -: qn) <| sc -: aa) <| sc -: rhs InsData dl don (TyApp al (TyCon cl qn) aa) cs md -> c InsData <| sc -: dl <| sc -: don <*> (c TyApp <| sc -: al <*> (c TyCon <| sc -: cl <| exprUT sc -: qn) <| sc -: aa) <| sc -: cs <| sc -: md InsGData dl don (TyApp al (TyCon cl qn) aa) mk cs md -> c InsGData <| sc -: dl <| sc -: don <*> (c TyApp <| sc -: al <*> (c TyCon <| sc -: cl <| exprUT sc -: qn) <| sc -: aa) <| sc -: mk <| sc -: cs <| sc -: md _ -> defaultRtraverse e sc instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (ClassDecl l) where rtraverse e sc = case e of ClsDecl l (TypeSig sl [n] t) -> c ClsDecl <| sc -: l <*> (c TypeSig <| sc -: sl <| binderV sc -: [n] <| sc -: t) _ -> defaultRtraverse e sc instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (Op l) where rtraverse e sc = case e of VarOp l name -> c VarOp <| sc -: l <*> fmap qNameToName (alg (nameToQName name) (exprV sc)) ConOp l name -> c ConOp <| sc -: l <*> fmap qNameToName (alg (nameToQName name) (exprV sc)) {- Note [Nested pattern scopes] ~~~~~~~~~~~~~~~~~~~~~~ When we resolve a group of patterns, their scopes nest. Most of the time, this is not important, but there are two exceptions: 1. ScopedTypeVariables Example: f (x :: a) (y :: a) = ... The first 'a' is a binder, the second — a reference. 2. View patterns An expression inside a view pattern may reference the variables bound earlier. Example: f x (find (< x) -> Just y) = ... -} -- Some road-block Resolvable instances instance Typeable a => Resolvable (Scoped a) where rtraverse = flip $ const pure instance Resolvable SrcSpan where rtraverse = flip $ const pure instance Resolvable SrcSpanInfo where rtraverse = flip $ const pure