-\begin{code}
-mkCharExpr :: Char -> CoreExpr -- Returns C# c :: Int
-mkIntExpr :: Integer -> CoreExpr -- Returns I# i :: Int
-mkIntegerExpr :: Integer -> DsM CoreExpr -- Result :: Integer
-mkStringExpr :: String -> DsM CoreExpr -- Result :: String
-mkStringExprFS :: FastString -> DsM CoreExpr -- Result :: String
-
-mkIntExpr i = mkConApp intDataCon [mkIntLit i]
-mkCharExpr c = mkConApp charDataCon [mkLit (MachChar c)]
-
-mkIntegerExpr i
- | inIntRange i -- Small enough, so start from an Int
- = dsLookupDataCon smallIntegerDataConName `thenDs` \ integer_dc ->
- returnDs (mkSmallIntegerLit integer_dc i)
-
--- Special case for integral literals with a large magnitude:
--- They are transformed into an expression involving only smaller
--- integral literals. This improves constant folding.
-
- | otherwise -- Big, so start from a string
- = dsLookupGlobalId plusIntegerName `thenDs` \ plus_id ->
- dsLookupGlobalId timesIntegerName `thenDs` \ times_id ->
- dsLookupDataCon smallIntegerDataConName `thenDs` \ integer_dc ->
- let
- lit i = mkSmallIntegerLit integer_dc i
- plus a b = Var plus_id `App` a `App` b
- times a b = Var times_id `App` a `App` b
-
- -- Transform i into (x1 + (x2 + (x3 + (...) * b) * b) * b) with abs xi <= b
- horner :: Integer -> Integer -> CoreExpr
- horner b i | abs q <= 1 = if r == 0 || r == i
- then lit i
- else lit r `plus` lit (i-r)
- | r == 0 = horner b q `times` lit b
- | otherwise = lit r `plus` (horner b q `times` lit b)
- where
- (q,r) = i `quotRem` b
-
- in
- returnDs (horner tARGET_MAX_INT i)
-
-mkSmallIntegerLit small_integer_data_con i = mkConApp small_integer_data_con [mkIntLit i]
-
-mkStringExpr str = mkStringExprFS (mkFastString str)
-
-mkStringExprFS str
- | nullFS str
- = returnDs (mkNilExpr charTy)
-
- | lengthFS str == 1
- = let
- the_char = mkCharExpr (headFS str)
- in
- returnDs (mkConsExpr charTy the_char (mkNilExpr charTy))
-
- | all safeChar chars
- = dsLookupGlobalId unpackCStringName `thenDs` \ unpack_id ->
- returnDs (App (Var unpack_id) (Lit (MachStr str)))
-
- | otherwise
- = dsLookupGlobalId unpackCStringUtf8Name `thenDs` \ unpack_id ->
- returnDs (App (Var unpack_id) (Lit (MachStr str)))
+The [CoreSyn let/app invariant] means that, other things being equal, because
+the argument to the outer 'seq' has an unlifted type, we'll use call-by-value thus:
+
+ f x y = case (y `seq` (# x,y #)) of v -> x `seq` v
+
+But that is bad for two reasons:
+ (a) we now evaluate y before x, and
+ (b) we can't bind v to an unboxed pair
+
+Seq is very, very special! So we recognise it right here, and desugar to
+ case x of _ -> case y of _ -> (# x,y #)
+
+Note [Desugaring seq (2)] cf Trac #2273
+~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider
+ let chp = case b of { True -> fst x; False -> 0 }
+ in chp `seq` ...chp...
+Here the seq is designed to plug the space leak of retaining (snd x)
+for too long.
+
+If we rely on the ordinary inlining of seq, we'll get
+ let chp = case b of { True -> fst x; False -> 0 }
+ case chp of _ { I# -> ...chp... }
+
+But since chp is cheap, and the case is an alluring contet, we'll
+inline chp into the case scrutinee. Now there is only one use of chp,
+so we'll inline a second copy. Alas, we've now ruined the purpose of
+the seq, by re-introducing the space leak:
+ case (case b of {True -> fst x; False -> 0}) of
+ I# _ -> ...case b of {True -> fst x; False -> 0}...
+
+We can try to avoid doing this by ensuring that the binder-swap in the
+case happens, so we get his at an early stage:
+ case chp of chp2 { I# -> ...chp2... }
+But this is fragile. The real culprit is the source program. Perhaps we
+should have said explicitly
+ let !chp2 = chp in ...chp2...
+
+But that's painful. So the code here does a little hack to make seq
+more robust: a saturated application of 'seq' is turned *directly* into
+the case expression, thus:
+ x `seq` e2 ==> case x of x -> e2 -- Note shadowing!
+ e1 `seq` e2 ==> case x of _ -> e2
+
+So we desugar our example to:
+ let chp = case b of { True -> fst x; False -> 0 }
+ case chp of chp { I# -> ...chp... }
+And now all is well.
+
+The reason it's a hack is because if you define mySeq=seq, the hack
+won't work on mySeq.
+
+Note [Desugaring seq (3)] cf Trac #2409
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The isLocalId ensures that we don't turn
+ True `seq` e
+into
+ case True of True { ... }
+which stupidly tries to bind the datacon 'True'.