diff options
author | Bartosz Nitka <niteria@gmail.com> | 2016-06-06 06:08:54 -0700 |
---|---|---|
committer | Bartosz Nitka <niteria@gmail.com> | 2016-06-06 06:13:48 -0700 |
commit | e684f5469399b9d239693eb54f9d1b4d55253ac4 (patch) | |
tree | eb1309bcb1aa7769dc236e58259e3056c6a66024 /compiler/rename | |
parent | a90085bd45239fffd65c01c24752a9bbcef346f1 (diff) | |
download | haskell-e684f5469399b9d239693eb54f9d1b4d55253ac4.tar.gz |
Desugar ApplicativeDo and RecDo deterministically
This fixes a problem described in
Note [Deterministic ApplicativeDo and RecursiveDo desugaring].
Test Plan: ./validate + new testcase
Reviewers: simonpj, bgamari, austin, simonmar
Reviewed By: simonmar
Subscribers: thomie
Differential Revision: https://phabricator.haskell.org/D2287
GHC Trac Issues: #4012
Diffstat (limited to 'compiler/rename')
-rw-r--r-- | compiler/rename/RnExpr.hs | 43 |
1 files changed, 36 insertions, 7 deletions
diff --git a/compiler/rename/RnExpr.hs b/compiler/rename/RnExpr.hs index 32277b43ac..c92f69e6e3 100644 --- a/compiler/rename/RnExpr.hs +++ b/compiler/rename/RnExpr.hs @@ -633,6 +633,27 @@ rnArithSeq (FromThenTo expr1 expr2 expr3) ************************************************************************ -} +{- +Note [Deterministic ApplicativeDo and RecursiveDo desugaring] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Both ApplicativeDo and RecursiveDo need to create tuples not +present in the source text. + +For ApplicativeDo we create: + + (a,b,c) <- (\c b a -> (a,b,c)) <$> + +For RecursiveDo we create: + + mfix (\ ~(a,b,c) -> do ...; return (a',b',c')) + +The order of the components in those tuples needs to be stable +across recompilations, otherwise they can get optimized differently +and we end up with incompatible binaries. +To get a stable order we use nameSetElemsStable. +See Note [Deterministic UniqFM] to learn more about nondeterminism. +-} + -- | Rename some Stmts rnStmts :: Outputable (body RdrName) => HsStmtContext Name @@ -814,8 +835,11 @@ rnStmt ctxt rnBody (L loc (RecStmt { recS_stmts = rec_stmts })) thing_inside -- (This set may not be empty, because we're in a recursive -- context.) ; rnRecStmtsAndThen rnBody rec_stmts $ \ segs -> do - { let bndrs = nameSetElems $ foldr (unionNameSet . (\(ds,_,_,_) -> ds)) - emptyNameSet segs + { let bndrs = nameSetElemsStable $ + foldr (unionNameSet . (\(ds,_,_,_) -> ds)) + emptyNameSet + segs + -- See Note [Deterministic ApplicativeDo and RecursiveDo desugaring] ; (thing, fvs_later) <- thing_inside bndrs ; let (rec_stmts', fvs) = segmentRecStmts loc ctxt empty_rec_stmt segs fvs_later -- We aren't going to try to group RecStmts with @@ -1172,8 +1196,11 @@ segmentRecStmts loc ctxt empty_rec_stmt segs fvs_later | otherwise = ([ L loc $ empty_rec_stmt { recS_stmts = ss - , recS_later_ids = nameSetElems (defs `intersectNameSet` fvs_later) - , recS_rec_ids = nameSetElems (defs `intersectNameSet` uses) }] + , recS_later_ids = nameSetElemsStable + (defs `intersectNameSet` fvs_later) + , recS_rec_ids = nameSetElemsStable + (defs `intersectNameSet` uses) }] + -- See Note [Deterministic ApplicativeDo and RecursiveDo desugaring] , uses `plusFV` fvs_later) where @@ -1298,8 +1325,9 @@ segsToStmts empty_rec_stmt ((defs, uses, fwds, ss) : segs) fvs_later new_stmt | non_rec = head ss | otherwise = L (getLoc (head ss)) rec_stmt rec_stmt = empty_rec_stmt { recS_stmts = ss - , recS_later_ids = nameSetElems used_later - , recS_rec_ids = nameSetElems fwds } + , recS_later_ids = nameSetElemsStable used_later + , recS_rec_ids = nameSetElemsStable fwds } + -- See Note [Deterministic ApplicativeDo and RecursiveDo desugaring] non_rec = isSingleton ss && isEmptyNameSet fwds used_later = defs `intersectNameSet` later_uses -- The ones needed after the RecStmt @@ -1581,7 +1609,8 @@ stmtTreeToStmts ctxt (StmtTreeApplicative trees) tail tail_fvs = do let stmts = flattenStmtTree tree pvarset = mkNameSet (concatMap (collectStmtBinders.unLoc.fst) stmts) `intersectNameSet` tail_fvs - pvars = nameSetElems pvarset + pvars = nameSetElemsStable pvarset + -- See Note [Deterministic ApplicativeDo and RecursiveDo desugaring] pat = mkBigLHsVarPatTup pvars tup = mkBigLHsVarTup pvars (stmts',fvs2) <- stmtTreeToStmts ctxt tree [] pvarset |