Skip to content

Commit b9e6874

Browse files
committed
Fix a bug in dynamic distinctness check.
We just added an optimization to `refreshAbsPure` that dynamically checks whether the binders are already fresh wrt the scope and does nothing in that case. But the check wasn't strict enough. We checked that the names in the binders were distinct with respect to the scope, but we didn't check that they were distinct with respect to *each other*. To do the check correctly, we need envs and scopes to carry information about shadowed names. Roughly, we make envs and scopes behave like `Map Name [a]` instead of `Map Name a`.
1 parent a3d78d2 commit b9e6874

File tree

1 file changed

+36
-24
lines changed

1 file changed

+36
-24
lines changed

src/lib/Name.hs

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ instance (SinkableB b, BindsNames b) => OutFrag (Nest b) where
239239
updateSubstFrag :: Color c => Name c i -> v c o -> SubstFrag v VoidS i o
240240
-> SubstFrag v VoidS i o
241241
updateSubstFrag (UnsafeMakeName v) rhs (UnsafeMakeSubst m) =
242-
UnsafeMakeSubst $ M.insert v (WithColor rhs) m
242+
UnsafeMakeSubst $ M.adjust (\(_:rest) -> (WithColor rhs) : rest ) v m
243243

244244
-- === monadic type classes for reading and extending envs and scopes ===
245245

@@ -783,14 +783,17 @@ refreshAbsPure scope (Abs b e) cont =
783783

784784
extendIfDistinct :: Scope n -> ScopeFrag n l
785785
-> Maybe (DistinctEvidence l, Scope l)
786-
extendIfDistinct scope frag =
787-
if M.disjoint scopeNames extNames
786+
extendIfDistinct scope frag = do
787+
if all isUnique extNames && M.disjoint scopeNames extNames
788788
then Just ( fabricateDistinctEvidence
789789
, Scope (UnsafeMakeScopeFrag (extNames <> scopeNames)))
790790
else Nothing
791791
where
792792
Scope (UnsafeMakeScopeFrag scopeNames) = scope
793793
UnsafeMakeScopeFrag extNames = frag
794+
isUnique :: [a] -> Bool
795+
isUnique [_] = True
796+
isUnique _ = False
794797

795798
-- === versions of monad constraints with scope params ===
796799

@@ -1143,7 +1146,7 @@ instance (HoistableE e, AlphaEqE e) => Eq (EKey e n) where
11431146
if M.keysSet (freeVarsE y) /= M.keysSet (xFreeVars)
11441147
then False
11451148
else do
1146-
let scope = (Scope $ UnsafeMakeScopeFrag $ xFreeVars) :: Scope UnsafeS
1149+
let scope = (Scope $ UnsafeMakeScopeFrag $ M.map (:[]) xFreeVars) :: Scope UnsafeS
11471150
withDistinctEvidence (fabricateDistinctEvidence :: DistinctEvidence UnsafeS) do
11481151
runScopeReaderM scope do
11491152
alphaEq (unsafeCoerceE x) (unsafeCoerceE y)
@@ -2159,18 +2162,23 @@ type B = S -> S -> * -- binder-y things, covariant in the first param and
21592162
type V = C -> E -- value-y things that we might look up in an environment
21602163
-- with a `Name c n`, parameterized by the name's color.
21612164

2162-
type NameSet (n::S) = M.Map RawName (WithColor UnitV UnsafeS)
2165+
type ColorRep = WithColor UnitV UnsafeS
2166+
type NameSet (n::S) = M.Map RawName ColorRep
21632167

2164-
newtype ScopeFrag (n::S) (l::S) = UnsafeMakeScopeFrag (NameSet UnsafeS) deriving Generic
2168+
newtype ScopeFrag (n::S) (l::S) = UnsafeMakeScopeFrag (M.Map RawName [ColorRep]) deriving Generic
21652169
newtype Scope (n::S) = Scope { fromScope :: ScopeFrag VoidS n } deriving Generic
21662170

21672171
instance Category ScopeFrag where
21682172
id = UnsafeMakeScopeFrag mempty
2169-
UnsafeMakeScopeFrag s2 . UnsafeMakeScopeFrag s1 = UnsafeMakeScopeFrag $ s1 <> s2
2173+
UnsafeMakeScopeFrag s2 . UnsafeMakeScopeFrag s1 =
2174+
-- Flipped because the innermost names are at the left (head) of the list.
2175+
-- But also flipped the other way because `(.)` is not like `(>>>)`.
2176+
-- Hope we got that right!
2177+
UnsafeMakeScopeFrag $ M.unionWith (++) s2 s1
21702178

21712179
instance Color c => BindsNames (NameBinder c) where
21722180
toScopeFrag (UnsafeMakeBinder v) =
2173-
UnsafeMakeScopeFrag (M.singleton v $ WithColor (UnitV :: UnitV c UnsafeS))
2181+
UnsafeMakeScopeFrag $ M.singleton v [WithColor (UnitV :: UnitV c UnsafeS)]
21742182

21752183
absurdNameFunction :: Name v VoidS -> a
21762184
absurdNameFunction _ = error "Void names shouldn't exist"
@@ -2422,7 +2430,7 @@ ignoreHoistFailure (HoistFailure _) = error "hoist failure"
24222430

24232431
hoist :: (BindsNames b, HoistableE e) => b n l -> e l -> HoistExcept (e n)
24242432
hoist b e =
2425-
case nameSetRawNames $ M.intersection frag (freeVarsE e) of
2433+
case nameSetRawNames $ M.intersection (freeVarsE e) frag of
24262434
[] -> HoistSuccess $ unsafeCoerceE e
24272435
leakedNames -> HoistFailure leakedNames
24282436
where UnsafeMakeScopeFrag frag = toScopeFrag b
@@ -2447,7 +2455,7 @@ nameSetToList nameSet =
24472455
Just (ConstE UnitE :: UnitV c UnsafeS)-> Just $ UnsafeMakeName rawName
24482456

24492457
toNameSet :: ScopeFrag n l -> NameSet l
2450-
toNameSet (UnsafeMakeScopeFrag s) = s
2458+
toNameSet (UnsafeMakeScopeFrag s) = M.map head s
24512459

24522460
nameSetRawNames :: NameSet n -> [RawName]
24532461
nameSetRawNames m = M.keys m
@@ -2464,13 +2472,14 @@ exchangeBs :: (Distinct l, BindsNames b1, SinkableB b1, HoistableB b2)
24642472
=> PairB b1 b2 n l
24652473
-> HoistExcept (PairB b2 b1 n l)
24662474
exchangeBs (PairB b1 b2) =
2467-
case nameSetRawNames $ M.intersection frag (freeVarsB b2) of
2475+
case nameSetRawNames $ M.intersection (freeVarsB b2) frag of
24682476
[] -> HoistSuccess $ PairB (unsafeCoerceB b2) (unsafeCoerceB b1)
24692477
leakedNames -> HoistFailure leakedNames
24702478
where UnsafeMakeScopeFrag frag = toScopeFrag b1
24712479

24722480
hoistNameSet :: BindsNames b => b n l -> NameSet l -> NameSet n
2473-
hoistNameSet b nameSet = unsafeCoerceNameSet $ nameSet `M.difference` frag
2481+
hoistNameSet b nameSet =
2482+
unsafeCoerceNameSet $ nameSet `M.difference` frag
24742483
where UnsafeMakeScopeFrag frag = toScopeFrag b
24752484

24762485
abstractFreeVar :: Name c n -> e n -> Abs (NameBinder c) e n
@@ -2525,7 +2534,7 @@ data SubstFrag
25252534
(i ::S) -- starting scope parameter for names we can look up in this env
25262535
(i'::S) -- ending scope parameter for names we can look up in this env
25272536
(o ::S) -- scope parameter for the values stored in the env
2528-
= UnsafeMakeSubst (M.Map RawName (WithColor v o))
2537+
= UnsafeMakeSubst (M.Map RawName [WithColor v o])
25292538
deriving (Generic)
25302539
deriving instance (forall c. Show (v c o)) => Show (SubstFrag v i i' o)
25312540

@@ -2534,34 +2543,37 @@ deriving instance (forall c. Show (v c o)) => Show (SubstFrag v i i' o)
25342543
lookupSubstFrag :: Color c => SubstFrag v i i' o -> Name c (i:=>:i') -> v c o
25352544
lookupSubstFrag (UnsafeMakeSubst m) (UnsafeMakeName rawName) =
25362545
case M.lookup rawName m of
2537-
Nothing -> error "Subst lookup failed (this should never happen)"
2538-
Just d -> case fromWithColor d of
2546+
Just (d:_) -> case fromWithColor d of
25392547
Nothing -> error "Wrong name color (should never happen)"
25402548
Just x -> x
2549+
_ -> error "Subst lookup failed (this should never happen)"
25412550

25422551
-- Just for debugging
25432552
lookupSubstFragRaw :: SubstFrag v i i' o -> RawName -> Maybe (WithColor v o)
2544-
lookupSubstFragRaw (UnsafeMakeSubst m) rawName = M.lookup rawName m
2553+
lookupSubstFragRaw (UnsafeMakeSubst m) rawName = fmap head $ M.lookup rawName m
25452554

25462555
instance InFrag (SubstFrag v) where
25472556
emptyInFrag = UnsafeMakeSubst mempty
25482557
catInFrags (UnsafeMakeSubst m1) (UnsafeMakeSubst m2) =
2549-
UnsafeMakeSubst (m2 <> m1) -- flipped because Data.Map uses a left-biased `<>`
2558+
-- flipped because the innermost names are at the left (head) of the list
2559+
UnsafeMakeSubst (M.unionWith (++) m2 m1)
25502560

25512561
singletonSubst :: Color c => NameBinder c i i' -> v c o -> SubstFrag v i i' o
25522562
singletonSubst (UnsafeMakeBinder name) x =
2553-
UnsafeMakeSubst (M.singleton name $ WithColor x)
2563+
UnsafeMakeSubst (M.singleton name [WithColor x])
25542564

25552565
fmapSubstFrag :: SinkableV v
25562566
=> (forall c. Color c => Name c (i:=>:i') -> v c o -> v' c o')
25572567
-> SubstFrag v i i' o -> SubstFrag v' i i' o'
25582568
fmapSubstFrag f (UnsafeMakeSubst m) = UnsafeMakeSubst m'
2559-
where m' = flip M.mapWithKey m \k (WithColor val) ->
2560-
WithColor $ f (UnsafeMakeName k) val
2569+
where m' = flip M.mapWithKey m $ \k xs ->
2570+
flip map xs \(WithColor val) ->
2571+
WithColor $ f (UnsafeMakeName k) val
25612572

25622573
envFragAsScope :: forall v i i' o. SubstFrag v i i' o -> ScopeFrag i i'
2563-
envFragAsScope (UnsafeMakeSubst m) = UnsafeMakeScopeFrag $
2564-
fmap (\(WithColor (_ :: v c o)) -> WithColor (UnitV :: UnitV c UnsafeS)) m
2574+
envFragAsScope (UnsafeMakeSubst m) =
2575+
UnsafeMakeScopeFrag $ flip fmap m \xs ->
2576+
flip map xs \(WithColor (_ :: v c o)) -> WithColor (UnitV :: UnitV c UnsafeS)
25652577

25662578
-- === iterating through env pairs ===
25672579

@@ -2570,7 +2582,7 @@ data SubstPair (v::V) (o::S) (i::S) (i'::S) where
25702582

25712583
toSubstPairs :: forall v i i' o . SubstFrag v i i' o -> Nest (SubstPair v o) i i'
25722584
toSubstPairs (UnsafeMakeSubst m) =
2573-
go $ M.elems $ M.mapWithKey mkPair m
2585+
go $ fold $ M.elems $ flip M.mapWithKey m \k xs -> map (mkPair k) xs
25742586
where
25752587
mkPair :: RawName -> WithColor v o -> SubstPair v o UnsafeS UnsafeS
25762588
mkPair rawName (WithColor v) =
@@ -2644,7 +2656,7 @@ instance HoistableB b => HoistableB (Nest b) where
26442656
instance (forall c n. Pretty (v c n)) => Pretty (SubstFrag v i i' o) where
26452657
pretty (UnsafeMakeSubst m) =
26462658
fold [ pretty v <+> "@>" <+> pretty x <> hardline
2647-
| (v, WithColor x) <- M.toList m ]
2659+
| (v, xs) <- M.toList m, WithColor x <- reverse xs]
26482660

26492661
instance (Generic (b UnsafeS UnsafeS)) => Generic (Nest b n l) where
26502662
type Rep (Nest b n l) = Rep [b UnsafeS UnsafeS]

0 commit comments

Comments
 (0)