summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorSimon Peyton Jones <simonpj@microsoft.com>2017-04-06 12:27:43 +0100
committerSimon Peyton Jones <simonpj@microsoft.com>2017-04-06 12:34:01 +0100
commit65b185d4886b4efa3efe3cc5ecc8dd6e07d89afe (patch)
treec8aa39e9fd28f8b4545b4df198d31627b1447edc /compiler
parent2ab7f626b94a5da4b544e01072219a95cd588202 (diff)
downloadhaskell-65b185d4886b4efa3efe3cc5ecc8dd6e07d89afe.tar.gz
Be less aggressive about fragile-context warrnings
In the implementation of WarnSimplifiableClassConstraints, be less aggressive about reporting a problem. We were complaining about a "fragile" case that in fact was not fragile. See Note [Simplifiable given constraints] in TcValidity. This fixes Trac #13526.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/typecheck/TcValidity.hs50
1 files changed, 33 insertions, 17 deletions
diff --git a/compiler/typecheck/TcValidity.hs b/compiler/typecheck/TcValidity.hs
index 3023dfecc0..c28c21da97 100644
--- a/compiler/typecheck/TcValidity.hs
+++ b/compiler/typecheck/TcValidity.hs
@@ -41,7 +41,7 @@ import HsSyn -- HsType
import TcRnMonad -- TcType, amongst others
import TcEnv ( tcGetInstEnvs )
import FunDeps
-import InstEnv ( ClsInst, lookupInstEnv, isOverlappable )
+import InstEnv ( InstMatch, lookupInstEnv )
import FamInstEnv ( isDominatedBy, injectiveBranches,
InjectivityCheckResult(..) )
import FamInst ( makeInjectivityErrors )
@@ -810,7 +810,8 @@ check_class_pred env dflags ctxt pred cls tys
| otherwise
= do { check_arity
- ; check_simplifiable_class_constraint
+ ; warn_simp <- woptM Opt_WarnSimplifiableClassConstraints
+ ; when warn_simp check_simplifiable_class_constraint
; checkTcM arg_tys_ok (predTyVarErr env pred) }
where
check_arity = checkTc (classArity cls == length tys)
@@ -833,25 +834,22 @@ check_class_pred env dflags ctxt pred cls tys
| DataTyCtxt {} <- ctxt -- Don't do this check for the "stupid theta"
= return () -- of a data type declaration
| otherwise
- = do { instEnvs <- tcGetInstEnvs
- ; let (matches, _, _) = lookupInstEnv False instEnvs cls tys
- bad_matches = [ inst | (inst,_) <- matches
- , not (isOverlappable inst) ]
- ; warnIf (Reason Opt_WarnSimplifiableClassConstraints)
- (not (null bad_matches))
- (simplifiable_constraint_warn bad_matches) }
-
- simplifiable_constraint_warn :: [ClsInst] -> SDoc
- simplifiable_constraint_warn (match : _)
+ = do { envs <- tcGetInstEnvs
+ ; case lookupInstEnv False envs cls tys of
+ ([m], [], _) -> addWarnTc (Reason Opt_WarnSimplifiableClassConstraints)
+ (simplifiable_constraint_warn m)
+ _ -> return () }
+
+ simplifiable_constraint_warn :: InstMatch -> SDoc
+ simplifiable_constraint_warn (match, _)
= vcat [ hang (text "The constraint" <+> quotes (ppr (tidyType env pred)))
2 (text "matches an instance declaration")
, ppr match
, hang (text "This makes type inference for inner bindings fragile;")
2 (text "either use MonoLocalBinds, or simplify it using the instance") ]
- simplifiable_constraint_warn [] = pprPanic "check_class_pred" (ppr pred)
{- Note [Simplifiable given constraints]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A type signature like
f :: Eq [(a,b)] => a -> b
is very fragile, for reasons described at length in TcInteract
@@ -862,9 +860,27 @@ fragility. But if we /infer/ the type of a local let-binding, things
can go wrong (Trac #11948 is an example, discussed in the Note).
So this warning is switched on only if we have NoMonoLocalBinds; in
-that case the warning discourages uses from writing simplifiable class
-constraints, at least unless the top-level instance is explicitly
-declared as OVERLAPPABLE.
+that case the warning discourages users from writing simplifiable
+class constraints.
+
+The warning only fires if the constraint in the signature
+matches the top-level instances in only one way, and with no
+unifiers -- that is, under the same circumstances that
+TcInteract.matchInstEnv fires an interaction with the top
+level instances. For example (Trac #13526), consider
+
+ instance {-# OVERLAPPABLE #-} Eq (T a) where ...
+ instance Eq (T Char) where ..
+ f :: Eq (T a) => ...
+
+We don't want to complain about this, even though the context
+(Eq (T a)) matches an instance, because the user may be
+deliberately deferring the choice so that the Eq (T Char)
+has a chance to fire when 'f' is called. And the fragility
+only matters when there's a risk that the instance might
+fire instead of the local 'given'; and there is no such
+risk in this case. Just use the same rules as for instance
+firing!
-}
-------------------------