module Reader.InferType
( inferTypes
) where
import Prelude hiding
((!))
import Control.Arrow
( (>>>)
, (&&&)
)
import Control.Monad
( (>=>)
, foldM
)
import Utils
( imLookup
)
import Data.Graph
( Graph
, buildG
, transposeG
, topSort
)
import qualified Data.Set as S
( fromList
, toList
, insert
, intersection
, difference
)
import Data.Enum
( EnumDefinition(..)
)
import Data.Types
( IdType(..)
, SignalType(..)
, SignalDecType(..)
)
import Data.Binding
( Binding
, BindExpr(..)
)
import Data.Expression
( Expr(..)
, Expr'(..)
, ExprPos
)
import Reader.Data
( TypeTable
, ExpressionTable
, ArgumentTable
, Specification(..)
)
import Reader.Error
( Error
, errExpect
, errRange
, errPattern
, errNoPFuns
, errArgArity
, errNoHigher
, errEquality
, errInfinite
)
import Data.Maybe
( fromJust
)
import Data.Either
( partitionEithers
)
import Control.Monad.State
( StateT(..)
, execStateT
, get
, put
, liftM
, when
, unless
)
import Control.Exception
( assert
)
import qualified Data.IntMap.Strict as IM
( map
)
import Data.IntMap.Strict
( IntMap
, (!)
, insert
, fromList
, findMax
, mapWithKey
)
type TypeChecker a = a -> StateT ST (Either Error) ()
type TC a = StateT ST (Either Error) a
type ExprType = IdType
type ID = Int
type Expression = Expr ID
data ST = ST
{ tCount :: Int
, tTypes :: TypeTable
, targs :: ArgumentTable
, spec :: Specification
, curBinding :: ID
}
inferTypes
:: Specification -> Either Error Specification
inferTypes s@Specification{..} = do
let st = ST { tCount = (+1) $ fst $ findMax names
, tTypes = mapWithKey (flip $ const TPoly) names
, targs = arguments
, spec = s
, curBinding = 1
}
tt <- execStateT inferTypeSpec st
return $ s { types = tTypes tt }
depOrderedBindings
:: Specification -> [Either (BindExpr ID) (BindExpr ID)]
depOrderedBindings Specification{..} =
let
im =
fromList $
map (bIdent &&& Left) parameters ++
map (bIdent &&& Right) definitions
ps :: [ID]
ps = map bIdent parameters
ds :: [ID]
ds = map bIdent definitions
xs :: [ID]
xs = ps ++ ds
in
if null xs
then []
else
let
es :: [(ID, ID)]
es = concatMap (\x -> map (x,) $ deps xs x) xs
g :: Graph
g = buildG (minimum xs, maximum xs) es
in
map (im !) $
filter (`elem` xs) $
topSort $
transposeG g
where
deps
:: [Int] -> Int -> [Int]
deps xs x =
S.toList $
S.intersection
(S.fromList $ dependencies ! x)
(S.fromList xs)
inferTypeSpec
:: TC ()
inferTypeSpec = do
s@Specification{..} <- spec <$> get
mapM_ setEnumType enumerations
mapM_ (setSignalType STInput) inputs
mapM_ (setSignalType STOutput) outputs
mapM_ (updType TNumber . bIdent) parameters
mapM_ typeCheckBinding $ depOrderedBindings s
mapM_ typeCheckBusParameter inputs
mapM_ typeCheckBusParameter outputs
mapM_ (`typeCheck` TLtl) initially
mapM_ (`typeCheck` TLtl) preset
mapM_ (`typeCheck` TLtl) requirements
mapM_ (`typeCheck` TLtl) assumptions
mapM_ (`typeCheck` TLtl) invariants
mapM_ (`typeCheck` TLtl) guarantees
where
setSignalType
:: SignalType -> SignalDecType ID -> TC ()
setSignalType s = \case
SDSingle (x,_) -> updType (TSignal s) x
SDBus (x,_) _ -> updType (TBus s) x
SDEnum (x,_) (y,_) -> do
Specification{..} <- spec <$> get
updType (TTypedBus s (imLookup y names) y) x
setEnumType
:: EnumDefinition ID -> TC ()
setEnumType e = do
Specification{..} <- spec <$> get
mapM_
(updType (TEnum (imLookup (eName e) names) $ eName e)
. (\(y,_,_) -> y))
(eValues e)
typeCheckBinding
:: Either (BindExpr ID) (BindExpr ID) -> TC ()
typeCheckBinding = \case
Left x -> typeCheckParameter $ bIdent x
Right x -> typeCheckDefinition $ bIdent x
typeCheckParameter
:: ID -> TC ()
typeCheckParameter i = do
Specification{..} <- spec <$> get
let
n :: Int
n = length $ arguments ! i
if n <= 0
then typeCheck (bindings ! i) $ TSet TNumber
else errNoPFuns n $ positions ! i
typeCheckDefinition
:: ID -> TC ()
typeCheckDefinition i = do
setCur i
e <- ((! i) . bindings . spec) <$> get
check e 10
setCur (1)
where
setCur
:: Int -> TC ()
setCur c = do
st <- get
put st
{ curBinding = c
}
inferBinding
:: Expression -> TC ExprType
inferBinding e = inferFromExpr e >>= \case
TSet TBoolean -> inferFromBoolExpr e
t' -> return t'
check
:: Expression -> Int -> TC ()
check e n = do
TSet t <- inferBinding e
updType t i
typeCheck e $ TSet t
if n > 0
then check e (n1)
else do
TSet t' <- inferBinding e
when (t /= t') $ do
n <- ((! i) . names . spec) <$> get
p <- ((! i) . positions . spec) <$> get
errInfinite n p
typeCheckBusParameter
:: SignalDecType ID -> TC ()
typeCheckBusParameter = \case
SDBus _ e -> typeCheck e TNumber
_ -> return ()
typeCheck
:: Expression -> ExprType -> TC ()
typeCheck e = \case
TSignal x -> typeChIdF e $ TSignal x
TBus x -> typeChIdF e $ TBus x
TEnum t x -> typeChIdF e $ TEnum t x
TTypedBus x y z -> typeChIdF e $ TTypedBus x y z
TEmptySet -> case expr e of
SetExplicit [] -> return ()
SetExplicit (x:_) -> typeErrES e x
SetCup x y -> typeChck2 x y TEmptySet
SetCap x y -> typeChck2 x y TEmptySet
SetMinus x y -> typeChck2 x y TEmptySet
SetRCup _ x -> typeCheck x TEmptySet
SetRCap _ x -> typeCheck x TEmptySet
_ -> typeChIdF e TEmptySet
TSet t -> case expr e of
SetExplicit xs -> typeChSEx t xs
SetRange x y z -> typeChSRg x y z
SetCup x y -> typeChck2 x y $ TSet t
SetRCup xs x -> typeChckO xs x $ TSet t
SetCap x y -> typeChck2 x y $ TSet t
SetRCap xs x -> typeChckO xs x $ TSet t
SetMinus x y -> typeChck2 x y $ TSet t
_ -> typeChIdF e $ TSet t
TNumber -> case expr e of
BaseCon {} -> return ()
NumSMin xs -> typeCheck xs $ TSet TNumber
NumSMax xs -> typeCheck xs $ TSet TNumber
NumSSize x -> typeChckS x
NumSizeOf b -> typeCheck b $ TBus STGeneric
NumPlus x y -> typeChck2 x y TNumber
NumRPlus xs x -> typeChckO xs x TNumber
NumMinus x y -> typeChck2 x y TNumber
NumMul x y -> typeChck2 x y TNumber
NumRMul xs x -> typeChckO xs x TNumber
NumDiv x y -> typeChck2 x y TNumber
NumMod x y -> typeChck2 x y TNumber
_ -> typeChIdF e TNumber
TBoolean -> case expr e of
BaseTrue -> return ()
BaseFalse -> return ()
BaseOtherwise -> return ()
Pattern x y -> typeChckP e
BlnElem x xs -> typeChElm x xs
BlnEQ x y -> typeChEqB x y
BlnNEQ x y -> typeChEqB x y
BlnGE x y -> typeChck2 x y TNumber
BlnGEQ x y -> typeChck2 x y TNumber
BlnLE x y -> typeChck2 x y TNumber
BlnLEQ x y -> typeChck2 x y TNumber
BlnNot x -> typeCheck x TBoolean
BlnOr x y -> typeChck2 x y TBoolean
BlnAnd x y -> typeChck2 x y TBoolean
BlnImpl x y -> typeChck2 x y TBoolean
BlnEquiv x y -> typeChck2 x y TBoolean
BlnROr xs x -> typeChckO xs x TBoolean
BlnRAnd xs x -> typeChckO xs x TBoolean
_ -> typeChIdF e TBoolean
TLtl -> case expr e of
BaseTrue -> return ()
BaseFalse -> return ()
BlnElem x xs -> typeChElm x xs
BlnEQ x y -> typeChEqL x y
BlnNEQ x y -> typeChEqL x y
BlnGE x y -> typeChck2 x y TNumber
BlnGEQ x y -> typeChck2 x y TNumber
BlnLE x y -> typeChck2 x y TNumber
BlnLEQ x y -> typeChck2 x y TNumber
BlnNot x -> typeCheck x TLtl
BlnOr x y -> typeChck2 x y TLtl
BlnAnd x y -> typeChck2 x y TLtl
BlnImpl x y -> typeChck2 x y TLtl
BlnEquiv x y -> typeChck2 x y TLtl
BlnROr xs x -> typeChckO xs x TLtl
BlnRAnd xs x -> typeChckO xs x TLtl
LtlNext x -> typeCheck x TLtl
LtlRNext x y -> typeChckR x y
LtlGlobally x -> typeCheck x TLtl
LtlRGlobally x y -> typeChckR x y
LtlFinally x -> typeCheck x TLtl
LtlRFinally x y -> typeChckR x y
LtlUntil x y -> typeChck2 x y TLtl
LtlWeak x y -> typeChck2 x y TLtl
LtlRelease x y -> typeChck2 x y TLtl
_ -> typeChIdF e TLtl
TPattern -> case expr e of
BaseTrue -> return ()
BaseFalse -> return ()
BaseWild -> return ()
BlnElem x xs -> typeChElm x xs
BlnEQ x y -> typeChck2 x y TNumber
BlnNEQ x y -> typeChck2 x y TNumber
BlnGE x y -> typeChck2 x y TNumber
BlnGEQ x y -> typeChck2 x y TNumber
BlnLE x y -> typeChck2 x y TNumber
BlnLEQ x y -> typeChck2 x y TNumber
BlnNot x -> typeCheck x TPattern
BlnOr x y -> typeChck2 x y TPattern
BlnAnd x y -> typeChck2 x y TPattern
BlnImpl x y -> typeChck2 x y TPattern
BlnEquiv x y -> typeChck2 x y TPattern
BlnROr xs x -> typeChckO xs x TPattern
BlnRAnd xs x -> typeChckO xs x TPattern
LtlNext x -> typeCheck x TPattern
LtlRNext x y -> typeChckU x y
LtlGlobally x -> typeCheck x TPattern
LtlRGlobally x y -> typeChckU x y
LtlFinally x -> typeCheck x TPattern
LtlRFinally x y -> typeChckU x y
LtlUntil x y -> typeChck2 x y TPattern
LtlWeak x y -> typeChck2 x y TPattern
LtlRelease x y -> typeChck2 x y TPattern
_ -> typeChIdF e TPattern
TPoly i -> inferFromExpr e >>= \case
TPoly j
| i == j -> typeChIdF e $ TPoly i
| otherwise -> equalPolyType i j >> inferFromExpr e >>= typeCheck e
t -> updatePolyType i t >> typeCheck e t
typeChIdF
:: Expression -> ExprType -> TC ()
typeChIdF e t = case expr e of
BaseId i -> typeCheckId t i $ srcPos e
BaseFml xs f -> typeCheckFml t xs f $ srcPos e
BaseBus x b -> typeCheckBus t x b $ srcPos e
Colon x y -> typeCheck x TBoolean >> typeCheck y t
x -> do
TSet t' <- inferFromExpr e
errExpect t t' $ srcPos e
typeCheckBus
:: ExprType -> Expression -> ID -> ExprPos -> TC ()
typeCheckBus t n b p = do
typeCheck n TNumber
((! b) . tTypes) <$> get >>= \case
TBus s' -> case t of
TSignal s -> case (s,s') of
(STInput, STOutput) -> errExpect t (TSignal s') p
(STOutput, STInput) -> errExpect t (TSignal s') p
_ -> return ()
TLtl -> return ()
_ -> errExpect t (TSignal s') p
TTypedBus s' _ _ -> case t of
TSignal s -> case (s,s') of
(STInput, STOutput) -> errExpect t (TSignal s') p
(STOutput, STInput) -> errExpect t (TSignal s') p
_ -> return ()
TLtl -> return ()
_ -> errExpect t (TSignal s') p
TPoly p -> updatePolyType p $ TBus STGeneric
t' -> errExpect t t' p
typeCheckId
:: ExprType -> Int -> ExprPos -> TC ()
typeCheckId t i p = do
as <- ((! i) . arguments . spec) <$> get
unless (null as) $ do
Specification{..} <- spec <$> get
errNoHigher (names ! i) p
tt <- tTypes <$> get
validTypes p i t (tt ! i)
validTypes
:: ExprPos -> Int -> ExprType -> ExprType
-> StateT ST (Either Error) ()
validTypes p i = vt
where
vt (TSignal STGeneric) (TSignal _) = return ()
vt (TSignal _) (TSignal STGeneric) = return ()
vt (TBus STGeneric) (TBus _) = return ()
vt (TBus _) (TBus STGeneric) = return ()
vt (TEnum m x) (TTypedBus _ n y) = vt (TEnum m x) $ TEnum n y
vt (TTypedBus _ m x) (TEnum n y) = vt (TEnum m x) $ TEnum n y
vt (TTypedBus _ m x) (TTypedBus _ n y) = vt (TEnum m x) $ TEnum n y
vt TEmptySet (TSet _) = return ()
vt (TSet s) TEmptySet = updType (TSet s) i
vt (TSet s) (TSet s') = vt s s'
vt TLtl TBoolean = return ()
vt TLtl (TSignal _) = return ()
vt (TPoly p') (TPoly p) = equalPolyType p p'
vt (TPoly _) _ = return ()
vt t (TPoly p) = updatePolyType p t
vt t t'
| t == t' = return ()
| otherwise = errExpect t t' p
typeCheckFml
:: ExprType -> [Expression] -> Int -> ExprPos -> TC ()
typeCheckFml t xs f p = do
pf <- ((! f) . positions . spec) <$> get
as <- ((! f) . arguments . spec) <$> get
tt <- tTypes <$> get
let at = map (tt !) as
when (length as /= length xs) $
errArgArity (show $ length xs) (length as) pf p
mapM_ (uncurry typeCheck) $ zip xs at
rt <- ((! f) . tTypes) <$> get
resetDependencies tt f
validTypes p f t rt
resetDependencies
:: TypeTable -> ID -> TC ()
resetDependencies tt x = do
i <- curBinding <$> get
as <- (S.fromList . (! x) . arguments . spec) <$> get
ds <- (S.fromList . (! x) . dependencies . spec) <$> get
if i == x
then
mapM_ (resetDependencies tt) $
S.toList $
S.difference ds $
S.insert x as
else do
resetType tt x
mapM_ (resetDependencies tt) $
filter (/= x) $ S.toList ds
resetType
:: TypeTable -> Int -> TC ()
resetType tt i = do
st@ST{..} <- get
put st { tTypes = insert i (tt ! i) tTypes }
updType
:: ExprType -> ID -> TC ()
updType t i = do
st@ST{..} <- get
put st { tTypes = insert i t tTypes }
equalPolyType
:: Int -> Int -> TC ()
equalPolyType n m = do
st@ST{..} <- get
put st { tTypes = IM.map upd tTypes }
where
upd = \case
TPoly x
| x == n || x == m -> TPoly $ min n m
| otherwise -> TPoly x
x -> x
updatePolyType
:: Int -> ExprType -> TC ()
updatePolyType n t = do
st@ST{..} <- get
put st { tTypes = IM.map upd tTypes }
where
upd = \case
TPoly x
| x == n -> t
| otherwise -> TPoly x
x -> x
typeChEqL
:: Expression -> Expression -> TC ()
typeChEqL x y = inferFromExpr x >>= \case
TNumber -> typeChck2 x y TNumber
TTypedBus s m i -> inferFromExpr y >>= \case
TEnum n j
| i == j -> return ()
| otherwise -> errExpect (TEnum m i) (TEnum n j) $ srcPos y
t -> errExpect (TEnum m i) t $ srcPos y
TEnum n j -> inferFromExpr y >>= \case
TTypedBus s m i
| i == j -> return ()
| otherwise -> errExpect
(TTypedBus STGeneric n j)
(TTypedBus STGeneric m i)
(srcPos y)
t -> errExpect (TTypedBus STGeneric n j) t $ srcPos y
TPoly p -> inferFromExpr y >>= \case
TNumber -> updatePolyType p TNumber
TEnum n j -> updatePolyType p (TTypedBus STGeneric n j)
TTypedBus _ n j -> updatePolyType p (TEnum n j)
TPoly p' -> equalPolyType p p'
t -> errEquality t $ srcPos y
t -> errEquality t $ srcPos x
typeChEqB
:: Expression -> Expression -> TC ()
typeChEqB x y = inferFromExpr x >>= \case
TNumber -> typeChck2 x y TNumber
TPoly p -> inferFromExpr y >>= \case
TNumber -> updatePolyType p TNumber
TPoly p'-> updatePolyType p TNumber >> updatePolyType p' TNumber
t -> errExpect TNumber t $ srcPos y
t -> errExpect TNumber t $ srcPos x
typeChck2
:: Expression -> Expression -> ExprType -> TC ()
typeChck2 x y t = do
typeCheck x t
typeCheck y t
typeChSEx
:: ExprType -> [Expression] -> TC ()
typeChSEx t =
mapM_ (`typeCheck` t)
typeChSRg
:: Expression -> Expression -> Expression -> TC ()
typeChSRg x y z = do
typeCheck x TNumber
typeCheck y TNumber
typeCheck z TNumber
typeChckS
:: Expression -> TC ()
typeChckS x =
inferFromExpr x >>= typeCheck x
typeChElm
:: Expression -> Expression -> TC ()
typeChElm x xs = do
inferFromExpr x >>= typeCheck x
inferFromExpr x >>= (typeCheck xs . TSet)
typeChckR
:: Expression -> Expression -> StateT ST (Either Error) ()
typeChckR e x = case expr e of
Colon n m -> do
typeCheck n TNumber
typeCheck m TNumber
typeCheck x TLtl
_ -> do
typeCheck e TNumber
typeCheck x TLtl
typeChckU
:: Expression -> Expression -> StateT ST (Either Error) ()
typeChckU e x = case expr e of
Colon n m -> do
typeCheck n TNumber
typeCheck m TNumber
typeCheck x TPattern
_ -> do
typeCheck e TNumber
typeCheck x TPattern
typeChckP
:: Expression -> StateT ST (Either Error) ()
typeChckP (expr -> Pattern x y) = do
typeCheck x TLtl
typeCheck y TPattern
typeChckO
:: [Expression] -> Expression -> ExprType -> StateT ST (Either Error) ()
typeChckO xs y t = do
mapM_ typeChckI xs
typeCheck y t
typeChckI
:: Expression -> StateT ST (Either Error) ()
typeChckI = expr >>> \case
BlnElem x xs -> typeChElm x xs
BlnLE (expr -> BlnLE x y) z -> typeChSRg x y z
BlnLE (expr -> BlnLEQ x y) z -> typeChSRg x y z
BlnLEQ (expr -> BlnLE x y) z -> typeChSRg x y z
BlnLEQ (expr -> BlnLEQ x y) z -> typeChSRg x y z
_ -> assert False undefined
typeErrES
:: Expression -> Expression -> StateT ST (Either Error) ()
typeErrES e x = do
t <- inferFromExpr x
typeCheck x t
errExpect TEmptySet (TSet t) $ srcPos e
typeChSBn
:: ExprType -> Expression -> Expression -> StateT ST (Either Error) ()
typeChSBn t x y = do
typeCheck x $ TSet t
typeCheck y $ TSet t
inferFromExpr
:: Expression -> StateT ST (Either Error) ExprType
inferFromExpr e = case expr e of
BaseCon {} -> return TNumber
NumSMin {} -> return TNumber
NumSMax {} -> return TNumber
NumSSize {} -> return TNumber
NumSizeOf {} -> return TNumber
NumPlus {} -> return TNumber
NumMinus {} -> return TNumber
NumMul {} -> return TNumber
NumDiv {} -> return TNumber
NumMod {} -> return TNumber
NumRPlus {} -> return TNumber
NumRMul {} -> return TNumber
BaseWild -> return TPattern
BaseOtherwise -> return TBoolean
Pattern {} -> return TBoolean
BaseTrue -> inferFromBoolExpr e
BaseFalse -> inferFromBoolExpr e
BlnEQ {} -> inferFromBoolExpr e
BlnNEQ {} -> inferFromBoolExpr e
BlnGE {} -> inferFromBoolExpr e
BlnGEQ {} -> inferFromBoolExpr e
BlnLE {} -> inferFromBoolExpr e
BlnLEQ {} -> inferFromBoolExpr e
BlnNot {} -> inferFromBoolExpr e
BlnOr {} -> inferFromBoolExpr e
BlnROr {} -> inferFromBoolExpr e
BlnAnd {} -> inferFromBoolExpr e
BlnRAnd {} -> inferFromBoolExpr e
BlnImpl {} -> inferFromBoolExpr e
BlnElem {} -> inferFromBoolExpr e
BlnEquiv {} -> inferFromBoolExpr e
BaseBus {} -> return TLtl
LtlNext {} -> return TLtl
LtlRNext {} -> return TLtl
LtlGlobally {} -> return TLtl
LtlRGlobally {} -> return TLtl
LtlFinally {} -> return TLtl
LtlRFinally {} -> return TLtl
LtlUntil {} -> return TLtl
LtlWeak {} -> return TLtl
LtlRelease {} -> return TLtl
SetRange {} -> return $ TSet TNumber
SetExplicit [] -> return TEmptySet
SetExplicit (x:_) -> TSet <$> inferFromExpr x
SetCup x y -> inferSetOp x y
SetCap x y -> inferSetOp x y
SetMinus x y -> inferSetOp x y
SetRCap _ x -> inferFromExpr x
SetRCup _ x -> inferFromExpr x
Colon _ x -> inferFromExpr x
BaseId i -> (imLookup i . tTypes) <$> get
BaseFml _ i -> (imLookup i . tTypes) <$> get
where
inferSetOp x y =
inferFromExpr x >>= \case
TEmptySet -> inferFromExpr y
t -> return t
inferFromBoolExpr
:: Expression -> StateT ST (Either Error) ExprType
inferFromBoolExpr e = case expr e of
SetExplicit xs -> inferFromBoolSet xs
SetCup x y -> inferFromBoolE2 x y
SetCap x y -> inferFromBoolE2 x y
SetMinus x y -> inferFromBoolE2 x y
BaseTrue -> return TBoolean
BaseFalse -> return TBoolean
BlnEQ x y -> inferFromEqExpr x y
BlnNEQ x y -> inferFromEqExpr x y
BlnGE {} -> return TBoolean
BlnGEQ {} -> return TBoolean
BlnLE {} -> return TBoolean
BlnLEQ {} -> return TBoolean
BlnElem {} -> return TBoolean
BlnNot x -> inferFromBoolExpr x
BlnOr x y -> inferFromBoolE2 x y
BlnROr _ x -> inferFromBoolExpr x
BlnAnd x y -> inferFromBoolE2 x y
BlnRAnd _ x -> inferFromBoolExpr x
BlnImpl x y -> inferFromBoolE2 x y
BlnEquiv x y -> inferFromBoolE2 x y
BaseId i -> inferFromBoolId i
BaseFml _ i -> inferFromBoolId i
_ -> inferFromExpr e >>= \case
TSignal _ -> return TLtl
TLtl -> return TLtl
_ -> return TBoolean
where
inferFromEqExpr
:: Expression -> Expression -> TC ExprType
inferFromEqExpr x y = inferFromExpr x >>= \case
TTypedBus {} -> return TLtl
TEnum {} -> return TLtl
TPoly p -> inferFromExpr y >>= \case
TTypedBus {} -> return TLtl
TEnum {} -> return TLtl
TPoly p' -> return TLtl
_ -> return TBoolean
_ -> return TBoolean
inferFromBoolId
:: ID -> TC ExprType
inferFromBoolId i =
(imLookup i . tTypes) <$> get >>= \case
TSignal _ -> return TLtl
TLtl -> return TLtl
_ -> return TBoolean
inferFromBoolE2
:: Expression -> Expression -> TC ExprType
inferFromBoolE2 x y =
inferFromBoolExpr x >>= \case
TBoolean -> inferFromBoolExpr y >>= \case
TSignal _ -> return TLtl
TLtl -> return TLtl
_ -> return TBoolean
TSet TBoolean -> inferFromBoolExpr y >>= \case
TSet (TSignal _) -> return $ TSet TLtl
TSet TLtl -> return $ TSet TLtl
_ -> return $ TSet TBoolean
TSignal {} -> return TLtl
TSet (TSignal _) -> return $ TSet TLtl
TLtl -> return TLtl
TSet TLtl -> return $ TSet TLtl
TSet _ -> return $ TSet TBoolean
_ -> return TBoolean
inferFromBoolSet
:: [Expression] -> TC ExprType
inferFromBoolSet =
fmap TSet . foldM inferFromBoolElement TBoolean
inferFromBoolElement
:: ExprType -> Expression -> TC ExprType
inferFromBoolElement = \case
TBoolean ->
inferFromBoolExpr >=> \case
TSignal _ -> return TLtl
TLtl -> return TLtl
_ -> return TBoolean
TSignal _ -> const $ return TLtl
TLtl -> const $ return TLtl
_ -> const $ return TBoolean