Repository : ssh://darcs.haskell.org//srv/darcs/ghc

On branch  : master

http://hackage.haskell.org/trac/ghc/changeset/242fc5606d5a94205949f8bd58bea348c247d863

>---------------------------------------------------------------

commit 242fc5606d5a94205949f8bd58bea348c247d863
Author: Simon Peyton Jones <simo...@microsoft.com>
Date:   Fri Oct 19 01:22:20 2012 +0100

    Some refactoring of the occurs check in TcUnify
    
    I was experimenting with allowing unification with a type variable
    when there are type functions in the type; but that led to strangely
    worse error messages (See Note [Conservative unification check]) in
    TcUnify.  I don't quite understand why, but the simple thing for now
    is to maintain the same behaviour.  I tidied up the code a bit though.

>---------------------------------------------------------------

 compiler/typecheck/TcUnify.lhs |  107 ++++++++++++++++++++++------------------
 1 files changed, 59 insertions(+), 48 deletions(-)

diff --git a/compiler/typecheck/TcUnify.lhs b/compiler/typecheck/TcUnify.lhs
index 18c77d7..3a13b9c 100644
--- a/compiler/typecheck/TcUnify.lhs
+++ b/compiler/typecheck/TcUnify.lhs
@@ -766,22 +766,19 @@ uUnfilledVar origin swapped tv1 details1 non_var_ty2  -- 
ty2 is not a type varia
       MetaTv { mtv_info = TauTv, mtv_ref = ref1 }
         -> do { mb_ty2' <- checkTauTvUpdate tv1 non_var_ty2
               ; case mb_ty2' of
-                  Nothing   -> do { traceTc "Occ/kind defer" (ppr tv1 <+> 
dcolon <+> ppr (tyVarKind tv1)
-                                                              $$ ppr 
non_var_ty2 $$ ppr (typeKind non_var_ty2))
-                                  ; defer }
                   Just ty2' -> updateMeta tv1 ref1 ty2'
+                  Nothing   -> do { traceTc "Occ/kind defer" 
+                                        (ppr tv1 <+> dcolon <+> ppr (tyVarKind 
tv1)
+                                         $$ ppr non_var_ty2 $$ ppr (typeKind 
non_var_ty2))
+                                  ; defer }
               }
 
       _other -> do { traceTc "Skolem defer" (ppr tv1); defer } -- Skolems of 
all sorts
   where
-    defer | Just ty2' <- tcView non_var_ty2    -- Note [Avoid deferring]
-                                               -- non_var_ty2 isn't expanded 
yet
-          = uUnfilledVar origin swapped tv1 details1 ty2'
-          | otherwise
-          = unSwap swapped (uType_defer origin) (mkTyVarTy tv1) non_var_ty2
-          -- Occurs check or an untouchable: just defer
-         -- NB: occurs check isn't necessarily fatal: 
-         --     eg tv1 occured in type family parameter
+    defer = unSwap swapped (uType_defer origin) (mkTyVarTy tv1) non_var_ty2
+               -- Occurs check or an untouchable: just defer
+              -- NB: occurs check isn't necessarily fatal: 
+              --     eg tv1 occured in type family parameter
 
 ----------------
 uUnfilledVars :: CtOrigin
@@ -855,51 +852,65 @@ checkTauTvUpdate :: TcTyVar -> TcType -> TcM (Maybe 
TcType)
 -- sort matters out.
 
 checkTauTvUpdate tv ty
-  = do { ty'   <- zonkTcType ty
-       ; sub_k <- unifyKindX (tyVarKind tv) (typeKind ty')
+  = do { ty1   <- zonkTcType ty
+       ; sub_k <- unifyKindX (tyVarKind tv) (typeKind ty1)
        ; case sub_k of
-           Nothing -> return Nothing
-           Just LT -> return Nothing
-           _       -> return (occurCheckExpand tv ty') }
-
-{-
+           Nothing           -> return Nothing
+           Just LT           -> return Nothing
+           _  | defer_me ty1   -- Quick test
+              -> -- Failed quick test so try harder
+                 case occurCheckExpand tv ty1 of 
+                   Nothing -> return Nothing
+                   Just ty2 | defer_me ty2 -> return Nothing
+                            | otherwise    -> return (Just ty2)
+              | otherwise   -> return (Just ty1) }
   where 
-    ok :: TcType -> Maybe TcType 
-    -- This version of TcType.occurCheckExpand checked that ty does 
-    -- not contain any type families, but that's no longer necessary:
-    -- See Note [Type family sharing]
-    -- 
-    -- Checks that tv does not occur in the arg type
-    -- expanding type synonyms where necessary to make this so
-    -- eg type Phantom a = Bool
-    --     ok (tv -> Int)         = Nothing
-    --     ok (x -> Int)          = Just (x -> Int)
-    --     ok (Phantom tv -> Int) = Just (Bool -> Int)
-    ok (TyVarTy tv') | not (tv == tv') = Just (TyVarTy tv') 
-    ok this_ty@(TyConApp tc tys) 
-      | not (isSynFamilyTyCon tc), Just tys' <- allMaybes (map ok tys) 
-      = Just (TyConApp tc tys') 
-      | isSynTyCon tc, Just ty_expanded <- tcView this_ty
-      = ok ty_expanded -- See Note [Type synonyms and the occur check] 
-    ok ty@(LitTy {}) = Just ty
-    ok (FunTy arg res) | Just arg' <- ok arg, Just res' <- ok res
-                       = Just (FunTy arg' res') 
-    ok (AppTy fun arg) | Just fun' <- ok fun, Just arg' <- ok arg 
-                       = Just (AppTy fun' arg') 
-    ok (ForAllTy tv1 ty1) | Just ty1' <- ok ty1 = Just (ForAllTy tv1 ty1') 
-    -- Fall-through 
-    ok _ty = Nothing 
--}
+    defer_me :: TcType -> Bool
+    -- Checks for (a) occurrence of tv
+    --            (b) type family applicatios
+    -- See Note [Conservative unification check]
+    defer_me (LitTy {})        = False
+    defer_me (TyVarTy tv')     = tv == tv'
+    defer_me (TyConApp tc tys) = isSynFamilyTyCon tc || any defer_me tys
+    defer_me (FunTy arg res)   = defer_me arg || defer_me res
+    defer_me (AppTy fun arg)   = defer_me fun || defer_me arg
+    defer_me (ForAllTy _ ty)   = defer_me ty
 \end{code}
 
-Note [Avoid deferring]
-~~~~~~~~~~~~~~~~~~~~~~
-We try to avoid creating deferred constraints only for efficiency.
-Example (Trac #4917)
+Note [Conservative unification check]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+When unifying (tv ~ rhs), w try to avoid creating deferred constraints
+only for efficiency.  However, we do not unify (the defer_me check) if
+  a) There's an occurs check (tv is in fvs(rhs))
+  b) There's a type-function call in 'rhs'
+
+If we fail defer_me we use occurCheckExpand to try to make it pass,
+(see Note [Type synonyms and the occur check]) and then use defer_me
+again to check.  Example: Trac #4917)
        a ~ Const a b
 where type Const a b = a.  We can solve this immediately, even when
 'a' is a skolem, just by expanding the synonym.
 
+We always defer type-function calls, even if it's be perfectly safe to
+unify, eg (a ~ F [b]).  Reason: this ensures that the constraint
+solver gets to see, and hence simplify the type-function call, which
+in turn might simplify the type of an inferred function.  Test ghci046
+is a case in point.
+
+More mysteriously, test T7010 gave a horrible error 
+  T7010.hs:29:21:
+    Couldn't match type `Serial (ValueTuple Float)' with `IO Float'
+    Expected type: (ValueTuple Vector, ValueTuple Vector)
+      Actual type: (ValueTuple Vector, ValueTuple Vector)
+because an insoluble type function constraint got mixed up with
+a soluble one when flattening.  I never fully understood this, but
+deferring type-function applications made it go away :-(.
+T5853 also got a less-good error message with more aggressive
+unification of type functions.
+
+Moreover the Note [Type family sharing] gives another reason, but
+again I'm not sure if it's really valid.
+
 Note [Type synonyms and the occur check]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Generally speaking we try to update a variable with type synonyms not



_______________________________________________
Cvs-ghc mailing list
Cvs-ghc@haskell.org
http://www.haskell.org/mailman/listinfo/cvs-ghc

Reply via email to