summaryrefslogtreecommitdiff
path: root/compiler/types/InstEnv.lhs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/types/InstEnv.lhs')
-rw-r--r--compiler/types/InstEnv.lhs108
1 files changed, 75 insertions, 33 deletions
diff --git a/compiler/types/InstEnv.lhs b/compiler/types/InstEnv.lhs
index e1ab8da5c7..636147a461 100644
--- a/compiler/types/InstEnv.lhs
+++ b/compiler/types/InstEnv.lhs
@@ -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.