Skip to content

Commit e9d2a2a

Browse files
authored
Merge pull request #5562 from unisonweb/fix/pattern-capture
Fix a variable capture during pattern desugaring
2 parents dc49234 + 3862b58 commit e9d2a2a

File tree

2 files changed

+90
-20
lines changed

2 files changed

+90
-20
lines changed

unison-runtime/src/Unison/Runtime/Pattern.hs

+27-20
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import Data.Set qualified as Set
2525
import Unison.ABT
2626
( absChain',
2727
renames,
28-
visitPure,
28+
visit,
2929
pattern AbsN',
3030
)
3131
import Unison.Builtin.Decls (builtinDataDecls, builtinEffectDecls)
@@ -765,34 +765,41 @@ initialize ::
765765
PType ->
766766
Term v ->
767767
[MatchCase () (Term v)] ->
768-
(Maybe v, (v, PType), PatternMatrix v)
769-
initialize r sc cs =
770-
( lv,
771-
(sv, r),
772-
PM $ evalState (traverse (mkRow sv) cs) 1
773-
)
768+
State Word64 (Maybe v, (v, PType), PatternMatrix v)
769+
initialize r sc cs = do
770+
(lv, sv) <- vars
771+
rs <- traverse (mkRow sv) cs
772+
pure (lv, (sv, r), PM rs)
774773
where
775-
(lv, sv)
776-
| Var' v <- sc = (Nothing, v)
777-
| pv <- freshenId 0 $ typed Pattern =
778-
(Just pv, pv)
774+
vars
775+
| Var' v <- sc = pure (Nothing, v)
776+
| otherwise = mkVars <$> grabId
777+
mkVars n = (Just pv, pv)
778+
where
779+
pv = freshenId n $ typed Pattern
780+
781+
grabId :: State Word64 Word64
782+
grabId = state $ \n -> (n, n+1)
779783

780784
splitPatterns :: (Var v) => DataSpec -> Term v -> Term v
781-
splitPatterns spec0 = visitPure $ \case
785+
splitPatterns spec0 tm = evalState (splitPatterns0 spec tm) 0
786+
where
787+
spec = Map.insert Rf.booleanRef (Right [0, 0]) spec0
788+
789+
splitPatterns0 :: (Var v) => DataSpec -> Term v -> State Word64 (Term v)
790+
splitPatterns0 spec = visit $ \case
782791
Match' sc0 cs0
783-
| ty <- determineType $ p <$> cs0,
784-
(lv, scrut, pm) <- initialize ty sc cs,
785-
body <- compile spec (uncurry Map.singleton scrut) pm ->
786-
Just $ case lv of
792+
| ty <- determineType $ p <$> cs0 -> Just $ do
793+
sc <- splitPatterns0 spec sc0
794+
cs <- (traverse . traverse) (splitPatterns0 spec) cs0
795+
(lv, scrut, pm) <- initialize ty sc cs
796+
let body = compile spec (uncurry Map.singleton scrut) pm
797+
pure $ case lv of
787798
Just v -> let1 False [(((), v), sc)] body
788799
_ -> body
789-
where
790-
sc = splitPatterns spec sc0
791-
cs = fmap (splitPatterns spec) <$> cs0
792800
_ -> Nothing
793801
where
794802
p (MatchCase pp _ _) = pp
795-
spec = Map.insert Rf.booleanRef (Right [0, 0]) spec0
796803

797804
builtinCase :: Set Reference
798805
builtinCase =
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
``` ucm :hide
2+
scratch/main> builtins.merge
3+
```
4+
5+
Checks a case that was resulting in variable capture when compiling
6+
pattern matching. `y` was evidently getting captured by the variable
7+
introduced for `confuser decoy`
8+
9+
``` unison
10+
type NatBox = NatBox Nat
11+
type Decoy a = { confuser : Tres }
12+
13+
type Tres = One | Two | Three
14+
15+
xyzzy : NatBox -> Decoy a -> Nat
16+
xyzzy box decoy =
17+
(NatBox y) = box
18+
(natty) = -- Note that these parentheses are required
19+
match confuser decoy with
20+
Tres.One -> y
21+
Two -> y + 1
22+
Three -> 11
23+
natty
24+
25+
> xyzzy (NatBox 1) (Decoy One)
26+
> xyzzy (NatBox 1) (Decoy Two)
27+
> xyzzy (NatBox 1) (Decoy Three)
28+
```
29+
30+
``` ucm :added-by-ucm
31+
Loading changes detected in scratch.u.
32+
33+
I found and typechecked these definitions in scratch.u. If you
34+
do an `add` or `update`, here's how your codebase would
35+
change:
36+
37+
⍟ These new definitions are ok to `add`:
38+
39+
type Decoy a
40+
type NatBox
41+
type Tres
42+
Decoy.confuser : Decoy a -> Tres
43+
Decoy.confuser.modify : (Tres ->{g} Tres)
44+
-> Decoy a1
45+
->{g} Decoy a
46+
Decoy.confuser.set : Tres -> Decoy a1 -> Decoy a
47+
xyzzy : NatBox -> Decoy a -> Nat
48+
49+
Now evaluating any watch expressions (lines starting with
50+
`>`)... Ctrl+C cancels.
51+
52+
16 | > xyzzy (NatBox 1) (Decoy One)
53+
54+
1
55+
56+
17 | > xyzzy (NatBox 1) (Decoy Two)
57+
58+
2
59+
60+
18 | > xyzzy (NatBox 1) (Decoy Three)
61+
62+
11
63+
```

0 commit comments

Comments
 (0)