Liberalising IncoherentInstances
authorJoachim Breitner <mail@joachim-breitner.de>
Mon, 19 Aug 2013 08:24:25 +0000 (10:24 +0200)
committerAustin Seipp <aseipp@pobox.com>
Fri, 30 Aug 2013 01:46:30 +0000 (20:46 -0500)
(Almost) as suggested by SPJ on
http://www.haskell.org/pipermail/glasgow-haskell-users/2013-July/022651.html
(fixes #8141)

Signed-off-by: Austin Seipp <aseipp@pobox.com>
compiler/basicTypes/BasicTypes.lhs
compiler/types/InstEnv.lhs
docs/users_guide/glasgow_exts.xml

index 838e368..877ee82 100644 (file)
@@ -381,17 +381,17 @@ data OverlapFlag
   -- its ambiguous which to choose)
   | OverlapOk { isSafeOverlap :: Bool }
 
-  -- | Like OverlapOk, but also ignore this instance
-  -- if it doesn't match the constraint you are
-  -- trying to resolve, but could match if the type variables
-  -- in the constraint were instantiated
+  -- | Silently ignore this instance if you 
+  -- find any other that matches the constraing you
+  -- are trying to resolve, including when checking if there are instances that
+  -- do not match, but unify.
   --
   -- Example: constraint (Foo [b])
   --        instances  (Foo [Int])      Incoherent
   --                   (Foo [a])
   -- Without the Incoherent flag, we'd complain that
   -- instantiating 'b' would change which instance
-  -- was chosen
+  -- was chosen.
   | Incoherent { isSafeOverlap :: Bool }
   deriving (Eq, Data, Typeable)
 
index 31a1bfb..a3ade6b 100644 (file)
@@ -535,7 +535,7 @@ lookupInstEnv' ie cls tys
       = find ((item, map (lookup_tv subst) tpl_tvs) : ms) us rest
 
         -- Does not match, so next check whether the things unify
-        -- See Note [Overlapping instances] above
+        -- See Note [Overlapping instances] and Note [Incoherent Instances]
       | Incoherent _ <- oflag
       = find ms us rest
 
@@ -625,12 +625,19 @@ insert_overlapping new_item (item:items)
         -- Keep new one
   | old_beats_new = item : items
         -- Keep old one
+  | incoherent new_item = item : items -- note [Incoherent Instances]
+        -- Keep old one
+  | incoherent item = new_item : items
+        -- Keep new one
   | otherwise     = item : insert_overlapping new_item items
         -- Keep both
   where
     new_beats_old = new_item `beats` item
     old_beats_new = item `beats` new_item
 
+    incoherent (inst, _) = case is_flag inst of Incoherent _ -> True
+                                                _            -> False
+
     (instA, _) `beats` (instB, _)
           = overlap_ok && 
             isJust (tcMatchTys (mkVarSet (is_tvs instB)) (is_tys instB) (is_tys instA))
@@ -646,6 +653,37 @@ insert_overlapping new_item (item:items)
                               _                          -> True
 \end{code}
 
+Note [Incoherent Instances]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The original motivation for incoherent instances was about the situation where
+an instance would unify, but not match. That would be an error, unless the
+unifying instances is marked as incoherent. Example:
+
+        class C a b c where foo :: (a,b,c)
+        instance C [a] b Int
+        instance [incoherent] [Int] b c
+        instance [incoherent] C a Int c
+
+Thanks to the incoherent flags,
+        foo :: ([a],b,Int)
+works: Only instance one matches, the others just unify, but are marked
+incoherent.
+
+So I can write
+        (foo :: ([a],b,Int)) :: ([Int], Int, Int).
+but if that works then I really want to be able to write
+        foo :: ([Int], Int, Int)
+as well. Now all three instances from above match. None is more specific than
+another, so none is ruled out by the normal overlapping rules. In order to
+allow this, we now (Aug 2013) liberarate the meaning of Incoherent instances to
+say: "An incoherent instances can be ignored if there is another matching
+instances." This subsumes the ignore-incoheren-unify-logic.
+
+The implementation is in insert_overlapping, where we remove incoherent
+instances if there are others.
+
+
 
 %************************************************************************
 %*                                                                      *
index 6c4046e..9056804 100644 (file)
@@ -4542,7 +4542,9 @@ So GHC rejects the program.</para>
 <para>
 If, however, you add the flag <option>-XIncoherentInstances</option>,
 GHC will instead pick (C), without complaining about
-the problem of subsequent instantiations.
+the problem of subsequent instantiations. In general, the flag
+<option>-XIncoherentInstances</option> will cause GHC to ignore an instance if
+there is another instance that matches the constraint.
 </para>
 <para>
 Notice that we gave a type signature to <literal>f</literal>, so GHC had to