Skip to content

Commit de6809b

Browse files
authored
Fix name clash in guard clauses (#4358)
* Fix name clash in guard clauses * Minor cleanup, update changelog entry
1 parent 8201875 commit de6809b

File tree

9 files changed

+95
-23
lines changed

9 files changed

+95
-23
lines changed

CHANGELOG.d/fix_4357.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
* Fix name clash in guard clauses introduced in #4293
2+
3+
As a consequence, a problem with the compiler not being able to see
4+
imported names if they're shadowed by a guard binder is also solved.
5+
```purs
6+
import Data.Foldable (fold)
7+
import Data.Maybe (Maybe(..))
8+
import Data.Monoid.Additive (Additive(..))
9+
10+
test :: Maybe Int -> Int
11+
test = case _ of
12+
m | Just fold <- m -> fold
13+
-- Previously would complain about `fold` being undefined
14+
| otherwise -> case fold [] of Additive x -> x
15+
```
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* Add `Guard` handler for the `everywhereWithContextOnValuesM` traversal.

src/Language/PureScript/AST/Traversals.hs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
module Language.PureScript.AST.Traversals where
55

66
import Prelude.Compat
7+
import Protolude (swap)
78

89
import Control.Monad
10+
import Control.Monad.Trans.State
911

1012
import Data.Foldable (fold)
1113
import Data.Functor.Identity (runIdentity)
@@ -424,15 +426,17 @@ everywhereWithContextOnValues
424426
-> (s -> Binder -> (s, Binder))
425427
-> (s -> CaseAlternative -> (s, CaseAlternative))
426428
-> (s -> DoNotationElement -> (s, DoNotationElement))
429+
-> (s -> Guard -> (s, Guard))
427430
-> ( Declaration -> Declaration
428431
, Expr -> Expr
429432
, Binder -> Binder
430433
, CaseAlternative -> CaseAlternative
431434
, DoNotationElement -> DoNotationElement
435+
, Guard -> Guard
432436
)
433-
everywhereWithContextOnValues s f g h i j = (runIdentity . f', runIdentity . g', runIdentity . h', runIdentity . i', runIdentity . j')
437+
everywhereWithContextOnValues s f g h i j k = (runIdentity . f', runIdentity . g', runIdentity . h', runIdentity . i', runIdentity . j', runIdentity . k')
434438
where
435-
(f', g', h', i', j') = everywhereWithContextOnValuesM s (wrap f) (wrap g) (wrap h) (wrap i) (wrap j)
439+
(f', g', h', i', j', k') = everywhereWithContextOnValuesM s (wrap f) (wrap g) (wrap h) (wrap i) (wrap j) (wrap k)
436440
wrap = ((pure .) .)
437441

438442
everywhereWithContextOnValuesM
@@ -444,13 +448,15 @@ everywhereWithContextOnValuesM
444448
-> (s -> Binder -> m (s, Binder))
445449
-> (s -> CaseAlternative -> m (s, CaseAlternative))
446450
-> (s -> DoNotationElement -> m (s, DoNotationElement))
451+
-> (s -> Guard -> m (s, Guard))
447452
-> ( Declaration -> m Declaration
448453
, Expr -> m Expr
449454
, Binder -> m Binder
450455
, CaseAlternative -> m CaseAlternative
451456
, DoNotationElement -> m DoNotationElement
457+
, Guard -> m Guard
452458
)
453-
everywhereWithContextOnValuesM s0 f g h i j = (f'' s0, g'' s0, h'' s0, i'' s0, j'' s0)
459+
everywhereWithContextOnValuesM s0 f g h i j k = (f'' s0, g'' s0, h'' s0, i'' s0, j'' s0, k'' s0)
454460
where
455461
f'' s = uncurry f' <=< f s
456462

@@ -501,7 +507,18 @@ everywhereWithContextOnValuesM s0 f g h i j = (f'' s0, g'' s0, h'' s0, i'' s0, j
501507

502508
i'' s = uncurry i' <=< i s
503509

504-
i' s (CaseAlternative bs val) = CaseAlternative <$> traverse (h'' s) bs <*> traverse (guardedExprM (k' s) (g'' s)) val
510+
i' s (CaseAlternative bs val) = CaseAlternative <$> traverse (h'' s) bs <*> traverse (guardedExprM' s) val
511+
512+
-- A specialized `guardedExprM` that keeps track of the context `s`
513+
-- after traversing `guards`, such that it's also exposed to `expr`.
514+
guardedExprM' :: s -> GuardedExpr -> m GuardedExpr
515+
guardedExprM' s (GuardedExpr guards expr) = do
516+
(guards', s') <- runStateT (traverse (StateT . goGuard) guards) s
517+
GuardedExpr guards' <$> g'' s' expr
518+
519+
-- Like k'', but `s` is tracked.
520+
goGuard :: Guard -> s -> m (Guard, s)
521+
goGuard x s = k s x >>= fmap swap . sndM' k'
505522

506523
j'' s = uncurry j' <=< j s
507524

@@ -510,6 +527,8 @@ everywhereWithContextOnValuesM s0 f g h i j = (f'' s0, g'' s0, h'' s0, i'' s0, j
510527
j' s (DoNotationLet ds) = DoNotationLet <$> traverse (f'' s) ds
511528
j' s (PositionedDoNotationElement pos com e1) = PositionedDoNotationElement pos com <$> j'' s e1
512529

530+
k'' s = uncurry k' <=< k s
531+
513532
k' s (ConditionGuard e) = ConditionGuard <$> g'' s e
514533
k' s (PatternGuard b e) = PatternGuard <$> h'' s b <*> g'' s e
515534

src/Language/PureScript/Linter/Wildcards.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import Language.PureScript.Types
2222
ignoreWildcardsUnderCompleteTypeSignatures :: Declaration -> Declaration
2323
ignoreWildcardsUnderCompleteTypeSignatures = onDecl
2424
where
25-
(onDecl, _, _, _, _) = everywhereWithContextOnValues False (,) handleExpr handleBinder (,) (,)
25+
(onDecl, _, _, _, _, _) = everywhereWithContextOnValues False (,) handleExpr handleBinder (,) (,) (,)
2626

2727
handleExpr isCovered = \case
2828
tv@(TypedValue chk v ty)

src/Language/PureScript/Sugar/Names.hs

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -172,14 +172,15 @@ renameInModule imports (Module modSS coms mn decls exps) =
172172
Module modSS coms mn <$> parU decls go <*> pure exps
173173
where
174174

175-
(go, _, _, _, _) =
175+
(go, _, _, _, _, _) =
176176
everywhereWithContextOnValuesM
177177
(modSS, M.empty)
178178
(\(_, bound) d -> (\(bound', d') -> ((declSourceSpan d', bound'), d')) <$> updateDecl bound d)
179179
updateValue
180180
updateBinder
181181
updateCase
182182
defS
183+
updateGuard
183184

184185
updateDecl
185186
:: M.Map Ident SourcePos
@@ -303,23 +304,25 @@ renameInModule imports (Module modSS coms mn decls exps) =
303304
:: (SourceSpan, M.Map Ident SourcePos)
304305
-> CaseAlternative
305306
-> m ((SourceSpan, M.Map Ident SourcePos), CaseAlternative)
306-
updateCase (pos, bound) c@(CaseAlternative bs gs) =
307-
return ((pos, updateGuard gs `M.union` rUnionMap binderNamesWithSpans' bs `M.union` bound), c)
307+
updateCase (pos, bound) c@(CaseAlternative bs _) =
308+
return ((pos, rUnionMap binderNamesWithSpans' bs `M.union` bound), c)
308309
where
309-
updateGuard :: [GuardedExpr] -> M.Map Ident SourcePos
310-
updateGuard [] = M.empty
311-
updateGuard (GuardedExpr g _ : xs) =
312-
updateGuard xs `M.union` rUnionMap updatePatGuard g
313-
where
314-
updatePatGuard (PatternGuard b _) = binderNamesWithSpans' b
315-
updatePatGuard _ = M.empty
316-
317310
rUnionMap f = foldl' (flip (M.union . f)) M.empty
318311

319-
binderNamesWithSpans'
320-
= M.fromList
321-
. fmap (second spanStart . swap)
322-
. binderNamesWithSpans
312+
updateGuard
313+
:: (SourceSpan, M.Map Ident SourcePos)
314+
-> Guard
315+
-> m ((SourceSpan, M.Map Ident SourcePos), Guard)
316+
updateGuard (pos, bound) g@(ConditionGuard _) =
317+
return ((pos, bound), g)
318+
updateGuard (pos, bound) g@(PatternGuard b _) =
319+
return ((pos, binderNamesWithSpans' b `M.union` bound), g)
320+
321+
binderNamesWithSpans' :: Binder -> M.Map Ident SourcePos
322+
binderNamesWithSpans'
323+
= M.fromList
324+
. fmap (second spanStart . swap)
325+
. binderNamesWithSpans
323326

324327
letBoundVariable :: Declaration -> Maybe Ident
325328
letBoundVariable = fmap valdeclIdent . getValueDeclaration

src/Language/PureScript/Sugar/Operators.hs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,15 @@ rebracketFiltered !caller pred_ externs m = do
136136
Module ss coms mn <$> mapM (usingPredicate pred_ f') ds <*> pure exts
137137
where
138138
(goDecl', goExpr', goBinder') = updateTypes goType
139-
(f', _, _, _, _) =
139+
(f', _, _, _, _, _) =
140140
everywhereWithContextOnValuesM
141141
ss
142142
(\_ d -> (declSourceSpan d,) <$> goDecl' d)
143143
(\pos -> uncurry goExpr <=< goExpr' pos)
144144
(\pos -> uncurry goBinder <=< goBinder' pos)
145145
defS
146146
defS
147+
defS
147148

148149
goExpr :: SourceSpan -> Expr -> m (SourceSpan, Expr)
149150
goExpr _ e@(PositionedValue pos _ _) = return (pos, e)
@@ -225,14 +226,15 @@ rebracketModule !caller pred_ valueOpTable typeOpTable (Module ss coms mn ds ext
225226
CalledByDocs -> f
226227
CalledByCompile -> g <=< f
227228

228-
(f, _, _, _, _) =
229+
(f, _, _, _, _, _) =
229230
everywhereWithContextOnValuesM
230231
ss
231232
(\_ d -> (declSourceSpan d,) <$> goDecl d)
232233
(\pos -> wrap (matchExprOperators valueOpTable) <=< goExpr' pos)
233234
(\pos -> wrap (matchBinderOperators valueOpTable) <=< goBinder' pos)
234235
defS
235236
defS
237+
defS
236238

237239
(g, _, _) = everywhereOnValuesTopDownM pure removeBinaryNoParens pure
238240

src/Language/PureScript/Traversals.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import Prelude.Compat
66
sndM :: (Functor f) => (b -> f c) -> (a, b) -> f (a, c)
77
sndM f (a, b) = (a, ) <$> f b
88

9+
sndM' :: (Functor f) => (a -> b -> f c) -> (a, b) -> f (a, c)
10+
sndM' f (a, b) = (a, ) <$> f a b
11+
912
thirdM :: (Functor f) => (c -> f d) -> (a, b, c) -> f (a, b, d)
1013
thirdM f (a, b, c) = (a, b, ) <$> f c
1114

src/Language/PureScript/TypeChecker/Skolems.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ skolemizeTypesInValue ann ident mbK sko scope =
5656
runIdentity . onExpr'
5757
where
5858
onExpr' :: Expr -> Identity Expr
59-
(_, onExpr', _, _, _) = everywhereWithContextOnValuesM [] defS onExpr onBinder defS defS
59+
(_, onExpr', _, _, _, _) = everywhereWithContextOnValuesM [] defS onExpr onBinder defS defS defS
6060

6161
onExpr :: [Text] -> Expr -> Identity ([Text], Expr)
6262
onExpr sco (DeferredDictionary c ts)

tests/purs/passing/4357.purs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module Main where
2+
3+
import Prelude
4+
5+
import Data.Foldable (fold)
6+
import Data.Maybe (Maybe(..))
7+
import Data.Monoid.Additive (Additive(..))
8+
import Effect.Console (log)
9+
10+
data Foo = Foo Int | Bar Int
11+
12+
g :: Foo -> Int
13+
g =
14+
case _ of
15+
a
16+
| Bar z <- a
17+
-> z
18+
| Foo z <- a
19+
-> z
20+
| otherwise
21+
-> 42
22+
23+
-- solved as a consequence of #4358
24+
test :: Maybe Int -> Int
25+
test = case _ of
26+
m | Just fold <- m -> fold
27+
| otherwise -> case fold [] of Additive x -> x
28+
29+
main = log "Done"

0 commit comments

Comments
 (0)