X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=blobdiff_plain;f=compiler%2FdeSugar%2FDesugar.lhs;h=28984608d993506a665e83868765df3690e0a912;hp=eeaa154669904794adbcaafc3fed057582252498;hb=29dae53960f63314456cb2b25d428faf87f4af04;hpb=ecb2e6d552b3302738418c2a3e94ad3a78cb3262 diff --git a/compiler/deSugar/Desugar.lhs b/compiler/deSugar/Desugar.lhs index eeaa154..2898460 100644 --- a/compiler/deSugar/Desugar.lhs +++ b/compiler/deSugar/Desugar.lhs @@ -8,6 +8,7 @@ The Desugarer: turning HsSyn into Core. \begin{code} module Desugar ( deSugar, deSugarExpr ) where +import TysWiredIn (unitDataConId) import DynFlags import StaticFlags import HscTypes @@ -17,7 +18,7 @@ import MkIface import Id import Name import CoreSyn -import OccurAnal +import CoreSubst import PprCore import DsMonad import DsExpr @@ -28,17 +29,19 @@ import DsExpr () -- Forces DsExpr to be compiled; DsBinds only import Module import RdrName import NameSet -import VarSet +import NameEnv import Rules -import CoreLint -import CoreFVs +import CoreMonad ( endPass, CoreToDo(..) ) import ErrUtils import Outputable import SrcLoc -import Maybes -import FastString import Coverage +import Util +import MonadUtils +import OrdList +import Data.List import Data.IORef +import Control.Exception ( catch, ErrorCall, Exception(..) ) \end{code} %************************************************************************ @@ -48,7 +51,8 @@ import Data.IORef %************************************************************************ \begin{code} -deSugar :: HscEnv -> ModLocation -> TcGblEnv -> IO (Maybe ModGuts) +-- | Main entry point to the desugarer. +deSugar :: HscEnv -> ModLocation -> TcGblEnv -> IO (Messages, Maybe ModGuts) -- Can modify PCS by faulting in more declarations deSugar hsc_env @@ -63,8 +67,11 @@ deSugar hsc_env tcg_fix_env = fix_env, tcg_inst_env = inst_env, tcg_fam_inst_env = fam_inst_env, - tcg_deprecs = deprecs, + tcg_warns = warns, + tcg_anns = anns, tcg_binds = binds, + tcg_imp_specs = imp_specs, + tcg_ev_binds = ev_binds, tcg_fords = fords, tcg_rules = rules, tcg_insts = insts, @@ -76,47 +83,81 @@ deSugar hsc_env -- Desugar the program ; let export_set = availsToNameSet exports - ; let auto_scc = mkAutoScc mod export_set + ; let auto_scc = mkAutoScc dflags mod export_set ; let target = hscTarget dflags ; let hpcInfo = emptyHpcInfo other_hpc_info - ; mb_res <- case target of - HscNothing -> return (Just ([], [], NoStubs, hpcInfo, emptyModBreaks)) - _ -> do (binds_cvr,ds_hpc_info, modBreaks) - <- if (opt_Hpc - || target == HscInterpreted) - && (not (isHsBoot hsc_src)) - then addCoverageTicksToBinds dflags mod mod_loc (typeEnvTyCons type_env) binds - else return (binds, hpcInfo, emptyModBreaks) - initDs hsc_env mod rdr_env type_env $ do - { core_prs <- dsTopLHsBinds auto_scc binds_cvr - ; (ds_fords, foreign_prs) <- dsForeigns fords - ; let all_prs = foreign_prs ++ core_prs - ; ds_rules <- mapM dsRule rules - ; return (all_prs, catMaybes ds_rules, ds_fords, ds_hpc_info, modBreaks) - } + ; (msgs, mb_res) + <- case target of + HscNothing -> + return (emptyMessages, + Just ([], nilOL, [], NoStubs, hpcInfo, emptyModBreaks)) + _ -> do + (binds_cvr,ds_hpc_info, modBreaks) + <- if (opt_Hpc + || target == HscInterpreted) + && (not (isHsBoot hsc_src)) + then addCoverageTicksToBinds dflags mod mod_loc + (typeEnvTyCons type_env) binds + else return (binds, hpcInfo, emptyModBreaks) + initDs hsc_env mod rdr_env type_env $ do + do { ds_ev_binds <- dsEvBinds ev_binds + ; core_prs <- dsTopLHsBinds auto_scc binds_cvr + ; (spec_prs, spec_rules) <- dsImpSpecs imp_specs + ; (ds_fords, foreign_prs) <- dsForeigns fords + ; rules <- mapMaybeM dsRule rules + ; return ( ds_ev_binds + , foreign_prs `appOL` core_prs `appOL` spec_prs + , spec_rules ++ rules + , ds_fords, ds_hpc_info, modBreaks) } + ; case mb_res of { - Nothing -> return Nothing ; - Just (all_prs, ds_rules, ds_fords,ds_hpc_info, modBreaks) -> do + Nothing -> return (msgs, Nothing) ; + Just (ds_ev_binds, all_prs, all_rules, ds_fords,ds_hpc_info, modBreaks) -> do { -- Add export flags to bindings keep_alive <- readIORef keep_var - ; let final_prs = addExportFlags target export_set - keep_alive all_prs ds_rules - ds_binds = [Rec final_prs] + ; let (rules_for_locals, rules_for_imps) + = partition isLocalRule all_rules + final_prs = addExportFlagsAndRules target + export_set keep_alive rules_for_locals (fromOL all_prs) + + final_pgm = combineEvBinds ds_ev_binds final_prs -- Notice that we put the whole lot in a big Rec, even the foreign binds -- When compiling PrelFloat, which defines data Float = F# Float# -- we want F# to be in scope in the foreign marshalling code! -- You might think it doesn't matter, but the simplifier brings all top-level -- things into the in-scope set before simplifying; so we get no unfolding for F#! - -- Lint result if necessary - ; endPass dflags "Desugar" Opt_D_dump_ds ds_binds - - -- Dump output - ; doIfSet (dopt Opt_D_dump_ds dflags) - (printDump (ppr_ds_rules ds_rules)) - - ; used_names <- mkUsedNames tcg_env + -- Lint result if necessary, and print + ; dumpIfSet_dyn dflags Opt_D_dump_ds "Desugared, before opt" $ + (vcat [ pprCoreBindings final_pgm + , pprRules rules_for_imps ]) + + ; (ds_binds, ds_rules_for_imps) <- simpleOptPgm dflags final_pgm rules_for_imps + -- The simpleOptPgm gets rid of type + -- bindings plus any stupid dead code +{- + ; dumpIfSet_dyn dflags Opt_D_dump_proof "input to flattener" (text $ showSDoc $ pprCoreBindings ds_binds) + ; let uhandler (err::ErrorCall) + = dumpIfSet_dyn dflags Opt_D_dump_proof "System FC Proof" + (text $ "\\begin{verbatim}\n" ++ + show err ++ + "\\end{verbatim}\n\n") + in (dumpIfSet_dyn dflags Opt_D_dump_proof "System FC Proof" $ + (vcat (map (\ bind -> let e = case bind of + NonRec b e -> e + Rec lve -> Let (Rec lve) (Var unitDataConId) + in text $ "\\begin{verbatim}\n" ++ + (showSDoc $ pprCoreBindings ds_binds) ++ + "\\end{verbatim}\n\n" ++ + "$$\n"++ + (core2proofAndShow e) ++ + "$$\n" + ) ds_binds))) `Control.Exception.catch` uhandler +-} + ; endPass dflags CoreDesugar ds_binds ds_rules_for_imps + + ; let used_names = mkUsedNames tcg_env ; deps <- mkDependencies tcg_env ; let mod_guts = ModGuts { @@ -128,95 +169,134 @@ deSugar hsc_env mg_dir_imps = imp_mods imports, mg_rdr_env = rdr_env, mg_fix_env = fix_env, - mg_deprecs = deprecs, + mg_warns = warns, + mg_anns = anns, mg_types = type_env, mg_insts = insts, mg_fam_insts = fam_insts, mg_inst_env = inst_env, mg_fam_inst_env = fam_inst_env, - mg_rules = ds_rules, + mg_rules = ds_rules_for_imps, mg_binds = ds_binds, mg_foreign = ds_fords, mg_hpc_info = ds_hpc_info, mg_modBreaks = modBreaks, mg_vect_info = noVectInfo } - ; return (Just mod_guts) + ; return (msgs, Just mod_guts) }}} -mkAutoScc :: Module -> NameSet -> AutoScc -mkAutoScc mod exports +dsImpSpecs :: [LTcSpecPrag] -> DsM (OrdList (Id,CoreExpr), [CoreRule]) +dsImpSpecs imp_specs + = do { spec_prs <- mapMaybeM (dsSpec Nothing) imp_specs + ; let (spec_binds, spec_rules) = unzip spec_prs + ; return (concatOL spec_binds, spec_rules) } + +combineEvBinds :: [DsEvBind] -> [(Id,CoreExpr)] -> [CoreBind] +-- Top-level bindings can include coercion bindings, but not via superclasses +-- See Note [Top-level evidence] +combineEvBinds [] val_prs + = [Rec val_prs] +combineEvBinds (LetEvBind (NonRec b r) : bs) val_prs + | isId b = combineEvBinds bs ((b,r):val_prs) + | otherwise = NonRec b r : combineEvBinds bs val_prs +combineEvBinds (LetEvBind (Rec prs) : bs) val_prs + = combineEvBinds bs (prs ++ val_prs) +combineEvBinds (CaseEvBind x _ _ : _) _ + = pprPanic "topEvBindPairs" (ppr x) +\end{code} + +Note [Top-level evidence] +~~~~~~~~~~~~~~~~~~~~~~~~~ +Top-level evidence bindings may be mutually recursive with the top-level value +bindings, so we must put those in a Rec. But we can't put them *all* in a Rec +because the occurrence analyser doesn't teke account of type/coercion variables +when computing dependencies. + +So we pull out the type/coercion variables (which are in dependency order), +and Rec the rest. + + +\begin{code} +mkAutoScc :: DynFlags -> Module -> NameSet -> AutoScc +mkAutoScc dflags mod exports | not opt_SccProfilingOn -- No profiling = NoSccs - | opt_AutoSccsOnAllToplevs -- Add auto-scc on all top-level things - = AddSccs mod (\_ -> True) - | opt_AutoSccsOnExportedToplevs -- Only on exported things + -- Add auto-scc on all top-level things + | dopt Opt_AutoSccsOnAllToplevs dflags + = AddSccs mod (\id -> not $ isDerivedOccName $ getOccName id) + -- See #1641. This is pretty yucky, but I can't see a better way + -- to identify compiler-generated Ids, and at least this should + -- catch them all. + -- Only on exported things + | dopt Opt_AutoSccsOnExportedToplevs dflags = AddSccs mod (\id -> idName id `elemNameSet` exports) | otherwise = NoSccs - deSugarExpr :: HscEnv -> Module -> GlobalRdrEnv -> TypeEnv -> LHsExpr Id - -> IO (Maybe CoreExpr) + -> IO (Messages, Maybe CoreExpr) -- Prints its own errors; returns Nothing if error occurred -deSugarExpr hsc_env this_mod rdr_env type_env tc_expr - = do { let dflags = hsc_dflags hsc_env - ; showPass dflags "Desugar" - - -- Do desugaring - ; mb_core_expr <- initDs hsc_env this_mod rdr_env type_env $ - dsLExpr tc_expr - - ; case mb_core_expr of { - Nothing -> return Nothing ; - Just expr -> do { - - -- Dump output - dumpIfSet_dyn dflags Opt_D_dump_ds "Desugared" (pprCoreExpr expr) - - ; return (Just expr) } } } - --- addExportFlags --- Set the no-discard flag if either --- a) the Id is exported --- b) it's mentioned in the RHS of an orphan rule --- c) it's in the keep-alive set --- --- It means that the binding won't be discarded EVEN if the binding --- ends up being trivial (v = w) -- the simplifier would usually just --- substitute w for v throughout, but we don't apply the substitution to --- the rules (maybe we should?), so this substitution would make the rule --- bogus. - --- You might wonder why exported Ids aren't already marked as such; --- it's just because the type checker is rather busy already and --- I didn't want to pass in yet another mapping. - -addExportFlags :: HscTarget -> NameSet -> NameSet -> [(Id, t)] -> [CoreRule] - -> [(Id, t)] -addExportFlags target exports keep_alive prs rules - = [(add_export bndr, rhs) | (bndr,rhs) <- prs] +deSugarExpr hsc_env this_mod rdr_env type_env tc_expr = do + let dflags = hsc_dflags hsc_env + showPass dflags "Desugarz" + + -- Do desugaring + (msgs, mb_core_expr) <- initDs hsc_env this_mod rdr_env type_env $ + dsLExpr tc_expr + + case mb_core_expr of + Nothing -> return (msgs, Nothing) + Just expr -> do + +{- + -- Dump output + dumpIfSet_dyn dflags Opt_D_dump_ds "Desugared" (text $ "$$\n"++(core2proofAndShow expr)++"$$\n") +-} + + return (msgs, Just expr) +\end{code} + +%************************************************************************ +%* * +%* Add rules and export flags to binders +%* * +%************************************************************************ + +\begin{code} +addExportFlagsAndRules + :: HscTarget -> NameSet -> NameSet -> [CoreRule] + -> [(Id, t)] -> [(Id, t)] +addExportFlagsAndRules target exports keep_alive rules prs + = mapFst add_one prs where - add_export bndr - | dont_discard bndr = setIdExported bndr + add_one bndr = add_rules name (add_export name bndr) + where + name = idName bndr + + ---------- Rules -------- + -- See Note [Attach rules to local ids] + -- NB: the binder might have some existing rules, + -- arising from specialisation pragmas + add_rules name bndr + | Just rules <- lookupNameEnv rule_base name + = bndr `addIdSpecialisations` rules + | otherwise + = bndr + rule_base = extendRuleBaseList emptyRuleBase rules + + ---------- Export flag -------- + -- See Note [Adding export flags] + add_export name bndr + | dont_discard name = setIdExported bndr | otherwise = bndr - orph_rhs_fvs = unionVarSets [ ruleRhsFreeVars rule - | rule <- rules, - not (isLocalRule rule) ] - -- A non-local rule keeps alive the free vars of its right-hand side. - -- (A "non-local" is one whose head function is not locally defined.) - -- Local rules are (later, after gentle simplification) - -- attached to the Id, and that keeps the rhs free vars alive. - - dont_discard bndr = is_exported name + dont_discard :: Name -> Bool + dont_discard name = is_exported name || name `elemNameSet` keep_alive - || bndr `elemVarSet` orph_rhs_fvs - where - name = idName bndr -- In interactive mode, we don't want to discard any top-level -- entities at all (eg. do not inline them away during @@ -228,15 +308,44 @@ addExportFlags target exports keep_alive prs rules is_exported :: Name -> Bool is_exported | target == HscInterpreted = isExternalName | otherwise = (`elemNameSet` exports) - -ppr_ds_rules :: [CoreRule] -> SDoc -ppr_ds_rules [] = empty -ppr_ds_rules rules - = text "" $$ text "-------------- DESUGARED RULES -----------------" $$ - pprRules rules \end{code} +Note [Adding export flags] +~~~~~~~~~~~~~~~~~~~~~~~~~~ +Set the no-discard flag if either + a) the Id is exported + b) it's mentioned in the RHS of an orphan rule + c) it's in the keep-alive set + +It means that the binding won't be discarded EVEN if the binding +ends up being trivial (v = w) -- the simplifier would usually just +substitute w for v throughout, but we don't apply the substitution to +the rules (maybe we should?), so this substitution would make the rule +bogus. + +You might wonder why exported Ids aren't already marked as such; +it's just because the type checker is rather busy already and +I didn't want to pass in yet another mapping. + +Note [Attach rules to local ids] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Find the rules for locally-defined Ids; then we can attach them +to the binders in the top-level bindings + +Reason + - It makes the rules easier to look up + - It means that transformation rules and specialisations for + locally defined Ids are handled uniformly + - It keeps alive things that are referred to only from a rule + (the occurrence analyser knows about rules attached to Ids) + - It makes sure that, when we apply a rule, the free vars + of the RHS are more likely to be in scope + - The imported rules are carried in the in-scope set + which is extended on each iteration by the new wave of + local binders; any rules which aren't on the binding will + thereby get dropped + %************************************************************************ %* * @@ -248,29 +357,42 @@ ppr_ds_rules rules dsRule :: LRuleDecl Id -> DsM (Maybe CoreRule) dsRule (L loc (HsRule name act vars lhs _tv_lhs rhs _fv_rhs)) = putSrcSpanDs loc $ - do { let bndrs = [var | RuleBndr (L _ var) <- vars] - ; lhs' <- dsLExpr lhs - ; rhs' <- dsLExpr rhs + do { let bndrs' = [var | RuleBndr (L _ var) <- vars] + + ; lhs' <- unsetOptM Opt_EnableRewriteRules $ + unsetOptM Opt_WarnIdentities $ + dsLExpr lhs -- Note [Desugaring RULE left hand sides] + + ; rhs' <- dsLExpr rhs - ; case decomposeRuleLhs (occurAnalyseExpr lhs') of { - Nothing -> do { warnDs msg; return Nothing } ; - Just (fn_id, args) -> do - -- Substitute the dict bindings eagerly, -- and take the body apart into a (f args) form - { let local_rule = isLocalId fn_id + ; case decomposeRuleLhs bndrs' lhs' of { + Left msg -> do { warnDs msg; return Nothing } ; + Right (final_bndrs, fn_id, args) -> do + + { let is_local = isLocalId fn_id -- NB: isLocalId is False of implicit Ids. This is good becuase -- we don't want to attach rules to the bindings of implicit Ids, -- because they don't show up in the bindings until just before code gen fn_name = idName fn_id - - rule = Rule { ru_name = name, ru_fn = fn_name, ru_act = act, - ru_bndrs = bndrs, ru_args = args, ru_rhs = rhs', - ru_rough = roughTopNames args, - ru_local = local_rule } + final_rhs = simpleOptExpr rhs' -- De-crap it + rule = mkRule False {- Not auto -} is_local + name act fn_name final_bndrs args final_rhs ; return (Just rule) } } } - where - msg = hang (ptext (sLit "RULE left-hand side too complicated to desugar; ignored")) - 2 (ppr lhs) \end{code} + +Note [Desugaring RULE left hand sides] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +For the LHS of a RULE we do *not* want to desugar + [x] to build (\cn. x `c` n) +We want to leave explicit lists simply as chains +of cons's. We can achieve that slightly indirectly by +switching off EnableRewriteRules. See DsExpr.dsExplicitList. + +That keeps the desugaring of list comprehensions simple too. + +Nor do we want to warn of conversion identities on the LHS; +the rule is precisly to optimise them: + {-# RULES "fromRational/id" fromRational = id :: Rational -> Rational #-}