+rnStmt ctxt (TransformStmt (stmts, _) usingExpr maybeByExpr) thing_inside = do
+ checkIsTransformableListComp ctxt
+
+ (usingExpr', fv_usingExpr) <- rnLExpr usingExpr
+ ((stmts', binders, (maybeByExpr', thing)), fvs) <-
+ rnNormalStmtsAndFindUsedBinders (TransformStmtCtxt ctxt) stmts $ \unshadowed_bndrs -> do
+ (maybeByExpr', fv_maybeByExpr) <- rnMaybeLExpr maybeByExpr
+ (thing, fv_thing) <- thing_inside
+
+ return ((maybeByExpr', thing), fv_maybeByExpr `plusFV` fv_thing)
+
+ return ((TransformStmt (stmts', binders) usingExpr' maybeByExpr', thing), fv_usingExpr `plusFV` fvs)
+ where
+ rnMaybeLExpr Nothing = return (Nothing, emptyFVs)
+ rnMaybeLExpr (Just expr) = do
+ (expr', fv_expr) <- rnLExpr expr
+ return (Just expr', fv_expr)
+
+rnStmt ctxt (GroupStmt (stmts, _) groupByClause) thing_inside = do
+ checkIsTransformableListComp ctxt
+
+ -- We must rename the using expression in the context before the transform is begun
+ groupByClauseAction <-
+ case groupByClause of
+ GroupByNothing usingExpr -> do
+ (usingExpr', fv_usingExpr) <- rnLExpr usingExpr
+ (return . return) (GroupByNothing usingExpr', fv_usingExpr)
+ GroupBySomething eitherUsingExpr byExpr -> do
+ (eitherUsingExpr', fv_eitherUsingExpr) <-
+ case eitherUsingExpr of
+ Right _ -> return (Right $ HsVar groupWithName, unitNameSet groupWithName)
+ Left usingExpr -> do
+ (usingExpr', fv_usingExpr) <- rnLExpr usingExpr
+ return (Left usingExpr', fv_usingExpr)
+
+ return $ do
+ (byExpr', fv_byExpr) <- rnLExpr byExpr
+ return (GroupBySomething eitherUsingExpr' byExpr', fv_eitherUsingExpr `plusFV` fv_byExpr)
+
+ -- We only use rnNormalStmtsAndFindUsedBinders to get unshadowed_bndrs, so
+ -- perhaps we could refactor this to use rnNormalStmts directly?
+ ((stmts', _, (groupByClause', usedBinderMap, thing)), fvs) <-
+ rnNormalStmtsAndFindUsedBinders (TransformStmtCtxt ctxt) stmts $ \unshadowed_bndrs -> do
+ (groupByClause', fv_groupByClause) <- groupByClauseAction
+
+ unshadowed_bndrs' <- mapM newLocalName unshadowed_bndrs
+ let binderMap = zip unshadowed_bndrs unshadowed_bndrs'
+
+ -- Bind the "thing" inside a context where we have REBOUND everything
+ -- bound by the statements before the group. This is necessary since after
+ -- the grouping the same identifiers actually have different meanings
+ -- i.e. they refer to lists not singletons!
+ (thing, fv_thing) <- bindLocalNames unshadowed_bndrs' thing_inside
+
+ -- We remove entries from the binder map that are not used in the thing_inside.
+ -- We can then use that usage information to ensure that the free variables do
+ -- not contain the things we just bound, but do contain the things we need to
+ -- make those bindings (i.e. the corresponding non-listy variables)
+
+ -- Note that we also retain those entries which have an old binder in our
+ -- own free variables (the using or by expression). This is because this map
+ -- is reused in the desugarer to create the type to bind from the statements
+ -- that occur before this one. If the binders we need are not in the map, they
+ -- will never get bound into our desugared expression and hence the simplifier
+ -- crashes as we refer to variables that don't exist!
+ let usedBinderMap = filter
+ (\(old_binder, new_binder) ->
+ (new_binder `elemNameSet` fv_thing) ||
+ (old_binder `elemNameSet` fv_groupByClause)) binderMap
+ (usedOldBinders, usedNewBinders) = unzip usedBinderMap
+ real_fv_thing = (delListFromNameSet fv_thing usedNewBinders) `plusFV` (mkNameSet usedOldBinders)
+
+ return ((groupByClause', usedBinderMap, thing), fv_groupByClause `plusFV` real_fv_thing)
+
+ traceRn (text "rnStmt: implicitly rebound these used binders:" <+> ppr usedBinderMap)
+ return ((GroupStmt (stmts', usedBinderMap) groupByClause', thing), fvs)
+