Refine incomplete-pattern checks (Trac #4905)
[ghc-hetmet.git] / compiler / simplCore / Simplify.lhs
index 7222703..6fe24df 100644 (file)
@@ -28,9 +28,7 @@ import CoreMonad        ( Tick(..), SimplifierMode(..) )
 import CoreSyn
 import Demand           ( isStrictDmd )
 import PprCore          ( pprParendExpr, pprCoreExpr )
-import CoreUnfold       ( mkUnfolding, mkCoreUnfolding
-                        , mkInlineUnfolding, mkSimpleUnfolding
-                        , exprIsConApp_maybe, callSiteInline, CallCtxt(..) )
+import CoreUnfold 
 import CoreUtils
 import qualified CoreSubst
 import CoreArity
@@ -638,7 +636,7 @@ completeBind env top_lvl old_bndr new_bndr new_rhs
       ; (new_arity, final_rhs) <- tryEtaExpand env new_bndr new_rhs
 
        -- Simplify the unfolding
-      ; new_unfolding <- simplUnfolding env top_lvl old_bndr occ_info final_rhs old_unf
+      ; new_unfolding <- simplUnfolding env top_lvl old_bndr final_rhs old_unf
 
       ; if postInlineUnconditionally env top_lvl new_bndr occ_info final_rhs new_unfolding
                        -- Inline and discard the binding
@@ -678,7 +676,7 @@ addPolyBind :: TopLevelFlag -> SimplEnv -> OutBind -> SimplM SimplEnv
 -- opportunity to inline 'y' too.
 
 addPolyBind top_lvl env (NonRec poly_id rhs)
-  = do { unfolding <- simplUnfolding env top_lvl poly_id NoOccInfo rhs noUnfolding
+  = do  { unfolding <- simplUnfolding env top_lvl poly_id rhs noUnfolding
                        -- Assumes that poly_id did not have an INLINE prag
                        -- which is perhaps wrong.  ToDo: think about this
         ; let final_id = setIdInfo poly_id $
@@ -695,16 +693,16 @@ addPolyBind _ env bind@(Rec _)
 
 ------------------------------
 simplUnfolding :: SimplEnv-> TopLevelFlag
-              -> Id
-              -> OccInfo -> OutExpr
+               -> InId
+               -> OutExpr
               -> Unfolding -> SimplM Unfolding
 -- Note [Setting the new unfolding]
-simplUnfolding env _ _ _ _ (DFunUnfolding ar con ops)
+simplUnfolding env _ _ _ (DFunUnfolding ar con ops)
   = return (DFunUnfolding ar con ops')
   where
     ops' = map (fmap (substExpr (text "simplUnfolding") env)) ops
 
-simplUnfolding env top_lvl id _ _ 
+simplUnfolding env top_lvl id _
     (CoreUnfolding { uf_tmpl = expr, uf_arity = arity
                    , uf_src = src, uf_guidance = guide })
   | isStableSource src
@@ -712,36 +710,46 @@ simplUnfolding env top_lvl id _ _
        ; let src' = CoreSubst.substUnfoldingSource (mkCoreSubst (text "inline-unf") env) src
              is_top_lvl = isTopLevel top_lvl
        ; case guide of
-           UnfIfGoodArgs{} ->
-              -- We need to force bottoming, or the new unfolding holds
-              -- on to the old unfolding (which is part of the id).
-              let bottoming = isBottomingId id
-              in bottoming `seq` return (mkUnfolding src' is_top_lvl bottoming expr')
+           UnfWhen sat_ok _    -- Happens for INLINE things
+              -> let guide' = UnfWhen sat_ok (inlineBoringOk expr')
+                    -- Refresh the boring-ok flag, in case expr'
+                    -- has got small. This happens, notably in the inlinings
+                    -- for dfuns for single-method classes; see
+                    -- Note [Single-method classes] in TcInstDcls.
+                    -- A test case is Trac #4138
+                 in return (mkCoreUnfolding src' is_top_lvl expr' arity guide')
+                -- See Note [Top-level flag on inline rules] in CoreUnfold
+
+           _other              -- Happens for INLINABLE things
+              -> let bottoming = isBottomingId id
+                 in bottoming `seq` -- See Note [Force bottoming field]
+                    return (mkUnfolding src' is_top_lvl bottoming expr')
                 -- If the guidance is UnfIfGoodArgs, this is an INLINABLE
                 -- unfolding, and we need to make sure the guidance is kept up
                 -- to date with respect to any changes in the unfolding.
-           _other -> 
-              return (mkCoreUnfolding src' is_top_lvl expr' arity guide)
-               -- See Note [Top-level flag on inline rules] in CoreUnfold
        }
   where
     act      = idInlineActivation id
     rule_env = updMode (updModeForInlineRules act) env
                       -- See Note [Simplifying inside InlineRules] in SimplUtils
 
-simplUnfolding _ top_lvl id _occ_info new_rhs _
-  = -- We need to force bottoming, or the new unfolding holds
-    -- on to the old unfolding (which is part of the id).
-    let bottoming = isBottomingId id
-    in bottoming `seq` return (mkUnfolding InlineRhs (isTopLevel top_lvl) bottoming new_rhs)
-  -- We make an  unfolding *even for loop-breakers*.
-  -- Reason: (a) It might be useful to know that they are WHNF
-  --        (b) In TidyPgm we currently assume that, if we want to
-  --            expose the unfolding then indeed we *have* an unfolding
-  --            to expose.  (We could instead use the RHS, but currently
-  --            we don't.)  The simple thing is always to have one.
+simplUnfolding _ top_lvl id new_rhs _
+  = let bottoming = isBottomingId id
+    in bottoming `seq`  -- See Note [Force bottoming field]
+       return (mkUnfolding InlineRhs (isTopLevel top_lvl) bottoming new_rhs)
+         -- We make an  unfolding *even for loop-breakers*.
+         -- Reason: (a) It might be useful to know that they are WHNF
+         --         (b) In TidyPgm we currently assume that, if we want to
+         --             expose the unfolding then indeed we *have* an unfolding
+         --             to expose.  (We could instead use the RHS, but currently
+         --             we don't.)  The simple thing is always to have one.
 \end{code}
 
+Note [Force bottoming field]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We need to force bottoming, or the new unfolding holds
+on to the old unfolding (which is part of the id).
+
 Note [Arity decrease]
 ~~~~~~~~~~~~~~~~~~~~~
 Generally speaking the arity of a binding should not decrease.  But it *can* 
@@ -1052,6 +1060,19 @@ simplCast env body co0 cont0
 %*                                                                      *
 %************************************************************************
 
+Note [Zap unfolding when beta-reducing]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Lambda-bound variables can have stable unfoldings, such as
+   $j = \x. \b{Unf=Just x}. e
+See Note [Case binders and join points] below; the unfolding for lets
+us optimise e better.  However when we beta-reduce it we want to
+revert to using the actual value, otherwise we can end up in the
+stupid situation of
+          let x = blah in
+          let b{Unf=Just x} = y
+          in ...b...
+Here it'd be far better to drop the unfolding and use the actual RHS.
+
 \begin{code}
 simplLam :: SimplEnv -> [InId] -> InExpr -> SimplCont
          -> SimplM (SimplEnv, OutExpr)
@@ -1061,7 +1082,12 @@ simplLam env [] body cont = simplExprF env body cont
         -- Beta reduction
 simplLam env (bndr:bndrs) body (ApplyTo _ arg arg_se cont)
   = do  { tick (BetaReduction bndr)
-        ; simplNonRecE env bndr (arg, arg_se) (bndrs, body) cont }
+        ; simplNonRecE env (zap_unfolding bndr) (arg, arg_se) (bndrs, body) cont }
+  where
+    zap_unfolding bndr  -- See Note [Zap unfolding when beta-reducing]
+      | isId bndr, isStableUnfolding (realIdUnfolding bndr)
+      = setIdUnfolding bndr NoUnfolding
+      | otherwise = bndr
 
         -- Not enough args, so there are real lambdas left to put in the result
 simplLam env bndrs body cont
@@ -1394,7 +1420,7 @@ So it's up to the programmer: rules can cause divergence
 
 %************************************************************************
 %*                                                                      *
-                Rebuilding a cse expression
+                Rebuilding a case expression
 %*                                                                      *
 %************************************************************************
 
@@ -1403,7 +1429,7 @@ Note [Case elimination]
 The case-elimination transformation discards redundant case expressions.
 Start with a simple situation:
 
-        case x# of      ===>   e[x#/y#]
+        case x# of      ===>   let y# = x# in e
           y# -> e
 
 (when x#, y# are of primitive type, of course).  We can't (in general)
@@ -1424,29 +1450,40 @@ Here the inner case is first trimmed to have only one alternative, the
 DEFAULT, after which it's an instance of the previous case.  This
 really only shows up in eliminating error-checking code.
 
-We also make sure that we deal with this very common case:
-
-        case e of
-          x -> ...x...
-
-Here we are using the case as a strict let; if x is used only once
-then we want to inline it.  We have to be careful that this doesn't
-make the program terminate when it would have diverged before, so we
-check that
-        - e is already evaluated (it may so if e is a variable)
-        - x is used strictly, or
-
-Lastly, the code in SimplUtils.mkCase combines identical RHSs.  So
+Note that SimplUtils.mkCase combines identical RHSs.  So
 
         case e of       ===> case e of DEFAULT -> r
            True  -> r
            False -> r
 
 Now again the case may be elminated by the CaseElim transformation.
+This includes things like (==# a# b#)::Bool so that we simplify
+      case ==# a# b# of { True -> x; False -> x }
+to just
+      x
+This particular example shows up in default methods for
+comparision operations (e.g. in (>=) for Int.Int32)
 
 Note [CaseElimination: lifted case]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We do not use exprOkForSpeculation in the lifted case.  Consider
+We also make sure that we deal with this very common case,
+where x has a lifted type:
+
+        case e of
+          x -> ...x...
+
+Here we are using the case as a strict let; if x is used only once
+then we want to inline it.  We have to be careful that this doesn't
+make the program terminate when it would have diverged before, so we
+check that
+        (a) 'e' is already evaluated (it may so if e is a variable)
+           Specifically we check (exprIsHNF e)
+or
+        (b) the scrutinee is a variable and 'x' is used strictly
+or
+        (c) 'x' is not used at all and e is ok-for-speculation
+
+For the (c), consider
    case (case a ># b of { True -> (p,q); False -> (q,p) }) of
      r -> blah
 The scrutinee is ok-for-speculation (it looks inside cases), but we do
@@ -1546,33 +1583,33 @@ rebuildCase env scrut case_bndr [(_, bndrs, rhs)] cont
   -- then there is now only one (DEFAULT) rhs
  | all isDeadBinder bndrs       -- bndrs are [InId]
 
-        -- Check that the scrutinee can be let-bound instead of case-bound
  , if isUnLiftedType (idType case_bndr)
-   then exprOkForSpeculation scrut
-        -- Satisfy the let-binding invariant
-        -- This includes things like (==# a# b#)::Bool
-        -- so that we simplify
-        --      case ==# a# b# of { True -> x; False -> x }
-        -- to just
-        --      x
-        -- This particular example shows up in default methods for
-        -- comparision operations (e.g. in (>=) for Int.Int32)
-
-   else exprIsHNF scrut || var_demanded_later scrut
-        -- It's already evaluated, or will be demanded later
-        -- See Note [Case elimination: lifted case]
+   then ok_for_spec         -- Satisfy the let-binding invariant
+   else elim_lifted
   = do  { tick (CaseElim case_bndr)
         ; env' <- simplNonRecX env case_bndr scrut
           -- If case_bndr is deads, simplNonRecX will discard
         ; simplExprF env' rhs cont }
   where
-        -- The case binder is going to be evaluated later,
-        -- and the scrutinee is a simple variable
-    var_demanded_later (Var v) = isStrictDmd (idDemandInfo case_bndr)
-                                 && not (isTickBoxOp v)
+    elim_lifted   -- See Note [Case elimination: lifted case]
+      = exprIsHNF scrut
+     || (strict_case_bndr && scrut_is_var scrut) 
+              -- The case binder is going to be evaluated later,
+              -- and the scrutinee is a simple variable
+
+     || (is_plain_seq && ok_for_spec)
+              -- Note: not the same as exprIsHNF
+
+    ok_for_spec      = exprOkForSpeculation scrut
+    is_plain_seq     = isDeadBinder case_bndr  -- Evaluation *only* for effect
+    strict_case_bndr = isStrictDmd (idDemandInfo case_bndr)
+
+    scrut_is_var (Cast s _) = scrut_is_var s
+    scrut_is_var (Var v)    = not (isTickBoxOp v)
                                     -- ugly hack; covering this case is what
                                     -- exprOkForSpeculation was intended for.
-    var_demanded_later _       = False
+    scrut_is_var _          = False
+
 
 --------------------------------------------------
 --      3. Try seq rules; see Note [User-defined RULES for seq] in MkId
@@ -1738,7 +1775,7 @@ improveSeq :: (FamInstEnv, FamInstEnv) -> SimplEnv
           -> SimplM (SimplEnv, OutExpr, OutId)
 -- Note [Improving seq]
 improveSeq fam_envs env scrut case_bndr case_bndr1 [(DEFAULT,_,_)]
-  | not (isDeadBinder case_bndr)       -- Not a pure seq!  See the Note!
+  | not (isDeadBinder case_bndr)       -- Not a pure seq!  See Note [Improving seq]
   , Just (co, ty2) <- topNormaliseType fam_envs (idType case_bndr1)
   = do { case_bndr2 <- newId (fsLit "nt") ty2
         ; let rhs  = DoneEx (Var case_bndr2 `Cast` mkSymCoercion co)