From 1cf5c7554da206fe39eb4e4a2e37e9e1d5c8ab27 Mon Sep 17 00:00:00 2001
From: Simon Peyton Jones <simonpj@microsoft.com>
Date: Wed, 3 Aug 2011 16:22:06 +0100
Subject: [PATCH] Fix a grevious error in InstEnv: Trac #5095

An claimed short-cut optimisation was actually an error.
The optimisation was this: when looking up (C a b), where
'a' and 'b' are type variables, we were returning [] immediately
if the instance environment had no instances of form (C a b).
Why? Because the thing being looked up definitely won't match
(C Int Bool), say.

BUT it will *unify* with (C Int Bool) and we care very much
about things it might unify with.  If we neglect them we may
silently allow incoherent instance selection, and that is
exactly what happened in #5095.

The fix is easy: remove the "optimisation".
---
 compiler/types/InstEnv.lhs | 45 ++++++++++++++------------------------
 1 file changed, 17 insertions(+), 28 deletions(-)

diff --git a/compiler/types/InstEnv.lhs b/compiler/types/InstEnv.lhs
index 2789a331cc02..bfae8b359bae 100644
--- a/compiler/types/InstEnv.lhs
+++ b/compiler/types/InstEnv.lhs
@@ -350,14 +350,11 @@ or, to put it another way, we have
 ---------------------------------------------------
 type InstEnv = UniqFM ClsInstEnv	-- Maps Class to instances for that class
 
-data ClsInstEnv 
+newtype ClsInstEnv 
   = ClsIE [Instance]	-- The instances for a particular class, in any order
-  	  Bool 		-- True <=> there is an instance of form C a b c
-			-- 	If *not* then the common case of looking up
-			--	(C a b c) can fail immediately
 
 instance Outputable ClsInstEnv where
-  ppr (ClsIE is b) = ptext (sLit "ClsIE") <+> ppr b <+> pprInstances is
+  ppr (ClsIE is) = pprInstances is
 
 -- INVARIANTS:
 --  * The is_tvs are distinct in each Instance
@@ -372,26 +369,24 @@ emptyInstEnv :: InstEnv
 emptyInstEnv = emptyUFM
 
 instEnvElts :: InstEnv -> [Instance]
-instEnvElts ie = [elt | ClsIE elts _ <- eltsUFM ie, elt <- elts]
+instEnvElts ie = [elt | ClsIE elts <- eltsUFM ie, elt <- elts]
 
 classInstances :: (InstEnv,InstEnv) -> Class -> [Instance]
 classInstances (pkg_ie, home_ie) cls 
   = get home_ie ++ get pkg_ie
   where
     get env = case lookupUFM env cls of
-		Just (ClsIE insts _) -> insts
-		Nothing		     -> []
+		Just (ClsIE insts) -> insts
+		Nothing		   -> []
 
 extendInstEnvList :: InstEnv -> [Instance] -> InstEnv
 extendInstEnvList inst_env ispecs = foldl extendInstEnv inst_env ispecs
 
 extendInstEnv :: InstEnv -> Instance -> InstEnv
-extendInstEnv inst_env ins_item@(Instance { is_cls = cls_nm, is_tcs = mb_tcs })
-  = addToUFM_C add inst_env cls_nm (ClsIE [ins_item] ins_tyvar)
+extendInstEnv inst_env ins_item@(Instance { is_cls = cls_nm })
+  = addToUFM_C add inst_env cls_nm (ClsIE [ins_item])
   where
-    add (ClsIE cur_insts cur_tyvar) _ = ClsIE (ins_item : cur_insts)
-					      (ins_tyvar || cur_tyvar)
-    ins_tyvar = not (any isJust mb_tcs)
+    add (ClsIE cur_insts) _ = ClsIE (ins_item : cur_insts)
 \end{code}
 
 
@@ -442,7 +437,7 @@ lookupInstEnv :: (InstEnv, InstEnv) 	-- External and home package inst-env
 -- Then which we choose would depend on the way in which 'a'
 -- is instantiated.  So we report that Foo [b] is a match (mapping b->a)
 -- but Foo [Int] is a unifier.  This gives the caller a better chance of
--- giving a suitable error messagen
+-- giving a suitable error message
 
 lookupInstEnv (pkg_ie, home_ie) cls tys
   = (safe_matches, all_unifs, safe_fail)
@@ -494,22 +489,9 @@ lookupInstEnv (pkg_ie, home_ie) cls tys
     --------------
     lookup env = case lookupUFM env cls of
 		   Nothing -> ([],[])	-- No instances for this class
-		   Just (ClsIE insts has_tv_insts)
-			| all_tvs && not has_tv_insts
-			-> ([],[])	-- Short cut for common case
-			-- The thing we are looking up is of form (C a b c), and
-			-- the ClsIE has no instances of that form, so don't bother to search
-	
-			| otherwise
-			-> find [] [] insts
+		   Just (ClsIE insts) -> find [] [] insts
 
     --------------
-    lookup_tv :: TvSubst -> TyVar -> Either TyVar Type	
-	-- See Note [InstTypes: instantiating types]
-    lookup_tv subst tv = case lookupTyVar subst tv of
-				Just ty -> Right ty
-				Nothing -> Left tv
-
     find ms us [] = (ms, us)
     find ms us (item@(Instance { is_tcs = mb_tcs, is_tvs = tpl_tvs, 
 				 is_tys = tpl_tys, is_flag = oflag,
@@ -541,6 +523,13 @@ lookupInstEnv (pkg_ie, home_ie) cls tys
 	    Just _   -> find ms (item:us) rest
 	    Nothing  -> find ms us	  rest
 
+    ----------------
+    lookup_tv :: TvSubst -> TyVar -> Either TyVar Type	
+	-- See Note [InstTypes: instantiating types]
+    lookup_tv subst tv = case lookupTyVar subst tv of
+				Just ty -> Right ty
+				Nothing -> Left tv
+
 ---------------
 ---------------
 insert_overlapping :: InstMatch -> [InstMatch] -> [InstMatch]
-- 
GitLab