{-# LANGUAGE CPP, MultiWayIf #-}
module TmOracle (
PmExpr(..), PmLit(..), SimpleEq, ComplexEq, PmVarEnv, falsePmExpr,
eqPmLit, filterComplex, isNotPmExprOther, runPmPprM, lhsExprToPmExpr,
hsExprToPmExpr, pprPmExprWithParens,
tmOracle, TmState, initialTmState, solveOneEq, extendSubst, canDiverge,
toComplex, exprDeepLookup, pmLitType, flattenPmVarEnv
) where
#include "HsVersions.h"
import GhcPrelude
import PmExpr
import Id
import Name
import Type
import HsLit
import TcHsSyn
import MonadUtils
import Util
import NameEnv
type PmVarEnv = NameEnv PmExpr
type TmOracleEnv = (Bool, PmVarEnv)
canDiverge :: Name -> TmState -> Bool
canDiverge :: Name -> TmState -> Bool
canDiverge x :: Name
x (standby :: [ComplexEq]
standby, (_unhandled :: Bool
_unhandled, env :: PmVarEnv
env))
| PmExprVar y :: Name
y <- PmVarEnv -> Name -> PmExpr
varDeepLookup PmVarEnv
env Name
x
= Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ (ComplexEq -> Bool) -> [ComplexEq] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Name -> ComplexEq -> Bool
isForcedByEq Name
x) [ComplexEq]
standby Bool -> Bool -> Bool
|| (ComplexEq -> Bool) -> [ComplexEq] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Name -> ComplexEq -> Bool
isForcedByEq Name
y) [ComplexEq]
standby
| Bool
otherwise = Bool
False
where
isForcedByEq :: Name -> ComplexEq -> Bool
isForcedByEq :: Name -> ComplexEq -> Bool
isForcedByEq y :: Name
y (e1 :: PmExpr
e1, e2 :: PmExpr
e2) = Name -> PmExpr -> Bool
varIn Name
y PmExpr
e1 Bool -> Bool -> Bool
|| Name -> PmExpr -> Bool
varIn Name
y PmExpr
e2
varIn :: Name -> PmExpr -> Bool
varIn :: Name -> PmExpr -> Bool
varIn x :: Name
x e :: PmExpr
e = case PmExpr
e of
PmExprVar y :: Name
y -> Name
x Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
== Name
y
PmExprCon _ es :: [PmExpr]
es -> (PmExpr -> Bool) -> [PmExpr] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Name
x Name -> PmExpr -> Bool
`varIn`) [PmExpr]
es
PmExprLit _ -> Bool
False
PmExprEq e1 :: PmExpr
e1 e2 :: PmExpr
e2 -> (Name
x Name -> PmExpr -> Bool
`varIn` PmExpr
e1) Bool -> Bool -> Bool
|| (Name
x Name -> PmExpr -> Bool
`varIn` PmExpr
e2)
PmExprOther _ -> Bool
False
flattenPmVarEnv :: PmVarEnv -> PmVarEnv
flattenPmVarEnv :: PmVarEnv -> PmVarEnv
flattenPmVarEnv env :: PmVarEnv
env = (PmExpr -> PmExpr) -> PmVarEnv -> PmVarEnv
forall elt1 elt2. (elt1 -> elt2) -> NameEnv elt1 -> NameEnv elt2
mapNameEnv (PmVarEnv -> PmExpr -> PmExpr
exprDeepLookup PmVarEnv
env) PmVarEnv
env
type TmState = ([ComplexEq], TmOracleEnv)
initialTmState :: TmState
initialTmState :: TmState
initialTmState = ([], (Bool
False, PmVarEnv
forall a. NameEnv a
emptyNameEnv))
solveOneEq :: TmState -> ComplexEq -> Maybe TmState
solveOneEq :: TmState -> ComplexEq -> Maybe TmState
solveOneEq solver_env :: TmState
solver_env@(_,(_,env :: PmVarEnv
env)) complex :: ComplexEq
complex
= TmState -> ComplexEq -> Maybe TmState
solveComplexEq TmState
solver_env
(ComplexEq -> Maybe TmState) -> ComplexEq -> Maybe TmState
forall a b. (a -> b) -> a -> b
$ ComplexEq -> ComplexEq
simplifyComplexEq
(ComplexEq -> ComplexEq) -> ComplexEq -> ComplexEq
forall a b. (a -> b) -> a -> b
$ PmVarEnv -> ComplexEq -> ComplexEq
applySubstComplexEq PmVarEnv
env ComplexEq
complex
solveComplexEq :: TmState -> ComplexEq -> Maybe TmState
solveComplexEq :: TmState -> ComplexEq -> Maybe TmState
solveComplexEq solver_state :: TmState
solver_state@(standby :: [ComplexEq]
standby, (unhandled :: Bool
unhandled, env :: PmVarEnv
env)) eq :: ComplexEq
eq@(e1 :: PmExpr
e1, e2 :: PmExpr
e2) = case ComplexEq
eq of
(PmExprOther _,_) -> TmState -> Maybe TmState
forall a. a -> Maybe a
Just ([ComplexEq]
standby, (Bool
True, PmVarEnv
env))
(_,PmExprOther _) -> TmState -> Maybe TmState
forall a. a -> Maybe a
Just ([ComplexEq]
standby, (Bool
True, PmVarEnv
env))
(PmExprLit l1 :: PmLit
l1, PmExprLit l2 :: PmLit
l2) -> case PmLit -> PmLit -> Bool
eqPmLit PmLit
l1 PmLit
l2 of
True -> TmState -> Maybe TmState
forall a. a -> Maybe a
Just TmState
solver_state
False -> Maybe TmState
forall a. Maybe a
Nothing
(PmExprCon c1 :: ConLike
c1 ts1 :: [PmExpr]
ts1, PmExprCon c2 :: ConLike
c2 ts2 :: [PmExpr]
ts2)
| ConLike
c1 ConLike -> ConLike -> Bool
forall a. Eq a => a -> a -> Bool
== ConLike
c2 -> (TmState -> ComplexEq -> Maybe TmState)
-> TmState -> [ComplexEq] -> Maybe TmState
forall (m :: * -> *) a b.
Monad m =>
(a -> b -> m a) -> a -> [b] -> m a
foldlM TmState -> ComplexEq -> Maybe TmState
solveComplexEq TmState
solver_state ([PmExpr] -> [PmExpr] -> [ComplexEq]
forall a b. [a] -> [b] -> [(a, b)]
zip [PmExpr]
ts1 [PmExpr]
ts2)
| Bool
otherwise -> Maybe TmState
forall a. Maybe a
Nothing
(PmExprCon _ [], PmExprEq t1 :: PmExpr
t1 t2 :: PmExpr
t2)
| PmExpr -> Bool
isTruePmExpr PmExpr
e1 -> TmState -> ComplexEq -> Maybe TmState
solveComplexEq TmState
solver_state (PmExpr
t1, PmExpr
t2)
| PmExpr -> Bool
isFalsePmExpr PmExpr
e1 -> TmState -> Maybe TmState
forall a. a -> Maybe a
Just (ComplexEq
eqComplexEq -> [ComplexEq] -> [ComplexEq]
forall a. a -> [a] -> [a]
:[ComplexEq]
standby, (Bool
unhandled, PmVarEnv
env))
(PmExprEq t1 :: PmExpr
t1 t2 :: PmExpr
t2, PmExprCon _ [])
| PmExpr -> Bool
isTruePmExpr PmExpr
e2 -> TmState -> ComplexEq -> Maybe TmState
solveComplexEq TmState
solver_state (PmExpr
t1, PmExpr
t2)
| PmExpr -> Bool
isFalsePmExpr PmExpr
e2 -> TmState -> Maybe TmState
forall a. a -> Maybe a
Just (ComplexEq
eqComplexEq -> [ComplexEq] -> [ComplexEq]
forall a. a -> [a] -> [a]
:[ComplexEq]
standby, (Bool
unhandled, PmVarEnv
env))
(PmExprVar x :: Name
x, PmExprVar y :: Name
y)
| Name
x Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
== Name
y -> TmState -> Maybe TmState
forall a. a -> Maybe a
Just TmState
solver_state
| Bool
otherwise -> Name -> PmExpr -> TmState -> Maybe TmState
extendSubstAndSolve Name
x PmExpr
e2 TmState
solver_state
(PmExprVar x :: Name
x, _) -> Name -> PmExpr -> TmState -> Maybe TmState
extendSubstAndSolve Name
x PmExpr
e2 TmState
solver_state
(_, PmExprVar x :: Name
x) -> Name -> PmExpr -> TmState -> Maybe TmState
extendSubstAndSolve Name
x PmExpr
e1 TmState
solver_state
(PmExprEq _ _, PmExprEq _ _) -> TmState -> Maybe TmState
forall a. a -> Maybe a
Just (ComplexEq
eqComplexEq -> [ComplexEq] -> [ComplexEq]
forall a. a -> [a] -> [a]
:[ComplexEq]
standby, (Bool
unhandled, PmVarEnv
env))
_ -> TmState -> Maybe TmState
forall a. a -> Maybe a
Just ([ComplexEq]
standby, (Bool
True, PmVarEnv
env))
extendSubstAndSolve :: Name -> PmExpr -> TmState -> Maybe TmState
extendSubstAndSolve :: Name -> PmExpr -> TmState -> Maybe TmState
extendSubstAndSolve x :: Name
x e :: PmExpr
e (standby :: [ComplexEq]
standby, (unhandled :: Bool
unhandled, env :: PmVarEnv
env))
= (TmState -> ComplexEq -> Maybe TmState)
-> TmState -> [ComplexEq] -> Maybe TmState
forall (m :: * -> *) a b.
Monad m =>
(a -> b -> m a) -> a -> [b] -> m a
foldlM TmState -> ComplexEq -> Maybe TmState
solveComplexEq TmState
new_incr_state ((ComplexEq -> ComplexEq) -> [ComplexEq] -> [ComplexEq]
forall a b. (a -> b) -> [a] -> [b]
map ComplexEq -> ComplexEq
simplifyComplexEq [ComplexEq]
changed)
where
(changed :: [ComplexEq]
changed, unchanged :: [ComplexEq]
unchanged) = (ComplexEq -> Either ComplexEq ComplexEq)
-> [ComplexEq] -> ([ComplexEq], [ComplexEq])
forall a b c. (a -> Either b c) -> [a] -> ([b], [c])
partitionWith (Name -> PmExpr -> ComplexEq -> Either ComplexEq ComplexEq
substComplexEq Name
x PmExpr
e) [ComplexEq]
standby
new_incr_state :: TmState
new_incr_state = ([ComplexEq]
unchanged, (Bool
unhandled, PmVarEnv -> Name -> PmExpr -> PmVarEnv
forall a. NameEnv a -> Name -> a -> NameEnv a
extendNameEnv PmVarEnv
env Name
x PmExpr
e))
extendSubst :: Id -> PmExpr -> TmState -> TmState
extendSubst :: Id -> PmExpr -> TmState -> TmState
extendSubst y :: Id
y e :: PmExpr
e (standby :: [ComplexEq]
standby, (unhandled :: Bool
unhandled, env :: PmVarEnv
env))
| PmExpr -> Bool
isNotPmExprOther PmExpr
simpl_e
= ([ComplexEq]
standby, (Bool
unhandled, PmVarEnv -> Name -> PmExpr -> PmVarEnv
forall a. NameEnv a -> Name -> a -> NameEnv a
extendNameEnv PmVarEnv
env Name
x PmExpr
simpl_e))
| Bool
otherwise = ([ComplexEq]
standby, (Bool
True, PmVarEnv
env))
where
x :: Name
x = Id -> Name
idName Id
y
simpl_e :: PmExpr
simpl_e = (PmExpr, Bool) -> PmExpr
forall a b. (a, b) -> a
fst ((PmExpr, Bool) -> PmExpr) -> (PmExpr, Bool) -> PmExpr
forall a b. (a -> b) -> a -> b
$ PmExpr -> (PmExpr, Bool)
simplifyPmExpr (PmExpr -> (PmExpr, Bool)) -> PmExpr -> (PmExpr, Bool)
forall a b. (a -> b) -> a -> b
$ PmVarEnv -> PmExpr -> PmExpr
exprDeepLookup PmVarEnv
env PmExpr
e
simplifyComplexEq :: ComplexEq -> ComplexEq
simplifyComplexEq :: ComplexEq -> ComplexEq
simplifyComplexEq (e1 :: PmExpr
e1, e2 :: PmExpr
e2) = ((PmExpr, Bool) -> PmExpr
forall a b. (a, b) -> a
fst ((PmExpr, Bool) -> PmExpr) -> (PmExpr, Bool) -> PmExpr
forall a b. (a -> b) -> a -> b
$ PmExpr -> (PmExpr, Bool)
simplifyPmExpr PmExpr
e1, (PmExpr, Bool) -> PmExpr
forall a b. (a, b) -> a
fst ((PmExpr, Bool) -> PmExpr) -> (PmExpr, Bool) -> PmExpr
forall a b. (a -> b) -> a -> b
$ PmExpr -> (PmExpr, Bool)
simplifyPmExpr PmExpr
e2)
simplifyPmExpr :: PmExpr -> (PmExpr, Bool)
simplifyPmExpr :: PmExpr -> (PmExpr, Bool)
simplifyPmExpr e :: PmExpr
e = case PmExpr
e of
PmExprCon c :: ConLike
c ts :: [PmExpr]
ts -> case (PmExpr -> (PmExpr, Bool)) -> [PmExpr] -> ([PmExpr], [Bool])
forall a b c. (a -> (b, c)) -> [a] -> ([b], [c])
mapAndUnzip PmExpr -> (PmExpr, Bool)
simplifyPmExpr [PmExpr]
ts of
(ts' :: [PmExpr]
ts', bs :: [Bool]
bs) -> (ConLike -> [PmExpr] -> PmExpr
PmExprCon ConLike
c [PmExpr]
ts', [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
or [Bool]
bs)
PmExprEq t1 :: PmExpr
t1 t2 :: PmExpr
t2 -> PmExpr -> PmExpr -> (PmExpr, Bool)
simplifyEqExpr PmExpr
t1 PmExpr
t2
_other_expr :: PmExpr
_other_expr -> (PmExpr
e, Bool
False)
simplifyEqExpr :: PmExpr -> PmExpr -> (PmExpr, Bool)
simplifyEqExpr :: PmExpr -> PmExpr -> (PmExpr, Bool)
simplifyEqExpr e1 :: PmExpr
e1 e2 :: PmExpr
e2 = case (PmExpr
e1, PmExpr
e2) of
(PmExprVar x :: Name
x, PmExprVar y :: Name
y)
| Name
x Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
== Name
y -> (PmExpr
truePmExpr, Bool
True)
(PmExprLit l1 :: PmLit
l1, PmExprLit l2 :: PmLit
l2) -> case PmLit -> PmLit -> Bool
eqPmLit PmLit
l1 PmLit
l2 of
True -> (PmExpr
truePmExpr, Bool
True)
False -> (PmExpr
falsePmExpr, Bool
True)
(PmExprEq {}, _) -> case (PmExpr -> (PmExpr, Bool)
simplifyPmExpr PmExpr
e1, PmExpr -> (PmExpr, Bool)
simplifyPmExpr PmExpr
e2) of
((e1' :: PmExpr
e1', True ), (e2' :: PmExpr
e2', _ )) -> PmExpr -> PmExpr -> (PmExpr, Bool)
simplifyEqExpr PmExpr
e1' PmExpr
e2'
((e1' :: PmExpr
e1', _ ), (e2' :: PmExpr
e2', True )) -> PmExpr -> PmExpr -> (PmExpr, Bool)
simplifyEqExpr PmExpr
e1' PmExpr
e2'
((e1' :: PmExpr
e1', False), (e2' :: PmExpr
e2', False)) -> (PmExpr -> PmExpr -> PmExpr
PmExprEq PmExpr
e1' PmExpr
e2', Bool
False)
(_, PmExprEq {}) -> case (PmExpr -> (PmExpr, Bool)
simplifyPmExpr PmExpr
e1, PmExpr -> (PmExpr, Bool)
simplifyPmExpr PmExpr
e2) of
((e1' :: PmExpr
e1', True ), (e2' :: PmExpr
e2', _ )) -> PmExpr -> PmExpr -> (PmExpr, Bool)
simplifyEqExpr PmExpr
e1' PmExpr
e2'
((e1' :: PmExpr
e1', _ ), (e2' :: PmExpr
e2', True )) -> PmExpr -> PmExpr -> (PmExpr, Bool)
simplifyEqExpr PmExpr
e1' PmExpr
e2'
((e1' :: PmExpr
e1', False), (e2' :: PmExpr
e2', False)) -> (PmExpr -> PmExpr -> PmExpr
PmExprEq PmExpr
e1' PmExpr
e2', Bool
False)
(PmExprCon c1 :: ConLike
c1 ts1 :: [PmExpr]
ts1, PmExprCon c2 :: ConLike
c2 ts2 :: [PmExpr]
ts2)
| ConLike
c1 ConLike -> ConLike -> Bool
forall a. Eq a => a -> a -> Bool
== ConLike
c2 ->
let (ts1' :: [PmExpr]
ts1', bs1 :: [Bool]
bs1) = (PmExpr -> (PmExpr, Bool)) -> [PmExpr] -> ([PmExpr], [Bool])
forall a b c. (a -> (b, c)) -> [a] -> ([b], [c])
mapAndUnzip PmExpr -> (PmExpr, Bool)
simplifyPmExpr [PmExpr]
ts1
(ts2' :: [PmExpr]
ts2', bs2 :: [Bool]
bs2) = (PmExpr -> (PmExpr, Bool)) -> [PmExpr] -> ([PmExpr], [Bool])
forall a b c. (a -> (b, c)) -> [a] -> ([b], [c])
mapAndUnzip PmExpr -> (PmExpr, Bool)
simplifyPmExpr [PmExpr]
ts2
(tss :: [PmExpr]
tss, _bss :: [Bool]
_bss) = (PmExpr -> PmExpr -> (PmExpr, Bool))
-> [PmExpr] -> [PmExpr] -> ([PmExpr], [Bool])
forall a b c d. (a -> b -> (c, d)) -> [a] -> [b] -> ([c], [d])
zipWithAndUnzip PmExpr -> PmExpr -> (PmExpr, Bool)
simplifyEqExpr [PmExpr]
ts1' [PmExpr]
ts2'
worst_case :: PmExpr
worst_case = PmExpr -> PmExpr -> PmExpr
PmExprEq (ConLike -> [PmExpr] -> PmExpr
PmExprCon ConLike
c1 [PmExpr]
ts1') (ConLike -> [PmExpr] -> PmExpr
PmExprCon ConLike
c2 [PmExpr]
ts2')
in if | Bool -> Bool
not ([Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
or [Bool]
bs1 Bool -> Bool -> Bool
|| [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
or [Bool]
bs2) -> (PmExpr
worst_case, Bool
False)
| (PmExpr -> Bool) -> [PmExpr] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all PmExpr -> Bool
isTruePmExpr [PmExpr]
tss -> (PmExpr
truePmExpr, Bool
True)
| (PmExpr -> Bool) -> [PmExpr] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any PmExpr -> Bool
isFalsePmExpr [PmExpr]
tss -> (PmExpr
falsePmExpr, Bool
True)
| Bool
otherwise -> (PmExpr
worst_case, Bool
False)
| Bool
otherwise -> (PmExpr
falsePmExpr, Bool
True)
_other_equality :: ComplexEq
_other_equality -> (PmExpr
original, Bool
False)
where
original :: PmExpr
original = PmExpr -> PmExpr -> PmExpr
PmExprEq PmExpr
e1 PmExpr
e2
applySubstComplexEq :: PmVarEnv -> ComplexEq -> ComplexEq
applySubstComplexEq :: PmVarEnv -> ComplexEq -> ComplexEq
applySubstComplexEq env :: PmVarEnv
env (e1 :: PmExpr
e1,e2 :: PmExpr
e2) = (PmVarEnv -> PmExpr -> PmExpr
exprDeepLookup PmVarEnv
env PmExpr
e1, PmVarEnv -> PmExpr -> PmExpr
exprDeepLookup PmVarEnv
env PmExpr
e2)
varDeepLookup :: PmVarEnv -> Name -> PmExpr
varDeepLookup :: PmVarEnv -> Name -> PmExpr
varDeepLookup env :: PmVarEnv
env x :: Name
x
| Just e :: PmExpr
e <- PmVarEnv -> Name -> Maybe PmExpr
forall a. NameEnv a -> Name -> Maybe a
lookupNameEnv PmVarEnv
env Name
x = PmVarEnv -> PmExpr -> PmExpr
exprDeepLookup PmVarEnv
env PmExpr
e
| Bool
otherwise = Name -> PmExpr
PmExprVar Name
x
{-# INLINE varDeepLookup #-}
exprDeepLookup :: PmVarEnv -> PmExpr -> PmExpr
exprDeepLookup :: PmVarEnv -> PmExpr -> PmExpr
exprDeepLookup env :: PmVarEnv
env (PmExprVar x :: Name
x) = PmVarEnv -> Name -> PmExpr
varDeepLookup PmVarEnv
env Name
x
exprDeepLookup env :: PmVarEnv
env (PmExprCon c :: ConLike
c es :: [PmExpr]
es) = ConLike -> [PmExpr] -> PmExpr
PmExprCon ConLike
c ((PmExpr -> PmExpr) -> [PmExpr] -> [PmExpr]
forall a b. (a -> b) -> [a] -> [b]
map (PmVarEnv -> PmExpr -> PmExpr
exprDeepLookup PmVarEnv
env) [PmExpr]
es)
exprDeepLookup env :: PmVarEnv
env (PmExprEq e1 :: PmExpr
e1 e2 :: PmExpr
e2) = PmExpr -> PmExpr -> PmExpr
PmExprEq (PmVarEnv -> PmExpr -> PmExpr
exprDeepLookup PmVarEnv
env PmExpr
e1)
(PmVarEnv -> PmExpr -> PmExpr
exprDeepLookup PmVarEnv
env PmExpr
e2)
exprDeepLookup _ other_expr :: PmExpr
other_expr = PmExpr
other_expr
tmOracle :: TmState -> [ComplexEq] -> Maybe TmState
tmOracle :: TmState -> [ComplexEq] -> Maybe TmState
tmOracle tm_state :: TmState
tm_state eqs :: [ComplexEq]
eqs = (TmState -> ComplexEq -> Maybe TmState)
-> TmState -> [ComplexEq] -> Maybe TmState
forall (m :: * -> *) a b.
Monad m =>
(a -> b -> m a) -> a -> [b] -> m a
foldlM TmState -> ComplexEq -> Maybe TmState
solveOneEq TmState
tm_state [ComplexEq]
eqs
pmLitType :: PmLit -> Type
pmLitType :: PmLit -> Type
pmLitType (PmSLit lit :: HsLit GhcTc
lit) = HsLit GhcTc -> Type
forall (p :: Pass). HsLit (GhcPass p) -> Type
hsLitType HsLit GhcTc
lit
pmLitType (PmOLit _ lit :: HsOverLit GhcTc
lit) = HsOverLit GhcTc -> Type
overLitType HsOverLit GhcTc
lit