Record the original text along with parsed Rationals: fixes #2245
[ghc-hetmet.git] / compiler / deSugar / MatchLit.lhs
index 4deb51c..4842b16 100644 (file)
@@ -19,19 +19,21 @@ import DsMonad
 import DsUtils
 
 import HsSyn
+
 import Id
 import CoreSyn
+import MkCore
 import TyCon
 import DataCon
+import TcHsSyn ( shortCutLit )
 import TcType
-import Type
 import PrelNames
 import TysWiredIn
-import Unique
 import Literal
 import SrcLoc
-import Ratio
+import Data.Ratio
 import Outputable
+import BasicTypes
 import Util
 import FastString
 \end{code}
@@ -59,12 +61,12 @@ See also below where we look for @DictApps@ for \tr{plusInt}, etc.
 
 \begin{code}
 dsLit :: HsLit -> DsM CoreExpr
-dsLit (HsStringPrim s) = return (mkLit (MachStr s))
-dsLit (HsCharPrim   c) = return (mkLit (MachChar c))
-dsLit (HsIntPrim    i) = return (mkLit (MachInt i))
-dsLit (HsWordPrim   w) = return (mkLit (MachWord w))
-dsLit (HsFloatPrim  f) = return (mkLit (MachFloat f))
-dsLit (HsDoublePrim d) = return (mkLit (MachDouble d))
+dsLit (HsStringPrim s) = return (Lit (MachStr s))
+dsLit (HsCharPrim   c) = return (Lit (MachChar c))
+dsLit (HsIntPrim    i) = return (Lit (MachInt i))
+dsLit (HsWordPrim   w) = return (Lit (MachWord w))
+dsLit (HsFloatPrim  f) = return (Lit (MachFloat f))
+dsLit (HsDoublePrim d) = return (Lit (MachDouble d))
 
 dsLit (HsChar c)       = return (mkCharExpr c)
 dsLit (HsString str)   = mkStringExprFS str
@@ -85,11 +87,21 @@ dsLit (HsRat r ty) = do
 dsOverLit :: HsOverLit Id -> DsM CoreExpr
 -- Post-typechecker, the SyntaxExpr field of an OverLit contains 
 -- (an expression for) the literal value itself
-dsOverLit (HsIntegral   _ lit _) = dsExpr lit
-dsOverLit (HsFractional _ lit _) = dsExpr lit
-dsOverLit (HsIsString   _ lit _) = dsExpr lit
+dsOverLit (OverLit { ol_val = val, ol_rebindable = rebindable 
+                  , ol_witness = witness, ol_type = ty })
+  | not rebindable
+  , Just expr <- shortCutLit val ty = dsExpr expr      -- Note [Literal short cut]
+  | otherwise                      = dsExpr witness
 \end{code}
 
+Note [Literal short cut]
+~~~~~~~~~~~~~~~~~~~~~~~~
+The type checker tries to do this short-cutting as early as possible, but 
+becuase of unification etc, more information is available to the desugarer.
+And where it's possible to generate the correct literal right away, it's
+much better do do so.
+
+
 \begin{code}
 hsLitKey :: HsLit -> Literal
 -- Get a Core literal to use (only) a grouping key
@@ -108,13 +120,14 @@ hsLitKey l                 = pprPanic "hsLitKey" (ppr l)
 
 hsOverLitKey :: OutputableBndr a => HsOverLit a -> Bool -> Literal
 -- Ditto for HsOverLit; the boolean indicates to negate
-hsOverLitKey (HsIntegral i _ _)   False = MachInt i
-hsOverLitKey (HsIntegral i _ _)   True  = MachInt (-i)
-hsOverLitKey (HsFractional r _ _) False = MachFloat r
-hsOverLitKey (HsFractional r _ _) True  = MachFloat (-r)
-hsOverLitKey (HsIsString s _ _)   False = MachStr s
-hsOverLitKey l                    _     = pprPanic "hsOverLitKey" (ppr l)
--- negated string should never happen
+hsOverLitKey (OverLit { ol_val = l }) neg = litValKey l neg
+
+litValKey :: OverLitVal -> Bool -> Literal
+litValKey (HsIntegral i)   False = MachInt i
+litValKey (HsIntegral i)   True  = MachInt (-i)
+litValKey (HsFractional r) False = MachFloat (fl_value r)
+litValKey (HsFractional r) True  = MachFloat (negate (fl_value r))
+litValKey (HsIsString s)   neg   = ASSERT( not neg) MachStr s
 \end{code}
 
 %************************************************************************
@@ -140,42 +153,55 @@ tidyLitPat (HsString s)
 tidyLitPat lit = LitPat lit
 
 ----------------
-tidyNPat :: HsOverLit Id -> Maybe (SyntaxExpr Id) -> SyntaxExpr Id -> Pat Id
-tidyNPat over_lit mb_neg eq 
-  | isIntTy    (overLitType over_lit) = mk_con_pat intDataCon    (HsIntPrim int_val)
-  | isWordTy   (overLitType over_lit) = mk_con_pat wordDataCon   (HsWordPrim int_val)
-  | isFloatTy  (overLitType over_lit) = mk_con_pat floatDataCon  (HsFloatPrim  rat_val)
-  | isDoubleTy (overLitType over_lit) = mk_con_pat doubleDataCon (HsDoublePrim rat_val)
---  | isStringTy lit_ty = mk_con_pat stringDataCon (HsStringPrim str_val)
-  | otherwise        = NPat over_lit mb_neg eq
+tidyNPat :: (HsLit -> Pat Id)  -- How to tidy a LitPat
+                -- We need this argument because tidyNPat is called
+                -- both by Match and by Check, but they tidy LitPats 
+                -- slightly differently; and we must desugar 
+                -- literals consistently (see Trac #5117)
+         -> HsOverLit Id -> Maybe (SyntaxExpr Id) -> SyntaxExpr Id 
+         -> Pat Id
+tidyNPat tidy_lit_pat (OverLit val False _ ty) mb_neg _
+       -- False: Take short cuts only if the literal is not using rebindable syntax
+       -- 
+       -- Once that is settled, look for cases where the type of the 
+       -- entire overloaded literal matches the type of the underlying literal,
+       -- and in that case take the short cut
+       -- NB: Watch out for wierd cases like Trac #3382
+       --        f :: Int -> Int
+       --        f "blah" = 4
+       --     which might be ok if we hvae 'instance IsString Int'
+       --    
+
+  | isIntTy ty,    Just int_lit <- mb_int_lit = mk_con_pat intDataCon    (HsIntPrim    int_lit)
+  | isWordTy ty,   Just int_lit <- mb_int_lit = mk_con_pat wordDataCon   (HsWordPrim   int_lit)
+  | isFloatTy ty,  Just rat_lit <- mb_rat_lit = mk_con_pat floatDataCon  (HsFloatPrim  rat_lit)
+  | isDoubleTy ty, Just rat_lit <- mb_rat_lit = mk_con_pat doubleDataCon (HsDoublePrim rat_lit)
+  | isStringTy ty, Just str_lit <- mb_str_lit = tidy_lit_pat (HsString str_lit)
   where
     mk_con_pat :: DataCon -> HsLit -> Pat Id
-    mk_con_pat con lit = unLoc (mkPrefixConPat con [noLoc $ LitPat lit] (overLitType over_lit))
-
-    neg_lit = case (mb_neg, over_lit) of
-               (Nothing,              _)   -> over_lit
-               (Just _,  HsIntegral i s ty)   -> HsIntegral   (-i) s ty
-               (Just _,  HsFractional f s ty) -> HsFractional (-f) s ty
-               (Just _,  HsIsString {})       -> panic "tidyNPat/neg_lit HsIsString"
-                            
-    int_val :: Integer
-    int_val = case neg_lit of
-               HsIntegral   i _ _ -> i
-               HsFractional {}    -> panic "tidyNPat/int_val HsFractional"
-               HsIsString   {}    -> panic "tidyNPat/int_val HsIsString"
+    mk_con_pat con lit = unLoc (mkPrefixConPat con [noLoc $ LitPat lit] ty)
+
+    mb_int_lit :: Maybe Integer
+    mb_int_lit = case (mb_neg, val) of
+                  (Nothing, HsIntegral i) -> Just i
+                  (Just _,  HsIntegral i) -> Just (-i)
+                  _ -> Nothing
        
-    rat_val :: Rational
-    rat_val = case neg_lit of
-               HsIntegral   i _ _ -> fromInteger i
-               HsFractional f _ _ -> f
-               HsIsString   {}    -> panic "tidyNPat/rat_val HsIsString"
+    mb_rat_lit :: Maybe Rational
+    mb_rat_lit = case (mb_neg, val) of
+                  (Nothing, HsIntegral   i) -> Just (fromInteger i)
+                  (Just _,  HsIntegral   i) -> Just (fromInteger (-i))
+                  (Nothing, HsFractional f) -> Just (fl_value f)
+                  (Just _, HsFractional f)  -> Just (negate (fl_value f))
+                  _ -> Nothing
        
-{-
-    str_val :: FastString
-    str_val = case neg_lit of
-               HsIsString   s _ _ -> s
-               _                  -> error "tidyNPat"
--}
+    mb_str_lit :: Maybe FastString
+    mb_str_lit = case (mb_neg, val) of
+                  (Nothing, HsIsString s) -> Just s
+                  _ -> Nothing
+
+tidyNPat _ over_lit mb_neg eq 
+  = NPat over_lit mb_neg eq
 \end{code}
 
 
@@ -232,14 +258,8 @@ matchLiterals [] _ _ = panic "matchLiterals []"
 %************************************************************************
 
 \begin{code}
-matchNPats :: [Id] -> Type -> [[EquationInfo]] -> DsM MatchResult
-       -- All NPats, but perhaps for different literals
-matchNPats vars ty groups
-  = do {  match_results <- mapM (matchOneNPat vars ty) groups
-       ; return (foldr1 combineMatchResults match_results) }
-
-matchOneNPat :: [Id] -> Type -> [EquationInfo] -> DsM MatchResult
-matchOneNPat (var:vars) ty (eqn1:eqns) -- All for the same literal
+matchNPats :: [Id] -> Type -> [EquationInfo] -> DsM MatchResult
+matchNPats (var:vars) ty (eqn1:eqns)   -- All for the same literal
   = do { let NPat lit mb_neg eq_chk = firstPat eqn1
        ; lit_expr <- dsOverLit lit
        ; neg_lit <- case mb_neg of
@@ -250,7 +270,7 @@ matchOneNPat (var:vars) ty (eqn1:eqns)      -- All for the same literal
        ; let pred_expr = mkApps eq_expr [Var var, neg_lit]
        ; match_result <- match vars ty (shiftEqns (eqn1:eqns))
        ; return (mkGuardedMatchResult pred_expr match_result) }
-matchOneNPat vars _ eqns = pprPanic "matchOneNPat" (ppr (vars, eqns))
+matchNPats vars _ eqns = pprPanic "matchOneNPat" (ppr (vars, eqns))
 \end{code}