@@ -693,6 +693,13 @@ data CTE v s
693
693
pattern ST1 :: Direction Word16 -> v -> Mem -> s -> CTE v s
694
694
pattern ST1 d v m s = ST d [v] [m] s
695
695
696
+ -- All variables, both bound and free occurring in a CTE. This is
697
+ -- useful for avoiding both free and bound variables when
698
+ -- freshening.
699
+ cteVars :: (Ord v ) => Cte v -> Set v
700
+ cteVars (ST _ vs _ e) = Set. fromList vs `Set.union` ABTN. freeVars e
701
+ cteVars (LZ v r as) = Set. fromList (either (const id ) (:) r $ v : as)
702
+
696
703
data ANormalF v e
697
704
= ALet (Direction Word16 ) [Mem ] e e
698
705
| AName (Either Reference v ) [v ] e
@@ -1706,8 +1713,16 @@ tru = TCon Ty.booleanRef 1 []
1706
1713
-- binding during ANF translation. Renames a variable in a
1707
1714
-- context, and returns an indication of whether the varible
1708
1715
-- was shadowed by one of the context bindings.
1716
+ --
1717
+ -- Note: this assumes that `u` is not bound by any of the context
1718
+ -- entries, as no effort is made to rename them to avoid capturing
1719
+ -- `u`.
1709
1720
renameCtx :: (Var v ) => v -> v -> Ctx v -> (Ctx v , Bool )
1710
- renameCtx v u (d, ctx) | (ctx, b) <- rn [] ctx = ((d, ctx), b)
1721
+ renameCtx v u (d, ctx) | (ctx, b) <- renameCtes v u ctx = ((d, ctx), b)
1722
+
1723
+ -- As above, but without the Direction.
1724
+ renameCtes :: (Var v ) => v -> v -> [Cte v ] -> ([Cte v ], Bool )
1725
+ renameCtes v u = rn []
1711
1726
where
1712
1727
swap w
1713
1728
| w == v = u
@@ -1725,7 +1740,92 @@ renameCtx v u (d, ctx) | (ctx, b) <- rn [] ctx = ((d, ctx), b)
1725
1740
where
1726
1741
e = LZ w (swap <$> f) (swap <$> as)
1727
1742
1728
- anfBlock :: (Var v ) => Term v a -> ANFM v (Ctx v , DNormal v )
1743
+ -- Simultaneously renames variables in a list of context entries.
1744
+ --
1745
+ -- Assumes that the variables being renamed to are not bound by the
1746
+ -- context entries, so that it is unnecessary to rename them.
1747
+ renamesCtes :: (Var v ) => Map v v -> [Cte v ] -> [Cte v ]
1748
+ renamesCtes rn = map f
1749
+ where
1750
+ swap w
1751
+ | Just u <- Map. lookup w rn = u
1752
+ | otherwise = w
1753
+
1754
+ f (ST d vs ccs b) = ST d vs ccs (ABTN. renames rn b)
1755
+ f (LZ v r as) = LZ v (second swap r) (map swap as)
1756
+
1757
+ -- Calculates the free variables occurring in a context. This
1758
+ -- consists of the free variables in the expressions being bound,
1759
+ -- but with previously bound variables subtracted.
1760
+ freeVarsCtx :: (Ord v ) => Ctx v -> Set v
1761
+ freeVarsCtx = freeVarsCte . snd
1762
+
1763
+ freeVarsCte :: (Ord v ) => [Cte v ] -> Set v
1764
+ freeVarsCte = foldr m Set. empty
1765
+ where
1766
+ m (ST _ vs _ bn) rest =
1767
+ ABTN. freeVars bn `Set.union` (rest Set. \\ Set. fromList vs)
1768
+ m (LZ v r as) rest =
1769
+ Set. fromList (either (const id ) (:) r as)
1770
+ `Set.union` Set. delete v rest
1771
+
1772
+ -- Conditionally freshens a list of variables. The predicate
1773
+ -- argument selects which variables to freshen, and the set is a set
1774
+ -- of variables to avoid for freshness. The process ensures that the
1775
+ -- result is mutually fresh, and returns a new set of variables to
1776
+ -- avoid, which includes the freshened variables.
1777
+ --
1778
+ -- Presumably any variables selected by the predicate should be
1779
+ -- included in the set, but the set may contain additional variables
1780
+ -- to avoid, when freshening.
1781
+ freshens :: (Var v ) => (v -> Bool ) -> Set v -> [v ] -> (Set v , [v ])
1782
+ freshens p avoid0 vs =
1783
+ mapAccumL f (Set. union avoid0 (Set. fromList vs)) vs
1784
+ where
1785
+ f avoid v
1786
+ | p v, u <- Var. freshIn avoid v = (Set. insert u avoid, u)
1787
+ | otherwise = (avoid, v)
1788
+
1789
+ -- Freshens the variable bindings in a context to avoid a set of
1790
+ -- variables. Returns the renaming necessary for anything that was
1791
+ -- bound in the freshened context.
1792
+ --
1793
+ -- Note: this only freshens if it's necessary to avoid variables in
1794
+ -- the _original_ set. We need to keep track of other variables to
1795
+ -- avoid when making up new names for those, but it it isn't
1796
+ -- necessary to freshen variables to remove shadowing _within_ the
1797
+ -- context, since it is presumably already correctly formed.
1798
+ freshenCtx :: (Var v ) => Set v -> Ctx v -> (Map v v , Ctx v )
1799
+ freshenCtx avoid0 (d, ctx) =
1800
+ case go lavoid Map. empty [] $ reverse ctx of
1801
+ (rn, ctx) -> (rn, (d, ctx))
1802
+ where
1803
+ -- precalculate all variable occurrences in the context to just
1804
+ -- completely avoid those as well.
1805
+ lavoid =
1806
+ foldl (flip $ Set. union . cteVars) avoid0 ctx
1807
+
1808
+ go _ rns fresh [] = (rns, fresh)
1809
+ go avoid rns fresh (bn : bns) = case bn of
1810
+ LZ v r as
1811
+ | v `Set.member` avoid0,
1812
+ u <- Var. freshIn avoid v,
1813
+ (fresh, _) <- renameCtes v u fresh,
1814
+ avoid <- Set. insert u avoid,
1815
+ rns <- Map. alter (Just . fromMaybe u) v rns ->
1816
+ go avoid rns (LZ u r as : fresh) bns
1817
+ ST d vs ccs expr
1818
+ | (avoid, us) <- freshens (`Set.member` avoid0) avoid vs,
1819
+ rn <- Map. fromList (filter (uncurry (/=) ) $ zip vs us),
1820
+ not (Map. null rn),
1821
+ fresh <- renamesCtes rn fresh,
1822
+ -- Note: rns union left-biased, so inner contexts take
1823
+ -- priority.
1824
+ rns <- Map. union rns rn ->
1825
+ go avoid rns (ST d us ccs expr : fresh) bns
1826
+ _ -> go avoid rns (bn : fresh) bns
1827
+
1828
+ anfBlock :: (Ord v , Var v ) => Term v a -> ANFM v (Ctx v , DNormal v )
1729
1829
anfBlock (Var' v) = pure (mempty , pure $ TVar v)
1730
1830
anfBlock (If' c t f) = do
1731
1831
(cctx, cc) <- anfBlock c
@@ -1875,14 +1975,24 @@ anfBlock (Let1Named' v b e) =
1875
1975
anfBlock b >>= \ case
1876
1976
(bctx, (Direct , TVar u)) -> do
1877
1977
(ectx, ce) <- anfBlock e
1978
+ (brn, bctx) <- fixupBctx bctx ectx ce
1979
+ u <- pure $ Map. findWithDefault u u brn
1878
1980
(ectx, shaded) <- pure $ renameCtx v u ectx
1879
1981
ce <- pure $ if shaded then ce else ABTN. rename v u <$> ce
1880
1982
pure (bctx <> ectx, ce)
1881
1983
(bctx, (d0, cb)) -> bindLocal [v] $ do
1882
1984
(ectx, ce) <- anfBlock e
1883
1985
d <- bindDirection d0
1986
+ (brn, bctx) <- fixupBctx bctx ectx ce
1987
+ cb <- pure $ ABTN. renames brn cb
1884
1988
let octx = bctx <> directed [ST1 d v BX cb] <> ectx
1885
1989
pure (octx, ce)
1990
+ where
1991
+ fixupBctx bctx ectx (_, ce) =
1992
+ pure $ freshenCtx (Set. union ecfvs efvs) bctx
1993
+ where
1994
+ ecfvs = freeVarsCtx ectx
1995
+ efvs = ABTN. freeVars ce
1886
1996
anfBlock (Apps' (Blank' b) args) = do
1887
1997
nm <- fresh
1888
1998
(actx, cas) <- anfArgs args
0 commit comments