Commit 1ae5fa45 authored by Simon Peyton Jones's avatar Simon Peyton Jones
Browse files

Complete work on new OVERLAPPABLE/OVERLAPPING pragmas (Trac #9242)

* Deprecate -XOverlappingInstances

* Update test suite.  Several tests even had entirely unnecessary
  uses of -XOverlappingInstances

* Update user manual with a careful description of the instance
  resolution story

* Fix an outright bug in the handling of duplidate instances in GHCi,
  which are meant to silently overwrite the earlier duplicate. The
  logic was right for family instances but was both more complicated,
  and plain wrong, for class instances.  (If you are interested, the
  bug was that we were eliminating the duplicate from the InstEnv, but
  not from the [ClsInst] held in tcg_insts.)  Test is ghci044a.
parent bfaa1799
......@@ -462,6 +462,7 @@ hasOverlappableFlag mode =
case mode of
Overlappable -> True
Overlaps -> True
Incoherent -> True
_ -> False
hasOverlappingFlag :: OverlapMode -> Bool
......@@ -469,57 +470,58 @@ hasOverlappingFlag mode =
case mode of
Overlapping -> True
Overlaps -> True
Incoherent -> True
_ -> False
data OverlapMode
{- | This instance must not overlap another `NoOverlap` instance.
However, it may be overlapped by `Overlapping` instances,
and it may overlap `Overlappable` instances. -}
data OverlapMode -- See Note [Rules for instance lookup] in InstEnv
= NoOverlap
-- ^ This instance must not overlap another `NoOverlap` instance.
-- However, it may be overlapped by `Overlapping` instances,
-- and it may overlap `Overlappable` instances.
{- | Silently ignore this instance if you find a
more specific one that matches the constraint
you are trying to resolve
Example: constraint (Foo [Int])
instance Foo [Int]
instance {-# OVERLAPPABLE #-} Foo [a]
Since the second instance has the Overlappable flag,
the first instance will be chosen (otherwise
its ambiguous which to choose) -}
| Overlappable
-- ^ Silently ignore this instance if you find a
-- more specific one that matches the constraint
-- you are trying to resolve
--
-- Example: constraint (Foo [Int])
-- instance Foo [Int]
-- instance {-# OVERLAPPABLE #-} Foo [a]
--
-- Since the second instance has the Overlappable flag,
-- the first instance will be chosen (otherwise
-- its ambiguous which to choose)
{- | Silently ignore any more general instances that may be
used to solve the constraint.
Example: constraint (Foo [Int])
instance {-# OVERLAPPING #-} Foo [Int]
instance Foo [a]
Since the first instance has the Overlapping flag,
the second---more general---instance will be ignored (otherwise
its ambiguous which to choose) -}
| Overlapping
-- ^ Silently ignore any more general instances that may be
-- used to solve the constraint.
--
-- Example: constraint (Foo [Int])
-- instance {-# OVERLAPPING #-} Foo [Int]
-- instance Foo [a]
--
-- Since the first instance has the Overlapping flag,
-- the second---more general---instance will be ignored (otherwise
-- it is ambiguous which to choose)
-- | Equiavalent to having both `Overlapping` and `Overlappable` flags.
| Overlaps
-- ^ Equiavalent to having both `Overlapping` and `Overlappable` flags.
-- | 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])
-- instance {-# INCOHERENT -} Foo [Int]
-- instance Foo [a]
-- Without the Incoherent flag, we'd complain that
-- instantiating 'b' would change which instance
-- was chosen. See also note [Incoherent instances]
| Incoherent
-- ^ Behave like Overlappable and Overlapping, and in addition pick
-- an an arbitrary one if there are multiple matching candidates, and
-- don't worry about later instantiation
--
-- Example: constraint (Foo [b])
-- instance {-# INCOHERENT -} Foo [Int]
-- instance Foo [a]
-- Without the Incoherent flag, we'd complain that
-- instantiating 'b' would change which instance
-- was chosen. See also note [Incoherent instances] in InstEnv
deriving (Eq, Data, Typeable)
......
......@@ -2871,7 +2871,9 @@ xFlags = [
deprecatedForExtension "MultiParamTypeClasses" ),
( "FunctionalDependencies", Opt_FunctionalDependencies, nop ),
( "GeneralizedNewtypeDeriving", Opt_GeneralizedNewtypeDeriving, setGenDeriving ),
( "OverlappingInstances", Opt_OverlappingInstances, nop ),
( "OverlappingInstances", Opt_OverlappingInstances,
\ turn_on -> when turn_on
$ deprecate "instead use per-instance pragamas OVERLAPPING/OVERLAPPABLE/OVERLAPS" ),
( "UndecidableInstances", Opt_UndecidableInstances, nop ),
( "IncoherentInstances", Opt_IncoherentInstances, nop ),
( "PackageImports", Opt_PackageImports, nop ),
......
......@@ -1100,8 +1100,8 @@ appendStubC (ForeignStubs h c) c_code = ForeignStubs h (c $$ c_code)
Note [The interactive package]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Type and class declarations at the command prompt are treated as if
they were defined in modules
Type, class, and value declarations at the command prompt are treated
as if they were defined in modules
interactive:Ghci1
interactive:Ghci2
...etc...
......@@ -1151,11 +1151,12 @@ The details are a bit tricky though:
The 'thisPackage' field stays as 'main' (or whatever -package-name says.
* The main trickiness is that the type environment (tcg_type_env and
fixity envt (tcg_fix_env) now contains entities from all the
GhciN modules together, rather than just a single module as is usually
the case. So you can't use "nameIsLocalOrFrom" to decide whether
to look in the TcGblEnv vs the HPT/PTE. This is a change, but not
a problem provided you know.
fixity envt (tcg_fix_env), and instances (tcg_insts, tcg_fam_insts)
now contains entities from all the interactive-package modules
(Ghci1, Ghci2, ...) together, rather than just a single module as
is usually the case. So you can't use "nameIsLocalOrFrom" to
decide whether to look in the TcGblEnv vs the HPT/PTE. This is a
change, but not a problem provided you know.
Note [Interactively-bound Ids in GHCi]
......
......@@ -49,7 +49,6 @@ import TcMType
import Type
import Coercion ( Role(..) )
import TcType
import Unify
import HscTypes
import Id
import Name
......@@ -60,9 +59,9 @@ import PrelNames
import SrcLoc
import DynFlags
import Bag
import Maybes
import Util
import Outputable
import Control.Monad( unless )
import Data.List( mapAccumL )
\end{code}
......@@ -410,22 +409,24 @@ tcExtendLocalInstEnv :: [ClsInst] -> TcM a -> TcM a
tcExtendLocalInstEnv dfuns thing_inside
= do { traceDFuns dfuns
; env <- getGblEnv
; inst_env' <- foldlM addLocalInst (tcg_inst_env env) dfuns
; let env' = env { tcg_insts = dfuns ++ tcg_insts env,
tcg_inst_env = inst_env' }
; (inst_env', cls_insts') <- foldlM addLocalInst
(tcg_inst_env env, tcg_insts env)
dfuns
; let env' = env { tcg_insts = cls_insts'
, tcg_inst_env = inst_env' }
; setGblEnv env' thing_inside }
addLocalInst :: InstEnv -> ClsInst -> TcM InstEnv
-- Check that the proposed new instance is OK,
addLocalInst :: (InstEnv, [ClsInst]) -> ClsInst -> TcM (InstEnv, [ClsInst])
-- Check that the proposed new instance is OK,
-- and then add it to the home inst env
-- If overwrite_inst, then we can overwrite a direct match
addLocalInst home_ie ispec
addLocalInst (home_ie, my_insts) ispec
= do {
-- Instantiate the dfun type so that we extend the instance
-- envt with completely fresh template variables
-- This is important because the template variables must
-- not overlap with anything in the things being looked up
-- (since we do unification).
-- (since we do unification).
--
-- We use tcInstSkolType because we don't want to allocate fresh
-- *meta* type variables.
......@@ -438,9 +439,23 @@ addLocalInst home_ie ispec
-- Load imported instances, so that we report
-- duplicates correctly
eps <- getEps
; let inst_envs = (eps_inst_env eps, home_ie)
(tvs, cls, tys) = instanceHead ispec
-- 'matches' are existing instance declarations that are less
-- specific than the new one
-- 'dups' are those 'matches' that are equal to the new one
; isGHCi <- getIsGHCi
; eps <- getEps
; let (home_ie', my_insts')
| isGHCi = ( deleteFromInstEnv home_ie ispec
, filterOut (identicalInstHead ispec) my_insts)
| otherwise = (home_ie, my_insts)
-- If there is a home-package duplicate instance,
-- silently delete it
(_tvs, cls, tys) = instanceHead ispec
inst_envs = (eps_inst_env eps, home_ie')
(matches, _, _) = lookupInstEnv inst_envs cls tys
dups = filter (identicalInstHead ispec) (map fst matches)
-- Check functional dependencies
; case checkFunDeps inst_envs ispec of
......@@ -448,31 +463,10 @@ addLocalInst home_ie ispec
Nothing -> return ()
-- Check for duplicate instance decls
; let (matches, unifs, _) = lookupInstEnv inst_envs cls tys
dup_ispecs = [ dup_ispec
| (dup_ispec, _) <- matches
, let dup_tys = is_tys dup_ispec
, isJust (tcMatchTys (mkVarSet tvs) tys dup_tys)]
-- Find memebers of the match list which ispec itself matches.
-- If the match is 2-way, it's a duplicate
-- If it's a duplicate, but we can overwrite home package dups, then overwrite
; isGHCi <- getIsGHCi
; overlapFlag <- getOverlapFlag
; case isGHCi of
False -> case dup_ispecs of
dup : _ -> dupInstErr ispec dup >> return (extendInstEnv home_ie ispec)
[] -> return (extendInstEnv home_ie ispec)
True -> case (dup_ispecs, home_ie_matches, unifs, overlapMode overlapFlag) of
(_, _:_, _, _) -> return (overwriteInstEnv home_ie ispec)
(dup:_, [], _, _) -> dupInstErr ispec dup >> return (extendInstEnv home_ie ispec)
([], _, u:_, NoOverlap) -> overlappingInstErr ispec u >> return (extendInstEnv home_ie ispec)
_ -> return (extendInstEnv home_ie ispec)
where (homematches, _) = lookupInstEnv' home_ie cls tys
home_ie_matches = [ dup_ispec
| (dup_ispec, _) <- homematches
, let dup_tys = is_tys dup_ispec
, isJust (tcMatchTys (mkVarSet tvs) tys dup_tys)] }
; unless (null dups) $
dupInstErr ispec (head dups)
; return (extendInstEnv home_ie' ispec, ispec:my_insts') }
traceDFuns :: [ClsInst] -> TcRn ()
traceDFuns ispecs
......@@ -492,11 +486,6 @@ dupInstErr ispec dup_ispec
= addClsInstsErr (ptext (sLit "Duplicate instance declarations:"))
[ispec, dup_ispec]
overlappingInstErr :: ClsInst -> ClsInst -> TcRn ()
overlappingInstErr ispec dup_ispec
= addClsInstsErr (ptext (sLit "Overlapping instance declarations:"))
[ispec, dup_ispec]
addClsInstsErr :: SDoc -> [ClsInst] -> TcRn ()
addClsInstsErr herald ispecs
= setSrcSpan (getSrcSpan (head sorted)) $
......
......@@ -325,6 +325,9 @@ data TcGblEnv
#endif /* GHCI */
tcg_ev_binds :: Bag EvBind, -- Top-level evidence bindings
-- Things defined in this module, or (in GHCi) in the interactive package
-- For the latter, see Note [The interactive package] in HscTypes
tcg_binds :: LHsBinds Id, -- Value bindings in this module
tcg_sigs :: NameSet, -- ...Top-level names that *lack* a signature
tcg_imp_specs :: [LTcSpecPrag], -- ...SPECIALISE prags for imported Ids
......
......@@ -46,7 +46,6 @@ import Coercion
import CoAxiom
import VarSet
import VarEnv
import Module( isInteractiveModule )
import Name
import UniqFM
import Outputable
......@@ -381,23 +380,21 @@ identicalFamInst :: FamInst -> FamInst -> Bool
-- Same LHS, *and* both instances are on the interactive command line
-- Used for overriding in GHCi
identicalFamInst (FamInst { fi_axiom = ax1 }) (FamInst { fi_axiom = ax2 })
= isInteractiveModule (nameModule (coAxiomName ax1))
&& isInteractiveModule (nameModule (coAxiomName ax2))
&& coAxiomTyCon ax1 == coAxiomTyCon ax2
= coAxiomTyCon ax1 == coAxiomTyCon ax2
&& brListLength brs1 == brListLength brs2
&& and (brListZipWith identical_ax_branch brs1 brs2)
where brs1 = coAxiomBranches ax1
brs2 = coAxiomBranches ax2
identical_ax_branch br1 br2
= length tvs1 == length tvs2
&& length lhs1 == length lhs2
&& and (zipWith (eqTypeX rn_env) lhs1 lhs2)
where
tvs1 = coAxBranchTyVars br1
tvs2 = coAxBranchTyVars br2
lhs1 = coAxBranchLHS br1
lhs2 = coAxBranchLHS br2
rn_env = rnBndrs2 (mkRnEnv2 emptyInScopeSet) tvs1 tvs2
&& and (brListZipWith identical_branch brs1 brs2)
where
brs1 = coAxiomBranches ax1
brs2 = coAxiomBranches ax2
identical_branch br1 br2
= isJust (tcMatchTys tvs1 lhs1 lhs2)
&& isJust (tcMatchTys tvs2 lhs2 lhs1)
where
tvs1 = mkVarSet (coAxBranchTyVars br1)
tvs2 = mkVarSet (coAxBranchTyVars br2)
lhs1 = coAxBranchLHS br1
lhs2 = coAxBranchLHS br2
\end{code}
%************************************************************************
......
......@@ -16,7 +16,7 @@ module InstEnv (
instanceHead, instanceSig, mkLocalInstance, mkImportedInstance,
instanceDFunId, tidyClsInstDFun, instanceRoughTcs,
InstEnv, emptyInstEnv, extendInstEnv, overwriteInstEnv,
InstEnv, emptyInstEnv, extendInstEnv, deleteFromInstEnv, identicalInstHead,
extendInstEnvList, lookupUniqueInstEnv, lookupInstEnv', lookupInstEnv, instEnvElts,
classInstances, orphNamesOfClsInst, instanceBindFun,
instanceCantMatch, roughMatchTcs
......@@ -160,7 +160,8 @@ pprInstance :: ClsInst -> SDoc
-- Prints the ClsInst as an instance declaration
pprInstance ispec
= hang (pprInstanceHdr ispec)
2 (ptext (sLit "--") <+> pprDefinedAt (getName ispec))
2 (vcat [ ptext (sLit "--") <+> pprDefinedAt (getName ispec)
, ifPprDebug (ppr (is_dfun ispec)) ])
-- * pprInstanceHdr is used in VStudio to populate the ClassView tree
pprInstanceHdr :: ClsInst -> SDoc
......@@ -420,26 +421,22 @@ extendInstEnv inst_env ins_item@(ClsInst { is_cls_nm = cls_nm })
where
add (ClsIE cur_insts) _ = ClsIE (ins_item : cur_insts)
overwriteInstEnv :: InstEnv -> ClsInst -> InstEnv
overwriteInstEnv inst_env ins_item@(ClsInst { is_cls_nm = cls_nm, is_tys = tys })
= addToUFM_C add inst_env cls_nm (ClsIE [ins_item])
deleteFromInstEnv :: InstEnv -> ClsInst -> InstEnv
deleteFromInstEnv inst_env ins_item@(ClsInst { is_cls_nm = cls_nm })
= adjustUFM adjust inst_env cls_nm
where
add (ClsIE cur_insts) _ = ClsIE (replaceInst cur_insts)
rough_tcs = roughMatchTcs tys
replaceInst [] = [ins_item]
replaceInst (item@(ClsInst { is_tcs = mb_tcs, is_tvs = tpl_tvs
, is_tys = tpl_tys }) : rest)
-- Fast check for no match, uses the "rough match" fields
| instanceCantMatch rough_tcs mb_tcs
= item : replaceInst rest
| let tpl_tv_set = mkVarSet tpl_tvs
, Just _ <- tcMatchTys tpl_tv_set tpl_tys tys
= ins_item : rest
| otherwise
= item : replaceInst rest
adjust (ClsIE items) = ClsIE (filterOut (identicalInstHead ins_item) items)
identicalInstHead :: ClsInst -> ClsInst -> Bool
-- ^ True when when the instance heads are the same
-- e.g. both are Eq [(a,b)]
-- Obviously should be insenstive to alpha-renaming
identicalInstHead (ClsInst { is_cls_nm = cls_nm1, is_tcs = rough1, is_tvs = tvs1, is_tys = tys1 })
(ClsInst { is_cls_nm = cls_nm2, is_tcs = rough2, is_tvs = tvs2, is_tys = tys2 })
= cls_nm1 == cls_nm2
&& not (instanceCantMatch rough1 rough2) -- Fast check for no match, uses the "rough match" fields
&& isJust (tcMatchTys (mkVarSet tvs1) tys1 tys2)
&& isJust (tcMatchTys (mkVarSet tvs2) tys2 tys1)
\end{code}
......@@ -453,6 +450,54 @@ overwriteInstEnv inst_env ins_item@(ClsInst { is_cls_nm = cls_nm, is_tys = tys }
the env is kept ordered, the first match must be the only one. The
thing we are looking up can have an arbitrary "flexi" part.
Note [Rules for instance lookup]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
These functions implement the carefully-written rules in the user
manual section on "overlapping instances". At risk of duplication,
here are the rules. If the rules change, change this text and the
user manual simultaneously. The link may be this:
http://www.haskell.org/ghc/docs/latest/html/users_guide/type-class-extensions.html#instance-overlap
The willingness to be overlapped or incoherent is a property of the
instance declaration itself, controlled as follows:
* An instance is "incoherent"
if it has an INCOHERENT pragama, or
if it appears in a module compiled with -XIncoherentInstances.
* An instance is "overlappable"
if it has an OVERLAPPABLE or OVERLAPS pragama, or
if it appears in a module compiled with -XOverlappingInstances, or
if the instance is incoherent.
* An instance is "overlapping"
if it has an OVERLAPPING or OVERLAPS pragama, or
if it appears in a module compiled with -XOverlappingInstances, or
if the instance is incoherent.
compiled with -XOverlappingInstances.
Now suppose that, in some client module, we are searching for an instance
of the target constraint (C ty1 .. tyn). The search works like this.
* Find all instances I that match the target constraint; that is, the
target constraint is a substitution instance of I. These instance
declarations are the candidates.
* Find all non-candidate instances that unify with the target
constraint. Such non-candidates instances might match when the
target constraint is further instantiated. If all of them are
incoherent, proceed; if not, the search fails.
* Eliminate any candidate IX for which both of the following hold:
* There is another candidate IY that is strictly more specific;
that is, IY is a substitution instance of IX but not vice versa.
* Either IX is overlappable or IY is overlapping.
* If only one candidate remains, pick it. Otherwise if all remaining
candidates are incoherent, pick an arbitrary candidate. Otherwise fail.
\begin{code}
type DFunInstType = Maybe Type
-- Just ty => Instantiate with this type
......@@ -536,7 +581,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] and Note [Incoherent Instances]
-- See Note [Overlapping instances] and Note [Incoherent instances]
| Incoherent <- overlapMode oflag
= find ms us rest
......@@ -566,7 +611,7 @@ lookupInstEnv' ie cls tys
lookupInstEnv :: (InstEnv, InstEnv) -- External and home package inst-env
-> Class -> [Type] -- What we are looking for
-> ClsInstLookupResult
-- ^ See Note [Rules for instance lookup]
lookupInstEnv (pkg_ie, home_ie) cls tys
= (safe_matches, all_unifs, safe_fail)
where
......@@ -606,7 +651,7 @@ lookupInstEnv (pkg_ie, home_ie) cls tys
if inSameMod x
then go bad unchecked
else go (i:bad) unchecked
inSameMod b =
let na = getName $ getName inst
la = isInternalName na
......@@ -617,7 +662,8 @@ lookupInstEnv (pkg_ie, home_ie) cls tys
---------------
---------------
insert_overlapping :: InstMatch -> [InstMatch] -> [InstMatch]
-- Add a new solution, knocking out strictly less specific ones
-- ^ Add a new solution, knocking out strictly less specific ones
-- See Note [Rules for instance lookup]
insert_overlapping new_item [] = [new_item]
insert_overlapping new_item (item:items)
| new_beats_old && old_beats_new = item : insert_overlapping new_item items
......@@ -653,29 +699,25 @@ insert_overlapping new_item (item:items)
Previous change: Trac #3877, Dec 10. -}
overlap_ok = hasOverlappingFlag (overlapMode (is_flag instA))
|| hasOverlappableFlag (overlapMode (is_flag instB))
\end{code}
Note [Incoherent instances]
~~~~~~~~~~~~~~~~~~~~~~~~~~~
For some classes, the choise of a particular instance does not matter, any one
For some classes, the choice of a particular instance does not matter, any one
is good. E.g. consider
class D a b where { opD :: a -> b -> String }
instance D Int b where ...
instance D a Int where ...
g (x::Int) = opD x x
g (x::Int) = opD x x -- Wanted: D Int Int
For such classes this should work (without having to add an "instance D Int
Int", and using -XOverlappingInstances, which would then work). This is what
-XIncoherentInstances is for: Telling GHC "I don't care which instance you use;
if you can use one, use it."
Should this logic only work when all candidates have the incoherent flag, or
Should this logic only work when *all* candidates have the incoherent flag, or
even when all but one have it? The right choice is the latter, which can be
justified by comparing the behaviour with how -XIncoherentInstances worked when
it was only about the unify-check (note [Overlapping instances]):
......@@ -686,7 +728,7 @@ Example:
instance [incoherent] [Int] b c
instance [incoherent] C a Int c
Thanks to the incoherent flags,
foo :: ([a],b,Int)
[Wanted] C [a] b Int
works: Only instance one matches, the others just unify, but are marked
incoherent.
......
......@@ -5060,11 +5060,21 @@ The <option>-XIncoherentInstances</option> flag implies the
<para>
A more precise specification is as follows.
The willingness to be overlapped or incoherent is a property of
the <emphasis>instance declaration</emphasis> itself, controlled by
either an explicit pragma, or the
presence or otherwise of the <option>-XOverlappingInstances</option>
and <option>-XIncoherentInstances</option> flags when that instance declaration is
being compiled. Now suppose that, in some client module, we are searching for an instance of the
the <emphasis>instance declaration</emphasis> itself, controlled as follows:
<itemizedlist>
<listitem><para>An instance is <emphasis>incoherent</emphasis> if it has an <literal>INCOHERENT</literal> pragama, or if it appears in a module compiled with <literal>-XIncoherentInstances</literal>.
</para></listitem>
<listitem><para>An instance is <emphasis>overlappable</emphasis> if it has an <literal>OVERLAPPABLE</literal> or <literal>OVERLAPS</literal> pragama, or if it appears in a module compiled with <literal>-XOverlappingInstances</literal>, or if the instance is incoherent.
</para></listitem>
<listitem><para>An instance is <emphasis>overlapping</emphasis> if it has an <literal>OVERLAPPING</literal> or <literal>OVERLAPS</literal> pragama, or if it appears in a module compiled with <literal>-XOverlappingInstances</literal>, or if the instance is incoherent.
</para></listitem>
</itemizedlist>
The <option>-XOverlappingInstances</option> language extension is now deprecated in favour
per-instance pragmas.
</para>
<para>
Now suppose that, in some client module, we are searching for an instance of the
<emphasis>target constraint</emphasis> <literal>(C ty1 .. tyn)</literal>.
The search works like this.
<itemizedlist>
......@@ -5078,8 +5088,7 @@ instance declarations are the <emphasis>candidates</emphasis>.
Find all <emphasis>non-candidate</emphasis> instances
that <emphasis>unify</emphasis> with the target constraint.
Such non-candidates instances might match when the target constraint is further
instantiated. If all of them were compiled with
<option>-XIncoherentInstances</option>, proceed; if not, the search fails.
instantiated. If all of them are incoherent, proceed; if not, the search fails.
</para></listitem>
<listitem><para>
......@@ -5095,21 +5104,12 @@ Eliminate any candidate IX for which both of the following hold:
</para></listitem>
</itemizedlist>
</para>
<para>
Instance annotated with an <literal>OVERLAPPABLE</literal> or
<literal>OVERLAPPING</literal> pragma are treated as such.
</para>
<para>
Instances annotated with the <literal>OVERLAPS</literal> pragma, or compiled
with <option>-XOverlappingInstances</option>, are treated as both
<emphasis>overlapping</emphasis> and <emphasis>overlappable</emphasis>.
</para>
</listitem>
<listitem><para>
If only one candidate remains, pick it.
Otherwise if all remaining candidates were compiled with
<option>-XInccoherentInstances</option>, pick an arbitrary candidate.
If exactly one non-incoherent candidate remains, pick it. If all
remaining candidates are incoherent, pick an arbitary
one. Otherwise fail.
</para></listitem>
</itemizedlist>
......@@ -5118,7 +5118,7 @@ overlapping instances without the library client having to know.
</para>
<para>
Errors are reported <emphasis>lazily</emphasis> (when attempting to solve a constraint), rather than <emphasis>eagerly</emphasis>
(when the instances themselves are defined). So for example
(when the instances themselves are defined). Consider, for example
<programlisting>
instance C Int b where ..
instance C a Bool where ..
......@@ -5133,20 +5133,19 @@ both instances match and an error is reported.
<para>
As a more substantial example of the rules in action, consider
<programlisting>
instance context1 => C Int b where ... -- (A)
instance context2 => C a Bool where ... -- (B)
instance context3 => C a [b] where ... -- (C)
instance context4 => C Int [Int] where ... -- (D)
instance {-# OVERLAPPABLE #-} context1 => C Int b where ... -- (A)
instance {-# OVERLAPPABLE #-} context2 => C a Bool where ... -- (B)
instance {-# OVERLAPPABLE #-} context3 => C a [b] where ... -- (C)
instance {-# OVERLAPPING #-} context4 => C Int [Int] where ... -- (D)
</programlisting>
compiled with <option>-XOverlappingInstances</option> enabled. Now suppose that the type inference
engine needs to solve The constraint
Now suppose that the type inference
engine needs to solve the constraint
<literal>C Int [Int]</literal>. This constraint matches instances (A), (C) and (D), but the last
is more specific, and hence is chosen.
</para>
<para>If (D) did not exist then (A) and (C) would still be matched, but neither is
most specific. In that case, the program would be rejected even with
<option>-XOverlappingInstances</option>. With
<option>-XIncoherentInstances</option> enabled, it would be accepted and (A) or
most specific. In that case, the program would be rejected, unless
<option>-XIncoherentInstances</option> is enabled, in which case it would be accepted and (A) or
(C) would be chosen arbitrarily.
</para>
<para>
......
......@@ -2,7 +2,6 @@
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE OverlappingInstances #-}
module HTk.Toolkit.TreeList (getObjectFromTreeList) where
......@@ -10,7 +9,7 @@ class Eq c => CItem c
-- A bizarre instance decl!
-- People who use instance decls like this are asking for trouble
instance GUIObject w => Eq w where
instance {-# OVERLAPPABLE #-} GUIObject w => Eq w where
w1 == w2 = toGUIObject w1 == toGUIObject w2
data StateEntry a
......@@ -31,7 +30,7 @@ getObjectFromTreeList state = state == state
data CItem a => TreeListObject a
instance CItem a => Eq (TreeListObject a)
instance {-# OVERLAPPING #-} CItem a => Eq (TreeListObject a)