diff options
| author | Sylvain Henry <sylvain@haskus.fr> | 2020-01-26 03:15:37 +0100 |
|---|---|---|
| committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2020-02-14 05:32:37 -0500 |
| commit | cf739945b8b28ff463dc44925348f20b3c1f22cb (patch) | |
| tree | 855da097719d6b62a15fa12034c60379c49dc4a5 /compiler/deSugar/Desugar.hs | |
| parent | af6a0c36431639655762440ec8d652796b86fe58 (diff) | |
| download | haskell-cf739945b8b28ff463dc44925348f20b3c1f22cb.tar.gz | |
Module hierarchy: HsToCore (cf #13009)
Diffstat (limited to 'compiler/deSugar/Desugar.hs')
| -rw-r--r-- | compiler/deSugar/Desugar.hs | 545 |
1 files changed, 0 insertions, 545 deletions
diff --git a/compiler/deSugar/Desugar.hs b/compiler/deSugar/Desugar.hs deleted file mode 100644 index bbf67cfc48..0000000000 --- a/compiler/deSugar/Desugar.hs +++ /dev/null @@ -1,545 +0,0 @@ -{- -(c) The University of Glasgow 2006 -(c) The GRASP/AQUA Project, Glasgow University, 1992-1998 - - -The Desugarer: turning HsSyn into Core. --} - -{-# LANGUAGE CPP #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE ViewPatterns #-} - -module Desugar ( - -- * Desugaring operations - deSugar, deSugarExpr - ) where - -#include "HsVersions.h" - -import GhcPrelude - -import DsUsage -import DynFlags -import HscTypes -import GHC.Hs -import TcRnTypes -import TcRnMonad ( finalSafeMode, fixSafeInstances ) -import TcRnDriver ( runTcInteractive ) -import Id -import Name -import Type -import Avail -import CoreSyn -import CoreFVs ( exprsSomeFreeVarsList ) -import CoreOpt ( simpleOptPgm, simpleOptExpr ) -import PprCore -import DsMonad -import DsExpr -import DsBinds -import DsForeign -import PrelNames ( coercibleTyConKey ) -import TysPrim ( eqReprPrimTyCon ) -import Unique ( hasKey ) -import Coercion ( mkCoVarCo ) -import TysWiredIn ( coercibleDataCon ) -import DataCon ( dataConWrapId ) -import MkCore ( mkCoreLet ) -import Module -import NameSet -import NameEnv -import Rules -import BasicTypes ( Activation(.. ), competesWith, pprRuleName ) -import CoreMonad ( CoreToDo(..) ) -import CoreLint ( endPassIO ) -import VarSet -import FastString -import ErrUtils -import Outputable -import SrcLoc -import Coverage -import Util -import MonadUtils -import OrdList -import ExtractDocs - -import Data.List -import Data.IORef -import Control.Monad( when ) -import Plugins ( LoadedPlugin(..) ) - -{- -************************************************************************ -* * -* The main function: deSugar -* * -************************************************************************ --} - --- | 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 - mod_loc - tcg_env@(TcGblEnv { tcg_mod = id_mod, - tcg_semantic_mod = mod, - tcg_src = hsc_src, - tcg_type_env = type_env, - tcg_imports = imports, - tcg_exports = exports, - tcg_keep = keep_var, - tcg_th_splice_used = tc_splice_used, - tcg_rdr_env = rdr_env, - tcg_fix_env = fix_env, - tcg_inst_env = inst_env, - tcg_fam_inst_env = fam_inst_env, - tcg_merged = merged, - tcg_warns = warns, - tcg_anns = anns, - tcg_binds = binds, - tcg_imp_specs = imp_specs, - tcg_dependent_files = dependent_files, - tcg_ev_binds = ev_binds, - tcg_th_foreign_files = th_foreign_files_var, - tcg_fords = fords, - tcg_rules = rules, - tcg_patsyns = patsyns, - tcg_tcs = tcs, - tcg_insts = insts, - tcg_fam_insts = fam_insts, - tcg_hpc = other_hpc_info, - tcg_complete_matches = complete_matches - }) - - = do { let dflags = hsc_dflags hsc_env - print_unqual = mkPrintUnqualified dflags rdr_env - ; withTiming dflags - (text "Desugar"<+>brackets (ppr mod)) - (const ()) $ - do { -- Desugar the program - ; let export_set = availsToNameSet exports - target = hscTarget dflags - hpcInfo = emptyHpcInfo other_hpc_info - - ; (binds_cvr, ds_hpc_info, modBreaks) - <- if not (isHsBootOrSig hsc_src) - then addTicksToBinds hsc_env mod mod_loc - export_set (typeEnvTyCons type_env) binds - else return (binds, hpcInfo, Nothing) - ; (msgs, mb_res) <- initDs hsc_env tcg_env $ - do { ds_ev_binds <- dsEvBinds ev_binds - ; core_prs <- dsTopLHsBinds binds_cvr - ; (spec_prs, spec_rules) <- dsImpSpecs imp_specs - ; (ds_fords, foreign_prs) <- dsForeigns fords - ; ds_rules <- mapMaybeM dsRule rules - ; let hpc_init - | gopt Opt_Hpc dflags = hpcInitCode mod ds_hpc_info - | otherwise = empty - ; return ( ds_ev_binds - , foreign_prs `appOL` core_prs `appOL` spec_prs - , spec_rules ++ ds_rules - , ds_fords `appendStubC` hpc_init) } - - ; case mb_res of { - Nothing -> return (msgs, Nothing) ; - Just (ds_ev_binds, all_prs, all_rules, ds_fords) -> - - do { -- Add export flags to bindings - keep_alive <- readIORef keep_var - ; 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#! - - ; endPassIO hsc_env print_unqual CoreDesugar final_pgm rules_for_imps - ; (ds_binds, ds_rules_for_imps) - <- simpleOptPgm dflags mod final_pgm rules_for_imps - -- The simpleOptPgm gets rid of type - -- bindings plus any stupid dead code - - ; endPassIO hsc_env print_unqual CoreDesugarOpt ds_binds ds_rules_for_imps - - ; let used_names = mkUsedNames tcg_env - pluginModules = - map lpModule (cachedPlugins (hsc_dflags hsc_env)) - ; deps <- mkDependencies (thisInstalledUnitId (hsc_dflags hsc_env)) - (map mi_module pluginModules) tcg_env - - ; used_th <- readIORef tc_splice_used - ; dep_files <- readIORef dependent_files - ; safe_mode <- finalSafeMode dflags tcg_env - ; usages <- mkUsageInfo hsc_env mod (imp_mods imports) used_names - dep_files merged pluginModules - -- id_mod /= mod when we are processing an hsig, but hsigs - -- never desugared and compiled (there's no code!) - -- Consequently, this should hold for any ModGuts that make - -- past desugaring. See Note [Identity versus semantic module]. - ; MASSERT( id_mod == mod ) - - ; foreign_files <- readIORef th_foreign_files_var - - ; let (doc_hdr, decl_docs, arg_docs) = extractDocs tcg_env - - ; let mod_guts = ModGuts { - mg_module = mod, - mg_hsc_src = hsc_src, - mg_loc = mkFileSrcSpan mod_loc, - mg_exports = exports, - mg_usages = usages, - mg_deps = deps, - mg_used_th = used_th, - mg_rdr_env = rdr_env, - mg_fix_env = fix_env, - mg_warns = warns, - mg_anns = anns, - mg_tcs = tcs, - mg_insts = fixSafeInstances safe_mode insts, - mg_fam_insts = fam_insts, - mg_inst_env = inst_env, - mg_fam_inst_env = fam_inst_env, - mg_patsyns = patsyns, - mg_rules = ds_rules_for_imps, - mg_binds = ds_binds, - mg_foreign = ds_fords, - mg_foreign_files = foreign_files, - mg_hpc_info = ds_hpc_info, - mg_modBreaks = modBreaks, - mg_safe_haskell = safe_mode, - mg_trust_pkg = imp_trust_own_pkg imports, - mg_complete_sigs = complete_matches, - mg_doc_hdr = doc_hdr, - mg_decl_docs = decl_docs, - mg_arg_docs = arg_docs - } - ; return (msgs, Just mod_guts) - }}}} - -mkFileSrcSpan :: ModLocation -> SrcSpan -mkFileSrcSpan mod_loc - = case ml_hs_file mod_loc of - Just file_path -> mkGeneralSrcSpan (mkFastString file_path) - Nothing -> interactiveSrcSpan -- Presumably - -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 :: [CoreBind] -> [(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 (NonRec b r : bs) val_prs - | isId b = combineEvBinds bs ((b,r):val_prs) - | otherwise = NonRec b r : combineEvBinds bs val_prs -combineEvBinds (Rec prs : bs) val_prs - = combineEvBinds bs (prs ++ val_prs) - -{- -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 take 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. --} - -deSugarExpr :: HscEnv -> LHsExpr GhcTc -> IO (Messages, Maybe CoreExpr) - -deSugarExpr hsc_env tc_expr = do { - let dflags = hsc_dflags hsc_env - - ; showPass dflags "Desugar" - - -- Do desugaring - ; (msgs, mb_core_expr) <- runTcInteractive hsc_env $ initDsTc $ - dsLExpr tc_expr - - ; case mb_core_expr of - Nothing -> return () - Just expr -> dumpIfSet_dyn dflags Opt_D_dump_ds "Desugared" - FormatCore (pprCoreExpr expr) - - ; return (msgs, mb_core_expr) } - -{- -************************************************************************ -* * -* Add rules and export flags to binders -* * -************************************************************************ --} - -addExportFlagsAndRules - :: HscTarget -> NameSet -> NameSet -> [CoreRule] - -> [(Id, t)] -> [(Id, t)] -addExportFlagsAndRules target exports keep_alive rules prs - = mapFst add_one prs - where - 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 :: Name -> Bool - dont_discard name = is_exported name - || name `elemNameSet` keep_alive - - -- In interactive mode, we don't want to discard any top-level - -- entities at all (eg. do not inline them away during - -- simplification), and retain them all in the TypeEnv so they are - -- available from the command line. - -- - -- isExternalName separates the user-defined top-level names from those - -- introduced by the type checker. - is_exported :: Name -> Bool - is_exported | targetRetainsAllBindings target = isExternalName - | otherwise = (`elemNameSet` exports) - -{- -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 - - -************************************************************************ -* * -* Desugaring transformation rules -* * -************************************************************************ --} - -dsRule :: LRuleDecl GhcTc -> DsM (Maybe CoreRule) -dsRule (L loc (HsRule { rd_name = name - , rd_act = rule_act - , rd_tmvs = vars - , rd_lhs = lhs - , rd_rhs = rhs })) - = putSrcSpanDs loc $ - do { let bndrs' = [var | L _ (RuleBndr _ (L _ var)) <- vars] - - ; lhs' <- unsetGOptM Opt_EnableRewriteRules $ - unsetWOptM Opt_WarnIdentities $ - dsLExpr lhs -- Note [Desugaring RULE left hand sides] - - ; rhs' <- dsLExpr rhs - ; this_mod <- getModule - - ; (bndrs'', lhs'', rhs'') <- unfold_coerce bndrs' lhs' rhs' - - -- Substitute the dict bindings eagerly, - -- and take the body apart into a (f args) form - ; dflags <- getDynFlags - ; case decomposeRuleLhs dflags bndrs'' lhs'' of { - Left msg -> do { warnDs NoReason 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 because - -- 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 - final_rhs = simpleOptExpr dflags rhs'' -- De-crap it - rule_name = snd (unLoc name) - final_bndrs_set = mkVarSet final_bndrs - arg_ids = filterOut (`elemVarSet` final_bndrs_set) $ - exprsSomeFreeVarsList isId args - - ; rule <- dsMkUserRule this_mod is_local - rule_name rule_act fn_name final_bndrs args - final_rhs - ; when (wopt Opt_WarnInlineRuleShadowing dflags) $ - warnRuleShadowing rule_name rule_act fn_id arg_ids - - ; return (Just rule) - } } } -dsRule (L _ (XRuleDecl nec)) = noExtCon nec - -warnRuleShadowing :: RuleName -> Activation -> Id -> [Id] -> DsM () --- See Note [Rules and inlining/other rules] -warnRuleShadowing rule_name rule_act fn_id arg_ids - = do { check False fn_id -- We often have multiple rules for the same Id in a - -- module. Maybe we should check that they don't overlap - -- but currently we don't - ; mapM_ (check True) arg_ids } - where - check check_rules_too lhs_id - | isLocalId lhs_id || canUnfold (idUnfolding lhs_id) - -- If imported with no unfolding, no worries - , idInlineActivation lhs_id `competesWith` rule_act - = warnDs (Reason Opt_WarnInlineRuleShadowing) - (vcat [ hang (text "Rule" <+> pprRuleName rule_name - <+> text "may never fire") - 2 (text "because" <+> quotes (ppr lhs_id) - <+> text "might inline first") - , text "Probable fix: add an INLINE[n] or NOINLINE[n] pragma for" - <+> quotes (ppr lhs_id) - , whenPprDebug (ppr (idInlineActivation lhs_id) $$ ppr rule_act) ]) - - | check_rules_too - , bad_rule : _ <- get_bad_rules lhs_id - = warnDs (Reason Opt_WarnInlineRuleShadowing) - (vcat [ hang (text "Rule" <+> pprRuleName rule_name - <+> text "may never fire") - 2 (text "because rule" <+> pprRuleName (ruleName bad_rule) - <+> text "for"<+> quotes (ppr lhs_id) - <+> text "might fire first") - , text "Probable fix: add phase [n] or [~n] to the competing rule" - , whenPprDebug (ppr bad_rule) ]) - - | otherwise - = return () - - get_bad_rules lhs_id - = [ rule | rule <- idCoreRules lhs_id - , ruleActivation rule `competesWith` rule_act ] - --- See Note [Desugaring coerce as cast] -unfold_coerce :: [Id] -> CoreExpr -> CoreExpr -> DsM ([Var], CoreExpr, CoreExpr) -unfold_coerce bndrs lhs rhs = do - (bndrs', wrap) <- go bndrs - return (bndrs', wrap lhs, wrap rhs) - where - go :: [Id] -> DsM ([Id], CoreExpr -> CoreExpr) - go [] = return ([], id) - go (v:vs) - | Just (tc, [k, t1, t2]) <- splitTyConApp_maybe (idType v) - , tc `hasKey` coercibleTyConKey = do - u <- newUnique - - let ty' = mkTyConApp eqReprPrimTyCon [k, k, t1, t2] - v' = mkLocalCoVar - (mkDerivedInternalName mkRepEqOcc u (getName v)) ty' - box = Var (dataConWrapId coercibleDataCon) `mkTyApps` - [k, t1, t2] `App` - Coercion (mkCoVarCo v') - - (bndrs, wrap) <- go vs - return (v':bndrs, mkCoreLet (NonRec v box) . wrap) - | otherwise = do - (bndrs,wrap) <- go vs - return (v:bndrs, wrap) - -{- 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 precisely to optimise them: - {-# RULES "fromRational/id" fromRational = id :: Rational -> Rational #-} - -Note [Desugaring coerce as cast] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -We want the user to express a rule saying roughly “mapping a coercion over a -list can be replaced by a coercion”. But the cast operator of Core (▷) cannot -be written in Haskell. So we use `coerce` for that (#2110). The user writes - map coerce = coerce -as a RULE, and this optimizes any kind of mapped' casts away, including `map -MkNewtype`. - -For that we replace any forall'ed `c :: Coercible a b` value in a RULE by -corresponding `co :: a ~#R b` and wrap the LHS and the RHS in -`let c = MkCoercible co in ...`. This is later simplified to the desired form -by simpleOptExpr (for the LHS) resp. the simplifiers (for the RHS). -See also Note [Getting the map/coerce RULE to work] in CoreSubst. - -Note [Rules and inlining/other rules] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If you have - f x = ... - g x = ... - {-# RULES "rule-for-f" forall x. f (g x) = ... #-} -then there's a good chance that in a potential rule redex - ...f (g e)... -then 'f' or 'g' will inline before the rule can fire. Solution: add an -INLINE [n] or NOINLINE [n] pragma to 'f' and 'g'. - -Note that this applies to all the free variables on the LHS, both the -main function and things in its arguments. - -We also check if there are Ids on the LHS that have competing RULES. -In the above example, suppose we had - {-# RULES "rule-for-g" forally. g [y] = ... #-} -Then "rule-for-f" and "rule-for-g" would compete. Better to add phase -control, so "rule-for-f" has a chance to fire before "rule-for-g" becomes -active; or perhaps after "rule-for-g" has become inactive. This is checked -by 'competesWith' - -Class methods have a built-in RULE to select the method from the dictionary, -so you can't change the phase on this. That makes id very dubious to -match on class methods in RULE lhs's. See #10595. I'm not happy -about this. For example in Control.Arrow we have - -{-# RULES "compose/arr" forall f g . - (arr f) . (arr g) = arr (f . g) #-} - -and similar, which will elicit exactly these warnings, and risk never -firing. But it's not clear what to do instead. We could make the -class method rules inactive in phase 2, but that would delay when -subsequent transformations could fire. --} |
