summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Peyton Jones <simonpj@microsoft.com>2011-11-09 23:32:20 +0000
committerSimon Peyton Jones <simonpj@microsoft.com>2011-11-09 23:32:20 +0000
commitf96db3ca8a7c83cc3da242fad761fb05543068f6 (patch)
tree5477bd92619eab7d4abe97f4ca55274d3c264d0f
parent2d5a1a5b14d636c3b248821da6a444fd02f74b8e (diff)
downloadhaskell-f96db3ca8a7c83cc3da242fad761fb05543068f6.tar.gz
Establish the invariant that (LitAlt l) is always unlifted
...and make sure it is, esp in the call to findAlt in the mighty Simplifier. Failing to check this led to searching a bunch of DataAlts for a LitAlt Integer. Naughty. See Trac #5603 for a case in point.
-rw-r--r--compiler/basicTypes/Literal.lhs6
-rw-r--r--compiler/coreSyn/CoreLint.lhs13
-rw-r--r--compiler/coreSyn/CoreSyn.lhs30
-rw-r--r--compiler/deSugar/DsUtils.lhs8
-rw-r--r--compiler/prelude/PrelRules.lhs3
-rw-r--r--compiler/simplCore/Simplify.lhs2
-rw-r--r--compiler/specialise/SpecConstr.lhs4
7 files changed, 49 insertions, 17 deletions
diff --git a/compiler/basicTypes/Literal.lhs b/compiler/basicTypes/Literal.lhs
index 417444542a..966dca1e71 100644
--- a/compiler/basicTypes/Literal.lhs
+++ b/compiler/basicTypes/Literal.lhs
@@ -33,7 +33,7 @@ module Literal
, pprLiteral
-- ** Predicates on Literals and their contents
- , litIsDupable, litIsTrivial
+ , litIsDupable, litIsTrivial, litIsLifted
, inIntRange, inWordRange, tARGET_MAX_INT, inCharRange
, isZeroLit
, litFitsInChar
@@ -368,6 +368,10 @@ litFitsInChar (MachInt i)
= fromInteger i <= ord minBound
&& fromInteger i >= ord maxBound
litFitsInChar _ = False
+
+litIsLifted :: Literal -> Bool
+litIsLifted (LitInteger {}) = True
+litIsLifted _ = False
\end{code}
Types
diff --git a/compiler/coreSyn/CoreLint.lhs b/compiler/coreSyn/CoreLint.lhs
index 9351da1716..457af3366d 100644
--- a/compiler/coreSyn/CoreLint.lhs
+++ b/compiler/coreSyn/CoreLint.lhs
@@ -41,7 +41,6 @@ import Kind
import Type
import TypeRep
import TyCon
-import TcType
import BasicTypes
import StaticFlags
import ListSetOps
@@ -526,12 +525,12 @@ lintCoreAlt _ alt_ty (DEFAULT, args, rhs) =
; checkAltExpr rhs alt_ty }
lintCoreAlt scrut_ty alt_ty (LitAlt lit, args, rhs)
- | isIntegerTy scrut_ty
- = failWithL integerScrutinisedMsg
+ | litIsLifted lit
+ = failWithL integerScrutinisedMsg
| otherwise
- = do { checkL (null args) (mkDefaultArgsMsg args)
- ; checkTys lit_ty scrut_ty (mkBadPatMsg lit_ty scrut_ty)
- ; checkAltExpr rhs alt_ty }
+ = do { checkL (null args) (mkDefaultArgsMsg args)
+ ; checkTys lit_ty scrut_ty (mkBadPatMsg lit_ty scrut_ty)
+ ; checkAltExpr rhs alt_ty }
where
lit_ty = literalType lit
@@ -1089,7 +1088,7 @@ mkBadPatMsg con_result_ty scrut_ty
integerScrutinisedMsg :: Message
integerScrutinisedMsg
- = text "In a case alternative, scrutinee type is Integer"
+ = text "In a LitAlt, the literal is lifted (probably Integer)"
mkBadAltMsg :: Type -> CoreAlt -> Message
mkBadAltMsg scrut_ty alt
diff --git a/compiler/coreSyn/CoreSyn.lhs b/compiler/coreSyn/CoreSyn.lhs
index ea0ef2242f..a8dbbceb36 100644
--- a/compiler/coreSyn/CoreSyn.lhs
+++ b/compiler/coreSyn/CoreSyn.lhs
@@ -278,11 +278,16 @@ type Arg b = Expr b
type Alt b = (AltCon, [b], Expr b)
-- | A case alternative constructor (i.e. pattern match)
-data AltCon = DataAlt DataCon -- ^ A plain data constructor: @case e of { Foo x -> ... }@.
- -- Invariant: the 'DataCon' is always from a @data@ type, and never from a @newtype@
- | LitAlt Literal -- ^ A literal: @case e of { 1 -> ... }@
- | DEFAULT -- ^ Trivial alternative: @case e of { _ -> ... }@
- deriving (Eq, Ord, Data, Typeable)
+data AltCon
+ = DataAlt DataCon -- ^ A plain data constructor: @case e of { Foo x -> ... }@.
+ -- Invariant: the 'DataCon' is always from a @data@ type, and never from a @newtype@
+
+ | LitAlt Literal -- ^ A literal: @case e of { 1 -> ... }@
+ -- Invariant: always an *unlifted* literal
+ -- See Note [Literal alternatives]
+
+ | DEFAULT -- ^ Trivial alternative: @case e of { _ -> ... }@
+ deriving (Eq, Ord, Data, Typeable)
-- | Binding, used for top level bindings in a module and local bindings in a @let@.
data Bind b = NonRec b (Expr b)
@@ -290,6 +295,21 @@ data Bind b = NonRec b (Expr b)
deriving (Data, Typeable)
\end{code}
+Note [Literal alternatives]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Literal alternatives (LitAlt lit) are always for *un-lifted* literals.
+We have one literal, a literal Integer, that is lifted, and we don't
+allow in a LitAlt, because LitAlt cases don't do any evaluation. Also
+(see Trac #5603) if you say
+ case 3 of
+ S# x -> ...
+ J# _ _ -> ...
+(where S#, J# are the constructors for Integer) we don't want the
+simplifier calling findAlt with argument (LitAlt 3). No no. Integer
+literals are an opaque encoding of an algebraic data type, not of
+an unlifted literal, like all the others.
+
+
-------------------------- CoreSyn INVARIANTS ---------------------------
Note [CoreSyn top-level invariant]
diff --git a/compiler/deSugar/DsUtils.lhs b/compiler/deSugar/DsUtils.lhs
index dc3f99bbbc..13994757f8 100644
--- a/compiler/deSugar/DsUtils.lhs
+++ b/compiler/deSugar/DsUtils.lhs
@@ -291,7 +291,7 @@ mkGuardedMatchResult pred_expr (MatchResult _ body_fn)
mkCoPrimCaseMatchResult :: Id -- Scrutinee
-> Type -- Type of the case
-> [(Literal, MatchResult)] -- Alternatives
- -> MatchResult
+ -> MatchResult -- Literals are all unlifted
mkCoPrimCaseMatchResult var ty match_alts
= MatchResult CanFail mk_case
where
@@ -300,8 +300,10 @@ mkCoPrimCaseMatchResult var ty match_alts
return (Case (Var var) var ty ((DEFAULT, [], fail) : alts))
sorted_alts = sortWith fst match_alts -- Right order for a Case
- mk_alt fail (lit, MatchResult _ body_fn) = do body <- body_fn fail
- return (LitAlt lit, [], body)
+ mk_alt fail (lit, MatchResult _ body_fn)
+ = ASSERT( not (litIsLifted lit) )
+ do body <- body_fn fail
+ return (LitAlt lit, [], body)
mkCoAlgCaseMatchResult
diff --git a/compiler/prelude/PrelRules.lhs b/compiler/prelude/PrelRules.lhs
index 4e39966183..40ee5b0850 100644
--- a/compiler/prelude/PrelRules.lhs
+++ b/compiler/prelude/PrelRules.lhs
@@ -348,6 +348,9 @@ litEq op_name is_eq
rule_fn _ _ = Nothing
do_lit_eq lit expr
+ | litIsLifted lit
+ = Nothing
+ | otherwise
= Just (mkWildCase expr (literalType lit) boolTy
[(DEFAULT, [], val_if_neq),
(LitAlt lit, [], val_if_eq)])
diff --git a/compiler/simplCore/Simplify.lhs b/compiler/simplCore/Simplify.lhs
index 0a9d388b7f..61431be874 100644
--- a/compiler/simplCore/Simplify.lhs
+++ b/compiler/simplCore/Simplify.lhs
@@ -21,6 +21,7 @@ import Type hiding ( substTy, extendTvSubst, substTyVar )
import SimplEnv
import SimplUtils
import FamInstEnv ( FamInstEnv )
+import Literal ( litIsLifted )
import Id
import MkId ( seqId, realWorldPrimId )
import MkCore ( mkImpossibleExpr )
@@ -1713,6 +1714,7 @@ rebuildCase, reallyRebuildCase
rebuildCase env scrut case_bndr alts cont
| Lit lit <- scrut -- No need for same treatment as constructors
-- because literals are inlined more vigorously
+ , not (litIsLifted lit)
= do { tick (KnownBranch case_bndr)
; case findAlt (LitAlt lit) alts of
Nothing -> missingAlt env case_bndr alts cont
diff --git a/compiler/specialise/SpecConstr.lhs b/compiler/specialise/SpecConstr.lhs
index 12492836ab..d2c07bcc1b 100644
--- a/compiler/specialise/SpecConstr.lhs
+++ b/compiler/specialise/SpecConstr.lhs
@@ -31,6 +31,7 @@ import CoreUtils
import CoreUnfold ( couldBeSmallEnoughToInline )
import CoreFVs ( exprsFreeVars )
import CoreMonad
+import Literal ( litIsLifted )
import HscTypes ( ModGuts(..) )
import WwLib ( mkWorkerArgs )
import DataCon
@@ -1714,7 +1715,8 @@ argsToPats env in_scope val_env args occs
\begin{code}
isValue :: ValueEnv -> CoreExpr -> Maybe Value
isValue _env (Lit lit)
- = Just (ConVal (LitAlt lit) [])
+ | litIsLifted lit = Nothing
+ | otherwise = Just (ConVal (LitAlt lit) [])
isValue env (Var v)
| Just stuff <- lookupVarEnv env v