X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=blobdiff_plain;f=compiler%2FdeSugar%2FDesugar.lhs;h=7d0be3f65b507d7b720c82be7a79a7d73ace6e49;hp=64fff0d0129fe1d34798e3e7f96b87ad7ebe0c2f;hb=34c8d0312071f7d0f4d221a997d3408c653ef9e5;hpb=d4f4391a030e683572eee01291cc8bc6203dbf5d diff --git a/compiler/deSugar/Desugar.lhs b/compiler/deSugar/Desugar.lhs index 64fff0d..7d0be3f 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,6 +18,7 @@ import MkIface import Id import Name import CoreSyn +import CoreSubst import PprCore import DsMonad import DsExpr @@ -27,16 +29,20 @@ import DsExpr () -- Forces DsExpr to be compiled; DsBinds only import Module import RdrName import NameSet +import NameEnv import Rules 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 DsHetMet +import Control.Exception ( catch, ErrorCall, Exception(..) ) \end{code} %************************************************************************ @@ -65,6 +71,8 @@ deSugar hsc_env 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, @@ -83,44 +91,74 @@ deSugar hsc_env <- case target of HscNothing -> return (emptyMessages, - Just ([], [], NoStubs, hpcInfo, emptyModBreaks)) + 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 + 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) + 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 (msgs, Nothing) ; - Just (all_prs, ds_rules, ds_fords,ds_hpc_info, modBreaks) -> do + 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_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 CoreDesugar ds_binds ds_rules - - -- 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 { @@ -139,7 +177,7 @@ deSugar hsc_env 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, @@ -149,6 +187,38 @@ deSugar hsc_env ; return (msgs, Just mod_guts) }}} +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 @@ -173,7 +243,7 @@ deSugarExpr :: HscEnv deSugarExpr hsc_env this_mod rdr_env type_env tc_expr = do let dflags = hsc_dflags hsc_env - showPass dflags "Desugar" + showPass dflags "Desugarz" -- Do desugaring (msgs, mb_core_expr) <- initDs hsc_env this_mod rdr_env type_env $ @@ -183,40 +253,51 @@ deSugarExpr hsc_env this_mod rdr_env type_env tc_expr = do Nothing -> return (msgs, Nothing) Just expr -> do +{- -- Dump output - dumpIfSet_dyn dflags Opt_D_dump_ds "Desugared" (pprCoreExpr expr) + dumpIfSet_dyn dflags Opt_D_dump_ds "Desugared" (text $ "$$\n"++(core2proofAndShow expr)++"$$\n") +-} return (msgs, Just expr) +\end{code} --- 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)] - -> [(Id, t)] -addExportFlags target exports keep_alive prs - = [(add_export bndr, rhs) | (bndr,rhs) <- prs] +%************************************************************************ +%* * +%* 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 - dont_discard bndr = is_exported name + dont_discard :: Name -> Bool + dont_discard name = is_exported name || name `elemNameSet` keep_alive - 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 +309,44 @@ addExportFlags target exports keep_alive prs 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 - = blankLine $$ 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 + %************************************************************************ %* * @@ -250,28 +360,28 @@ dsRule (L loc (HsRule name act vars lhs _tv_lhs rhs _fv_rhs)) = putSrcSpanDs loc $ do { let bndrs' = [var | RuleBndr (L _ var) <- vars] - ; lhs' <- unsetOptM Opt_EnableRewriteRules $ - dsLExpr lhs -- Note [Desugaring RULE lhss] + ; lhs' <- unsetOptM Opt_EnableRewriteRules $ + unsetOptM Opt_WarnIdentities $ + dsLExpr lhs -- Note [Desugaring RULE left hand sides] - ; rhs' <- dsLExpr rhs + ; rhs' <- dsLExpr rhs -- Substitute the dict bindings eagerly, -- and take the body apart into a (f args) form - ; case decomposeRuleLhs (mkLams bndrs' lhs') of { - Nothing -> do { warnDs msg; return Nothing } ; - Just (bndrs, fn_id, args) -> do + ; case decomposeRuleLhs bndrs' lhs' of { + Left msg -> do { warnDs msg; return Nothing } ; + Right (final_bndrs, fn_id, args) -> do - { let local_rule = isLocalId fn_id + { 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 = mkRule local_rule name act fn_name bndrs args rhs' + fn_name = idName fn_id + 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] @@ -283,3 +393,7 @@ 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 #-}