futhark-0.22.2: src/Language/Futhark/FreeVars.hs
-- | Facilities for computing free term variables in various syntactic
-- constructs.
module Language.Futhark.FreeVars
( freeInExp,
freeInPat,
freeInType,
freeWithout,
FV (..),
)
where
import Data.Map.Strict qualified as M
import Data.Set qualified as S
import Language.Futhark.Prop
import Language.Futhark.Syntax
-- | A set of names where we also track their type.
newtype FV = FV {unFV :: M.Map VName StructType}
deriving (Show)
instance Semigroup FV where
FV x <> FV y = FV $ M.unionWith max x y
instance Monoid FV where
mempty = FV mempty
-- | Set subtraction. Do not consider those variables as free.
freeWithout :: FV -> S.Set VName -> FV
freeWithout (FV x) y = FV $ M.filterWithKey keep x
where
keep k _ = k `S.notMember` y
ident :: IdentBase Info VName -> FV
ident v = FV $ M.singleton (identName v) (toStruct $ unInfo (identType v))
size :: VName -> FV
size v = FV $ M.singleton v $ Scalar $ Prim $ Signed Int64
-- | A 'FV' with these names, considered to be sizes.
sizes :: S.Set VName -> FV
sizes = foldMap size
-- | Compute the set of free variables of an expression.
freeInExp :: ExpBase Info VName -> FV
freeInExp expr = case expr of
Literal {} -> mempty
IntLit {} -> mempty
FloatLit {} -> mempty
StringLit {} -> mempty
Hole {} -> mempty
Parens e _ -> freeInExp e
QualParens _ e _ -> freeInExp e
TupLit es _ -> foldMap freeInExp es
RecordLit fs _ -> foldMap freeInExpField fs
where
freeInExpField (RecordFieldExplicit _ e _) = freeInExp e
freeInExpField (RecordFieldImplicit vn t _) = ident $ Ident vn t mempty
ArrayLit es t _ ->
foldMap freeInExp es <> sizes (freeInType $ unInfo t)
AppExp (Range e me incl _) _ ->
freeInExp e <> foldMap freeInExp me <> foldMap freeInExp incl
Var qn (Info t) _ -> FV $ M.singleton (qualLeaf qn) $ toStruct t
Ascript e _ _ -> freeInExp e
AppExp (Coerce e _ _) (Info ar) ->
freeInExp e <> sizes (freeInType (appResType ar))
AppExp (LetPat let_sizes pat e1 e2 _) _ ->
freeInExp e1
<> ( (sizes (freeInPat pat) <> freeInExp e2)
`freeWithout` (patNames pat <> S.fromList (map sizeName let_sizes))
)
AppExp (LetFun vn (tparams, pats, _, _, e1) e2 _) _ ->
( (freeInExp e1 <> sizes (foldMap freeInPat pats))
`freeWithout` ( foldMap patNames pats
<> S.fromList (map typeParamName tparams)
)
)
<> (freeInExp e2 `freeWithout` S.singleton vn)
AppExp (If e1 e2 e3 _) _ -> freeInExp e1 <> freeInExp e2 <> freeInExp e3
AppExp (Apply e1 e2 _ _) _ -> freeInExp e1 <> freeInExp e2
Negate e _ -> freeInExp e
Not e _ -> freeInExp e
Lambda pats e0 _ (Info (_, RetType dims t)) _ ->
(sizes (foldMap freeInPat pats) <> freeInExp e0 <> sizes (freeInType t))
`freeWithout` (foldMap patNames pats <> S.fromList dims)
OpSection {} -> mempty
OpSectionLeft _ _ e _ _ _ -> freeInExp e
OpSectionRight _ _ e _ _ _ -> freeInExp e
ProjectSection {} -> mempty
IndexSection idxs _ _ -> foldMap freeInDimIndex idxs
AppExp (DoLoop sparams pat e1 form e3 _) _ ->
let (e2fv, e2ident) = formVars form
in freeInExp e1
<> ( (e2fv <> freeInExp e3)
`freeWithout` (S.fromList sparams <> patNames pat <> e2ident)
)
where
formVars (For v e2) = (freeInExp e2, S.singleton $ identName v)
formVars (ForIn p e2) = (freeInExp e2, patNames p)
formVars (While e2) = (freeInExp e2, mempty)
AppExp (BinOp (qn, _) (Info qn_t) (e1, _) (e2, _) _) _ ->
FV (M.singleton (qualLeaf qn) $ toStruct qn_t)
<> freeInExp e1
<> freeInExp e2
Project _ e _ _ -> freeInExp e
AppExp (LetWith id1 id2 idxs e1 e2 _) _ ->
ident id2
<> foldMap freeInDimIndex idxs
<> freeInExp e1
<> (freeInExp e2 `freeWithout` S.singleton (identName id1))
AppExp (Index e idxs _) _ -> freeInExp e <> foldMap freeInDimIndex idxs
Update e1 idxs e2 _ -> freeInExp e1 <> foldMap freeInDimIndex idxs <> freeInExp e2
RecordUpdate e1 _ e2 _ _ -> freeInExp e1 <> freeInExp e2
Assert e1 e2 _ _ -> freeInExp e1 <> freeInExp e2
Constr _ es _ _ -> foldMap freeInExp es
Attr _ e _ -> freeInExp e
AppExp (Match e cs _) _ -> freeInExp e <> foldMap caseFV cs
where
caseFV (CasePat p eCase _) =
(sizes (freeInPat p) <> freeInExp eCase)
`freeWithout` patNames p
freeInDimIndex :: DimIndexBase Info VName -> FV
freeInDimIndex (DimFix e) = freeInExp e
freeInDimIndex (DimSlice me1 me2 me3) =
foldMap (foldMap freeInExp) [me1, me2, me3]
-- | Free variables in pattern (including types of the bound identifiers).
freeInPat :: PatBase Info VName -> S.Set VName
freeInPat (TuplePat ps _) = foldMap freeInPat ps
freeInPat (RecordPat fs _) = foldMap (freeInPat . snd) fs
freeInPat (PatParens p _) = freeInPat p
freeInPat (Id _ (Info tp) _) = freeInType tp
freeInPat (Wildcard (Info tp) _) = freeInType tp
freeInPat (PatAscription p _ _) = freeInPat p
freeInPat (PatLit _ (Info tp) _) = freeInType tp
freeInPat (PatConstr _ _ ps _) = foldMap freeInPat ps
freeInPat (PatAttr _ p _) = freeInPat p
-- | Free variables in the type (meaning those that are used in size expression).
freeInType :: TypeBase Size as -> S.Set VName
freeInType t =
case t of
Array _ _ s a ->
freeInType (Scalar a) <> foldMap onSize (shapeDims s)
Scalar (Record fs) ->
foldMap freeInType fs
Scalar Prim {} ->
mempty
Scalar (Sum cs) ->
foldMap (foldMap freeInType) cs
Scalar (Arrow _ v t1 (RetType dims t2)) ->
S.filter (notV v) $ S.filter (`notElem` dims) $ freeInType t1 <> freeInType t2
Scalar (TypeVar _ _ _ targs) ->
foldMap typeArgDims targs
where
typeArgDims (TypeArgDim d _) = onSize d
typeArgDims (TypeArgType at _) = freeInType at
notV Unnamed = const True
notV (Named v) = (/= v)
onSize (NamedSize qn) = S.singleton $ qualLeaf qn
onSize _ = mempty