summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Peyton Jones <simonpj@microsoft.com>2018-07-04 15:17:54 +0100
committerSimon Peyton Jones <simonpj@microsoft.com>2018-07-05 10:44:23 +0100
commit45f44e2c9d5db2f25c52abb402f197c20579400f (patch)
treef2d09ea5cfa5d0c414e9bff8592595081d2610aa
parent14dfdf6a0a3364e2d3ae6f6839ef65bb24df4ebf (diff)
downloadhaskell-45f44e2c9d5db2f25c52abb402f197c20579400f.tar.gz
Refactor validity checking for constraints
There are several changes here. * TcInteract has gotten too big, so I moved all the class-instance matching out of TcInteract into a new module ClsInst. It parallels the FamInst module. The main export of ClsInst is matchGlobalInst. This now works in TcM not TcS. * A big reason to make matchGlobalInst work in TcM is that we can then use it from TcValidity.checkSimplifiableClassConstraint. That extends checkSimplifiableClassConstraint to work uniformly for built-in instances, which means that we now get a warning if we have givens (Typeable x, KnownNat n); see Trac #15322. * This change also made me refactor LookupInstResult, in particular by adding the InstanceWhat field. I also changed the name of the type to ClsInstResult. Then instead of matchGlobalInst reporting a staging error (which is inappropriate for the call from TcValidity), we can do so in TcInteract.checkInstanceOK. * In TcValidity, we now check quantified constraints for termination. For example, this signature should be rejected: f :: (forall a. Eq (m a) => Eq (m a)) => blah as discussed in Trac #15316. The main change here is that TcValidity.check_pred_help now uses classifyPredType, and has a case for ForAllPred which it didn't before. This had knock-on refactoring effects in TcValidity.
-rw-r--r--compiler/ghc.cabal.in1
-rw-r--r--compiler/typecheck/ClsInst.hs586
-rw-r--r--compiler/typecheck/TcInteract.hs634
-rw-r--r--compiler/typecheck/TcSMonad.hs54
-rw-r--r--compiler/typecheck/TcSimplify.hs2
-rw-r--r--compiler/typecheck/TcValidity.hs170
-rw-r--r--testsuite/tests/indexed-types/should_compile/T15322.hs12
-rw-r--r--testsuite/tests/indexed-types/should_compile/T15322.stderr8
-rw-r--r--testsuite/tests/indexed-types/should_compile/T15322a.hs12
-rw-r--r--testsuite/tests/indexed-types/should_compile/T15322a.stderr12
-rw-r--r--testsuite/tests/indexed-types/should_compile/all.T2
-rw-r--r--testsuite/tests/partial-sigs/should_compile/SomethingShowable.stderr4
-rw-r--r--testsuite/tests/polykinds/T11466.stderr4
-rw-r--r--testsuite/tests/quantified-constraints/T15316.hs21
-rw-r--r--testsuite/tests/quantified-constraints/T15316.stderr6
-rw-r--r--testsuite/tests/quantified-constraints/all.T1
-rw-r--r--testsuite/tests/typecheck/should_compile/T10177.hs3
-rw-r--r--testsuite/tests/typecheck/should_compile/T13526.stderr4
-rw-r--r--testsuite/tests/typecheck/should_compile/TcCustomSolverSuper.hs10
-rw-r--r--testsuite/tests/typecheck/should_fail/T8912.stderr4
-rw-r--r--testsuite/tests/typecheck/should_fail/fd-loop.stderr6
-rw-r--r--testsuite/tests/typecheck/should_fail/tcfail157.stderr7
-rw-r--r--testsuite/tests/typecheck/should_fail/tcfail211.stderr4
23 files changed, 881 insertions, 686 deletions
diff --git a/compiler/ghc.cabal.in b/compiler/ghc.cabal.in
index 01628dcad1..d4a1dc3c6e 100644
--- a/compiler/ghc.cabal.in
+++ b/compiler/ghc.cabal.in
@@ -437,6 +437,7 @@ Library
WorkWrap
WwLib
FamInst
+ ClsInst
Inst
TcAnnotations
TcArrows
diff --git a/compiler/typecheck/ClsInst.hs b/compiler/typecheck/ClsInst.hs
new file mode 100644
index 0000000000..b8ab2bfea2
--- /dev/null
+++ b/compiler/typecheck/ClsInst.hs
@@ -0,0 +1,586 @@
+{-# LANGUAGE CPP #-}
+
+module ClsInst (
+ matchGlobalInst,
+ ClsInstResult(..),
+ InstanceWhat(..), safeOverlap
+ ) where
+
+#include "HsVersions.h"
+
+import GhcPrelude
+
+import TcEnv
+import TcRnMonad
+import TcType
+import TcMType
+import TcEvidence
+import RnEnv( addUsedGRE )
+import RdrName( lookupGRE_FieldLabel )
+import InstEnv
+import Inst( instDFunType )
+import FamInst( tcGetFamInstEnvs, tcInstNewTyCon_maybe, tcLookupDataFamInst )
+
+import TysWiredIn
+import TysPrim( eqPrimTyCon, eqReprPrimTyCon )
+import PrelNames
+
+import Id
+import Type
+import Kind( isConstraintKind )
+import MkCore ( mkStringExprFS, mkNaturalExpr )
+
+import Unique ( hasKey )
+import Name ( Name )
+import Var ( DFunId )
+import DataCon
+import TyCon
+import Class
+import DynFlags
+import Outputable
+import Util( splitAtList, fstOf3 )
+import Data.Maybe
+
+{- *******************************************************************
+* *
+ Class lookup
+* *
+**********************************************************************-}
+
+-- | Indicates if Instance met the Safe Haskell overlapping instances safety
+-- check.
+--
+-- See Note [Safe Haskell Overlapping Instances] in TcSimplify
+-- See Note [Safe Haskell Overlapping Instances Implementation] in TcSimplify
+type SafeOverlapping = Bool
+
+data ClsInstResult
+ = NoInstance -- Definitely no instance
+
+ | OneInst { cir_new_theta :: [TcPredType]
+ , cir_mk_ev :: [EvExpr] -> EvTerm
+ , cir_what :: InstanceWhat }
+
+ | NotSure -- Multiple matches and/or one or more unifiers
+
+data InstanceWhat
+ = BuiltinInstance
+ | LocalInstance
+ | TopLevInstance { iw_dfun_id :: DFunId
+ , iw_safe_over :: SafeOverlapping }
+
+instance Outputable ClsInstResult where
+ ppr NoInstance = text "NoInstance"
+ ppr NotSure = text "NotSure"
+ ppr (OneInst { cir_new_theta = ev
+ , cir_what = what })
+ = text "OneInst" <+> vcat [ppr ev, ppr what]
+
+instance Outputable InstanceWhat where
+ ppr BuiltinInstance = text "built-in instance"
+ ppr LocalInstance = text "locally-quantified instance"
+ ppr (TopLevInstance { iw_safe_over = so })
+ = text "top-level instance" <+> (text $ if so then "[safe]" else "[unsafe]")
+
+safeOverlap :: InstanceWhat -> Bool
+safeOverlap (TopLevInstance { iw_safe_over = so }) = so
+safeOverlap _ = True
+
+matchGlobalInst :: DynFlags
+ -> Bool -- True <=> caller is the short-cut solver
+ -- See Note [Shortcut solving: overlap]
+ -> Class -> [Type] -> TcM ClsInstResult
+matchGlobalInst dflags short_cut clas tys
+ | cls_name == knownNatClassName = matchKnownNat clas tys
+ | cls_name == knownSymbolClassName = matchKnownSymbol clas tys
+ | isCTupleClass clas = matchCTuple clas tys
+ | cls_name == typeableClassName = matchTypeable clas tys
+ | clas `hasKey` heqTyConKey = matchLiftedEquality tys
+ | clas `hasKey` coercibleTyConKey = matchLiftedCoercible tys
+ | cls_name == hasFieldClassName = matchHasField dflags short_cut clas tys
+ | otherwise = matchInstEnv dflags short_cut clas tys
+ where
+ cls_name = className clas
+
+
+{- ********************************************************************
+* *
+ Looking in the instance environment
+* *
+***********************************************************************-}
+
+
+matchInstEnv :: DynFlags -> Bool -> Class -> [Type] -> TcM ClsInstResult
+matchInstEnv dflags short_cut_solver clas tys
+ = do { instEnvs <- tcGetInstEnvs
+ ; let safeOverlapCheck = safeHaskell dflags `elem` [Sf_Safe, Sf_Trustworthy]
+ (matches, unify, unsafeOverlaps) = lookupInstEnv True instEnvs clas tys
+ safeHaskFail = safeOverlapCheck && not (null unsafeOverlaps)
+ ; traceTc "matchInstEnv" $
+ vcat [ text "goal:" <+> ppr clas <+> ppr tys
+ , text "matches:" <+> ppr matches
+ , text "unify:" <+> ppr unify ]
+ ; case (matches, unify, safeHaskFail) of
+
+ -- Nothing matches
+ ([], [], _)
+ -> do { traceTc "matchClass not matching" (ppr pred)
+ ; return NoInstance }
+
+ -- A single match (& no safe haskell failure)
+ ([(ispec, inst_tys)], [], False)
+ | short_cut_solver -- Called from the short-cut solver
+ , isOverlappable ispec
+ -- If the instance has OVERLAPPABLE or OVERLAPS or INCOHERENT
+ -- then don't let the short-cut solver choose it, because a
+ -- later instance might overlap it. Trac #14434 is an example
+ -- See Note [Shortcut solving: overlap]
+ -> do { traceTc "matchClass: ignoring overlappable" (ppr pred)
+ ; return NotSure }
+
+ | otherwise
+ -> do { let dfun_id = instanceDFunId ispec
+ ; traceTc "matchClass success" $
+ vcat [text "dict" <+> ppr pred,
+ text "witness" <+> ppr dfun_id
+ <+> ppr (idType dfun_id) ]
+ -- Record that this dfun is needed
+ ; match_one (null unsafeOverlaps) dfun_id inst_tys }
+
+ -- More than one matches (or Safe Haskell fail!). Defer any
+ -- reactions of a multitude until we learn more about the reagent
+ _ -> do { traceTc "matchClass multiple matches, deferring choice" $
+ vcat [text "dict" <+> ppr pred,
+ text "matches" <+> ppr matches]
+ ; return NotSure } }
+ where
+ pred = mkClassPred clas tys
+
+match_one :: SafeOverlapping -> DFunId -> [DFunInstType] -> TcM ClsInstResult
+ -- See Note [DFunInstType: instantiating types] in InstEnv
+match_one so dfun_id mb_inst_tys
+ = do { traceTc "match_one" (ppr dfun_id $$ ppr mb_inst_tys)
+ ; (tys, theta) <- instDFunType dfun_id mb_inst_tys
+ ; traceTc "match_one 2" (ppr dfun_id $$ ppr tys $$ ppr theta)
+ ; return $ OneInst { cir_new_theta = theta
+ , cir_mk_ev = evDFunApp dfun_id tys
+ , cir_what = TopLevInstance { iw_dfun_id = dfun_id
+ , iw_safe_over = so } } }
+
+
+{- ********************************************************************
+* *
+ Class lookup for CTuples
+* *
+***********************************************************************-}
+
+matchCTuple :: Class -> [Type] -> TcM ClsInstResult
+matchCTuple clas tys -- (isCTupleClass clas) holds
+ = return (OneInst { cir_new_theta = tys
+ , cir_mk_ev = tuple_ev
+ , cir_what = BuiltinInstance })
+ -- The dfun *is* the data constructor!
+ where
+ data_con = tyConSingleDataCon (classTyCon clas)
+ tuple_ev = evDFunApp (dataConWrapId data_con) tys
+
+{- ********************************************************************
+* *
+ Class lookup for Literals
+* *
+***********************************************************************-}
+
+{-
+Note [KnownNat & KnownSymbol and EvLit]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+A part of the type-level literals implementation are the classes
+"KnownNat" and "KnownSymbol", which provide a "smart" constructor for
+defining singleton values. Here is the key stuff from GHC.TypeLits
+
+ class KnownNat (n :: Nat) where
+ natSing :: SNat n
+
+ newtype SNat (n :: Nat) = SNat Integer
+
+Conceptually, this class has infinitely many instances:
+
+ instance KnownNat 0 where natSing = SNat 0
+ instance KnownNat 1 where natSing = SNat 1
+ instance KnownNat 2 where natSing = SNat 2
+ ...
+
+In practice, we solve `KnownNat` predicates in the type-checker
+(see typecheck/TcInteract.hs) because we can't have infinitely many instances.
+The evidence (aka "dictionary") for `KnownNat` is of the form `EvLit (EvNum n)`.
+
+We make the following assumptions about dictionaries in GHC:
+ 1. The "dictionary" for classes with a single method---like `KnownNat`---is
+ a newtype for the type of the method, so using a evidence amounts
+ to a coercion, and
+ 2. Newtypes use the same representation as their definition types.
+
+So, the evidence for `KnownNat` is just a value of the representation type,
+wrapped in two newtype constructors: one to make it into a `SNat` value,
+and another to make it into a `KnownNat` dictionary.
+
+Also note that `natSing` and `SNat` are never actually exposed from the
+library---they are just an implementation detail. Instead, users see
+a more convenient function, defined in terms of `natSing`:
+
+ natVal :: KnownNat n => proxy n -> Integer
+
+The reason we don't use this directly in the class is that it is simpler
+and more efficient to pass around an integer rather than an entire function,
+especially when the `KnowNat` evidence is packaged up in an existential.
+
+The story for kind `Symbol` is analogous:
+ * class KnownSymbol
+ * newtype SSymbol
+ * Evidence: a Core literal (e.g. mkNaturalExpr)
+-}
+
+matchKnownNat :: Class -> [Type] -> TcM ClsInstResult
+matchKnownNat clas [ty] -- clas = KnownNat
+ | Just n <- isNumLitTy ty = do
+ et <- mkNaturalExpr n
+ makeLitDict clas ty et
+matchKnownNat _ _ = return NoInstance
+
+matchKnownSymbol :: Class -> [Type] -> TcM ClsInstResult
+matchKnownSymbol clas [ty] -- clas = KnownSymbol
+ | Just s <- isStrLitTy ty = do
+ et <- mkStringExprFS s
+ makeLitDict clas ty et
+matchKnownSymbol _ _ = return NoInstance
+
+makeLitDict :: Class -> Type -> EvExpr -> TcM ClsInstResult
+-- makeLitDict adds a coercion that will convert the literal into a dictionary
+-- of the appropriate type. See Note [KnownNat & KnownSymbol and EvLit]
+-- in TcEvidence. The coercion happens in 2 steps:
+--
+-- Integer -> SNat n -- representation of literal to singleton
+-- SNat n -> KnownNat n -- singleton to dictionary
+--
+-- The process is mirrored for Symbols:
+-- String -> SSymbol n
+-- SSymbol n -> KnownSymbol n
+makeLitDict clas ty et
+ | Just (_, co_dict) <- tcInstNewTyCon_maybe (classTyCon clas) [ty]
+ -- co_dict :: KnownNat n ~ SNat n
+ , [ meth ] <- classMethods clas
+ , Just tcRep <- tyConAppTyCon_maybe -- SNat
+ $ funResultTy -- SNat n
+ $ dropForAlls -- KnownNat n => SNat n
+ $ idType meth -- forall n. KnownNat n => SNat n
+ , Just (_, co_rep) <- tcInstNewTyCon_maybe tcRep [ty]
+ -- SNat n ~ Integer
+ , let ev_tm = mkEvCast et (mkTcSymCo (mkTcTransCo co_dict co_rep))
+ = return $ OneInst { cir_new_theta = []
+ , cir_mk_ev = \_ -> ev_tm
+ , cir_what = BuiltinInstance }
+
+ | otherwise
+ = pprPanic "makeLitDict" $
+ text "Unexpected evidence for" <+> ppr (className clas)
+ $$ vcat (map (ppr . idType) (classMethods clas))
+
+{- ********************************************************************
+* *
+ Class lookup for Typeable
+* *
+***********************************************************************-}
+
+-- | Assumes that we've checked that this is the 'Typeable' class,
+-- and it was applied to the correct argument.
+matchTypeable :: Class -> [Type] -> TcM ClsInstResult
+matchTypeable clas [k,t] -- clas = Typeable
+ -- For the first two cases, See Note [No Typeable for polytypes or qualified types]
+ | isForAllTy k = return NoInstance -- Polytype
+ | isJust (tcSplitPredFunTy_maybe t) = return NoInstance -- Qualified type
+
+ -- Now cases that do work
+ | k `eqType` typeNatKind = doTyLit knownNatClassName t
+ | k `eqType` typeSymbolKind = doTyLit knownSymbolClassName t
+ | isConstraintKind t = doTyConApp clas t constraintKindTyCon []
+ | Just (arg,ret) <- splitFunTy_maybe t = doFunTy clas t arg ret
+ | Just (tc, ks) <- splitTyConApp_maybe t -- See Note [Typeable (T a b c)]
+ , onlyNamedBndrsApplied tc ks = doTyConApp clas t tc ks
+ | Just (f,kt) <- splitAppTy_maybe t = doTyApp clas t f kt
+
+matchTypeable _ _ = return NoInstance
+
+-- | Representation for a type @ty@ of the form @arg -> ret@.
+doFunTy :: Class -> Type -> Type -> Type -> TcM ClsInstResult
+doFunTy clas ty arg_ty ret_ty
+ = return $ OneInst { cir_new_theta = preds
+ , cir_mk_ev = mk_ev
+ , cir_what = BuiltinInstance }
+ where
+ preds = map (mk_typeable_pred clas) [arg_ty, ret_ty]
+ mk_ev [arg_ev, ret_ev] = evTypeable ty $
+ EvTypeableTrFun (EvExpr arg_ev) (EvExpr ret_ev)
+ mk_ev _ = panic "TcInteract.doFunTy"
+
+
+-- | Representation for type constructor applied to some kinds.
+-- 'onlyNamedBndrsApplied' has ensured that this application results in a type
+-- of monomorphic kind (e.g. all kind variables have been instantiated).
+doTyConApp :: Class -> Type -> TyCon -> [Kind] -> TcM ClsInstResult
+doTyConApp clas ty tc kind_args
+ | Just _ <- tyConRepName_maybe tc
+ = return $ OneInst { cir_new_theta = (map (mk_typeable_pred clas) kind_args)
+ , cir_mk_ev = mk_ev
+ , cir_what = BuiltinInstance }
+ | otherwise
+ = return NoInstance
+ where
+ mk_ev kinds = evTypeable ty $ EvTypeableTyCon tc (map EvExpr kinds)
+
+-- | Representation for TyCon applications of a concrete kind. We just use the
+-- kind itself, but first we must make sure that we've instantiated all kind-
+-- polymorphism, but no more.
+onlyNamedBndrsApplied :: TyCon -> [KindOrType] -> Bool
+onlyNamedBndrsApplied tc ks
+ = all isNamedTyConBinder used_bndrs &&
+ not (any isNamedTyConBinder leftover_bndrs)
+ where
+ bndrs = tyConBinders tc
+ (used_bndrs, leftover_bndrs) = splitAtList ks bndrs
+
+doTyApp :: Class -> Type -> Type -> KindOrType -> TcM ClsInstResult
+-- Representation for an application of a type to a type-or-kind.
+-- This may happen when the type expression starts with a type variable.
+-- Example (ignoring kind parameter):
+-- Typeable (f Int Char) -->
+-- (Typeable (f Int), Typeable Char) -->
+-- (Typeable f, Typeable Int, Typeable Char) --> (after some simp. steps)
+-- Typeable f
+doTyApp clas ty f tk
+ | isForAllTy (typeKind f)
+ = return NoInstance -- We can't solve until we know the ctr.
+ | otherwise
+ = return $ OneInst { cir_new_theta = map (mk_typeable_pred clas) [f, tk]
+ , cir_mk_ev = mk_ev
+ , cir_what = BuiltinInstance }
+ where
+ mk_ev [t1,t2] = evTypeable ty $ EvTypeableTyApp (EvExpr t1) (EvExpr t2)
+ mk_ev _ = panic "doTyApp"
+
+
+-- Emit a `Typeable` constraint for the given type.
+mk_typeable_pred :: Class -> Type -> PredType
+mk_typeable_pred clas ty = mkClassPred clas [ typeKind ty, ty ]
+
+ -- Typeable is implied by KnownNat/KnownSymbol. In the case of a type literal
+ -- we generate a sub-goal for the appropriate class.
+ -- See Note [Typeable for Nat and Symbol]
+doTyLit :: Name -> Type -> TcM ClsInstResult
+doTyLit kc t = do { kc_clas <- tcLookupClass kc
+ ; let kc_pred = mkClassPred kc_clas [ t ]
+ mk_ev [ev] = evTypeable t $ EvTypeableTyLit (EvExpr ev)
+ mk_ev _ = panic "doTyLit"
+ ; return (OneInst { cir_new_theta = [kc_pred]
+ , cir_mk_ev = mk_ev
+ , cir_what = BuiltinInstance }) }
+
+{- Note [Typeable (T a b c)]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+For type applications we always decompose using binary application,
+via doTyApp, until we get to a *kind* instantiation. Example
+ Proxy :: forall k. k -> *
+
+To solve Typeable (Proxy (* -> *) Maybe) we
+ - First decompose with doTyApp,
+ to get (Typeable (Proxy (* -> *))) and Typeable Maybe
+ - Then solve (Typeable (Proxy (* -> *))) with doTyConApp
+
+If we attempt to short-cut by solving it all at once, via
+doTyConApp
+
+(this note is sadly truncated FIXME)
+
+
+Note [No Typeable for polytypes or qualified types]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We do not support impredicative typeable, such as
+ Typeable (forall a. a->a)
+ Typeable (Eq a => a -> a)
+ Typeable (() => Int)
+ Typeable (((),()) => Int)
+
+See Trac #9858. For forall's the case is clear: we simply don't have
+a TypeRep for them. For qualified but not polymorphic types, like
+(Eq a => a -> a), things are murkier. But:
+
+ * We don't need a TypeRep for these things. TypeReps are for
+ monotypes only.
+
+ * Perhaps we could treat `=>` as another type constructor for `Typeable`
+ purposes, and thus support things like `Eq Int => Int`, however,
+ at the current state of affairs this would be an odd exception as
+ no other class works with impredicative types.
+ For now we leave it off, until we have a better story for impredicativity.
+
+
+Note [Typeable for Nat and Symbol]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We have special Typeable instances for Nat and Symbol. Roughly we
+have this instance, implemented here by doTyLit:
+ instance KnownNat n => Typeable (n :: Nat) where
+ typeRep = tyepNatTypeRep @n
+where
+ Data.Typeable.Internals.typeNatTypeRep :: KnownNat a => TypeRep a
+
+Ultimately typeNatTypeRep uses 'natSing' from KnownNat to get a
+runtime value 'n'; it turns it into a string with 'show' and uses
+that to whiz up a TypeRep TyCon for 'n', with mkTypeLitTyCon.
+See #10348.
+
+Because of this rule it's inadvisable (see #15322) to have a constraint
+ f :: (Typeable (n :: Nat)) => blah
+in a function signature; it gives rise to overlap problems just as
+if you'd written
+ f :: Eq [a] => blah
+-}
+
+{- ********************************************************************
+* *
+ Class lookup for lifted equality
+* *
+***********************************************************************-}
+
+-- See also Note [The equality types story] in TysPrim
+matchLiftedEquality :: [Type] -> TcM ClsInstResult
+matchLiftedEquality args
+ = return (OneInst { cir_new_theta = [ mkTyConApp eqPrimTyCon args ]
+ , cir_mk_ev = evDFunApp (dataConWrapId heqDataCon) args
+ , cir_what = BuiltinInstance })
+
+-- See also Note [The equality types story] in TysPrim
+matchLiftedCoercible :: [Type] -> TcM ClsInstResult
+matchLiftedCoercible args@[k, t1, t2]
+ = return (OneInst { cir_new_theta = [ mkTyConApp eqReprPrimTyCon args' ]
+ , cir_mk_ev = evDFunApp (dataConWrapId coercibleDataCon)
+ args
+ , cir_what = BuiltinInstance })
+ where
+ args' = [k, k, t1, t2]
+matchLiftedCoercible args = pprPanic "matchLiftedCoercible" (ppr args)
+
+
+{- ********************************************************************
+* *
+ Class lookup for overloaded record fields
+* *
+***********************************************************************-}
+
+{-
+Note [HasField instances]
+~~~~~~~~~~~~~~~~~~~~~~~~~
+Suppose we have
+
+ data T y = MkT { foo :: [y] }
+
+and `foo` is in scope. Then GHC will automatically solve a constraint like
+
+ HasField "foo" (T Int) b
+
+by emitting a new wanted
+
+ T alpha -> [alpha] ~# T Int -> b
+
+and building a HasField dictionary out of the selector function `foo`,
+appropriately cast.
+
+The HasField class is defined (in GHC.Records) thus:
+
+ class HasField (x :: k) r a | x r -> a where
+ getField :: r -> a
+
+Since this is a one-method class, it is represented as a newtype.
+Hence we can solve `HasField "foo" (T Int) b` by taking an expression
+of type `T Int -> b` and casting it using the newtype coercion.
+Note that
+
+ foo :: forall y . T y -> [y]
+
+so the expression we construct is
+
+ foo @alpha |> co
+
+where
+
+ co :: (T alpha -> [alpha]) ~# HasField "foo" (T Int) b
+
+is built from
+
+ co1 :: (T alpha -> [alpha]) ~# (T Int -> b)
+
+which is the new wanted, and
+
+ co2 :: (T Int -> b) ~# HasField "foo" (T Int) b
+
+which can be derived from the newtype coercion.
+
+If `foo` is not in scope, or has a higher-rank or existentially
+quantified type, then the constraint is not solved automatically, but
+may be solved by a user-supplied HasField instance. Similarly, if we
+encounter a HasField constraint where the field is not a literal
+string, or does not belong to the type, then we fall back on the
+normal constraint solver behaviour.
+-}
+
+-- See Note [HasField instances]
+matchHasField :: DynFlags -> Bool -> Class -> [Type] -> TcM ClsInstResult
+matchHasField dflags short_cut clas tys
+ = do { fam_inst_envs <- tcGetFamInstEnvs
+ ; rdr_env <- getGlobalRdrEnv
+ ; case tys of
+ -- We are matching HasField {k} x r a...
+ [_k_ty, x_ty, r_ty, a_ty]
+ -- x should be a literal string
+ | Just x <- isStrLitTy x_ty
+ -- r should be an applied type constructor
+ , Just (tc, args) <- tcSplitTyConApp_maybe r_ty
+ -- use representation tycon (if data family); it has the fields
+ , let r_tc = fstOf3 (tcLookupDataFamInst fam_inst_envs tc args)
+ -- x should be a field of r
+ , Just fl <- lookupTyConFieldLabel x r_tc
+ -- the field selector should be in scope
+ , Just gre <- lookupGRE_FieldLabel rdr_env fl
+
+ -> do { sel_id <- tcLookupId (flSelector fl)
+ ; (tv_prs, preds, sel_ty) <- tcInstType newMetaTyVars sel_id
+
+ -- The first new wanted constraint equates the actual
+ -- type of the selector with the type (r -> a) within
+ -- the HasField x r a dictionary. The preds will
+ -- typically be empty, but if the datatype has a
+ -- "stupid theta" then we have to include it here.
+ ; let theta = mkPrimEqPred sel_ty (mkFunTy r_ty a_ty) : preds
+
+ -- Use the equality proof to cast the selector Id to
+ -- type (r -> a), then use the newtype coercion to cast
+ -- it to a HasField dictionary.
+ mk_ev (ev1:evs) = evSelector sel_id tvs evs `evCast` co
+ where
+ co = mkTcSubCo (evTermCoercion (EvExpr ev1))
+ `mkTcTransCo` mkTcSymCo co2
+ mk_ev [] = panic "matchHasField.mk_ev"
+
+ Just (_, co2) = tcInstNewTyCon_maybe (classTyCon clas)
+ tys
+
+ tvs = mkTyVarTys (map snd tv_prs)
+
+ -- The selector must not be "naughty" (i.e. the field
+ -- cannot have an existentially quantified type), and
+ -- it must not be higher-rank.
+ ; if not (isNaughtyRecordSelector sel_id) && isTauTy sel_ty
+ then do { addUsedGRE True gre
+ ; return OneInst { cir_new_theta = theta
+ , cir_mk_ev = mk_ev
+ , cir_what = BuiltinInstance } }
+ else matchInstEnv dflags short_cut clas tys }
+
+ _ -> matchInstEnv dflags short_cut clas tys }
diff --git a/compiler/typecheck/TcInteract.hs b/compiler/typecheck/TcInteract.hs
index 5d3a98854c..18d952501d 100644
--- a/compiler/typecheck/TcInteract.hs
+++ b/compiler/typecheck/TcInteract.hs
@@ -8,7 +8,6 @@ module TcInteract (
#include "HsVersions.h"
import GhcPrelude
-
import BasicTypes ( SwapFlag(..), isSwapped,
infinity, IntWithInf, intGtLimit )
import TcCanonical
@@ -16,38 +15,23 @@ import TcFlatten
import TcUnify( canSolveByUnification )
import VarSet
import Type
-import Kind( isConstraintKind )
-import InstEnv( DFunInstType, lookupInstEnv
- , instanceDFunId, isOverlappable )
+import InstEnv( DFunInstType )
import CoAxiom( sfInteractTop, sfInteractInert )
-import TcMType (newMetaTyVars)
-
import Var
import TcType
-import Name
-import RdrName ( lookupGRE_FieldLabel )
-import PrelNames ( knownNatClassName, knownSymbolClassName,
- typeableClassName,
- coercibleTyConKey,
- hasFieldClassName,
+import PrelNames ( coercibleTyConKey,
heqTyConKey, eqTyConKey, ipClassKey )
-import TysWiredIn ( typeNatKind, typeSymbolKind, heqDataCon,
- coercibleDataCon, constraintKindTyCon )
-import TysPrim ( eqPrimTyCon, eqReprPrimTyCon )
-import Id( idType, isNaughtyRecordSelector )
import CoAxiom ( TypeEqn, CoAxiom(..), CoAxBranch(..), fromBranches )
import Class
import TyCon
-import DataCon( dataConWrapId )
-import FieldLabel
import FunDeps
import FamInst
+import ClsInst( ClsInstResult(..), InstanceWhat(..), safeOverlap )
import FamInstEnv
import Unify ( tcUnifyTyWithTFs, ruleMatchTyKiX )
import TcEvidence
-import MkCore ( mkStringExprFS, mkNaturalExpr )
import Outputable
import TcRnTypes
@@ -1127,21 +1111,20 @@ shortCutSolver dflags ev_w ev_i
| let pred = ctEvPred ev
loc = ctEvLoc ev
, ClassPred cls tys <- classifyPredType pred
- = do { inst_res <- lift $ matchGlobalInst dflags True cls tys loc
+ = do { inst_res <- lift $ matchGlobalInst dflags True cls tys
; case inst_res of
- OneInst { lir_new_theta = preds
- , lir_mk_ev = mk_ev
- , lir_safe_over = safeOverlap }
- | safeOverlap
+ OneInst { cir_new_theta = preds
+ , cir_mk_ev = mk_ev
+ , cir_what = what }
+ | safeOverlap what
, all isTyFamFree preds -- Note [Shortcut solving: type families]
-> do { let solved_dicts' = addDict solved_dicts cls tys ev
- loc' = bumpCtLocDepth loc
-- solved_dicts': it is important that we add our goal
-- to the cache before we solve! Otherwise we may end
-- up in a loop while solving recursive dictionaries.
; lift $ traceTcS "shortCutSolver: found instance" (ppr preds)
- ; lift $ checkReductionDepth loc pred
+ ; loc' <- lift $ checkInstanceOK loc what pred
; evc_vs <- mapM (new_wanted_cached loc' solved_dicts') preds
-- Emit work for subgoals but use our local cache
@@ -2232,8 +2215,9 @@ doTopReactDict inerts work_item@(CDictCan { cc_ev = ev, cc_class = cls
= do { dflags <- getDynFlags
; lkup_res <- matchClassInst dflags inerts cls xis dict_loc
; case lkup_res of
- OneInst { lir_safe_over = s }
- -> do { unless s $ insertSafeOverlapFailureTcS work_item
+ OneInst { cir_what = what }
+ -> do { unless (safeOverlap what) $
+ insertSafeOverlapFailureTcS work_item
; when (isWanted ev) $ addSolvedDict ev cls xis
; chooseInstance work_item lkup_res }
_ -> -- NoInstance or NotSure
@@ -2264,53 +2248,66 @@ doTopReactDict inerts work_item@(CDictCan { cc_ev = ev, cc_class = cls
doTopReactDict _ w = pprPanic "doTopReactDict" (ppr w)
-chooseInstance :: Ct -> LookupInstResult -> TcS (StopOrContinue Ct)
+chooseInstance :: Ct -> ClsInstResult -> TcS (StopOrContinue Ct)
chooseInstance work_item
- (OneInst { lir_new_theta = theta
- , lir_mk_ev = mk_ev })
+ (OneInst { cir_new_theta = theta
+ , cir_what = what
+ , cir_mk_ev = mk_ev })
= do { traceTcS "doTopReact/found instance for" $ ppr ev
- ; checkReductionDepth deeper_loc pred
- ; if isDerived ev then finish_derived theta
- else finish_wanted theta mk_ev }
+ ; deeper_loc <- checkInstanceOK loc what pred
+ ; if isDerived ev then finish_derived deeper_loc theta
+ else finish_wanted deeper_loc theta mk_ev }
where
ev = ctEvidence work_item
pred = ctEvPred ev
loc = ctEvLoc ev
- origin = ctLocOrigin loc
- deeper_loc = zap_origin (bumpCtLocDepth loc)
-
- zap_origin loc -- After applying an instance we can set ScOrigin to
- -- infinity, so that prohibitedSuperClassSolve never fires
- | ScOrigin {} <- origin
- = setCtLocOrigin loc (ScOrigin infinity)
- | otherwise
- = loc
- finish_wanted :: [TcPredType]
+ finish_wanted :: CtLoc -> [TcPredType]
-> ([EvExpr] -> EvTerm) -> TcS (StopOrContinue Ct)
-- Precondition: evidence term matches the predicate workItem
- finish_wanted theta mk_ev
+ finish_wanted loc theta mk_ev
= do { evb <- getTcEvBindsVar
; if isNoEvBindsVar evb
then -- See Note [Instances in no-evidence implications]
continueWith work_item
else
- do { evc_vars <- mapM (newWanted deeper_loc) theta
+ do { evc_vars <- mapM (newWanted loc) theta
; setEvBindIfWanted ev (mk_ev (map getEvExpr evc_vars))
; emitWorkNC (freshGoals evc_vars)
; stopWith ev "Dict/Top (solved wanted)" } }
- finish_derived theta -- Use type-class instances for Deriveds, in the hope
- = -- of generating some improvements
- -- C.f. Example 3 of Note [The improvement story]
- -- It's easy because no evidence is involved
- do { emitNewDeriveds deeper_loc theta
- ; traceTcS "finish_derived" (ppr (ctl_depth deeper_loc))
+ finish_derived loc theta
+ = -- Use type-class instances for Deriveds, in the hope
+ -- of generating some improvements
+ -- C.f. Example 3 of Note [The improvement story]
+ -- It's easy because no evidence is involved
+ do { emitNewDeriveds loc theta
+ ; traceTcS "finish_derived" (ppr (ctl_depth loc))
; stopWith ev "Dict/Top (solved derived)" }
chooseInstance work_item lookup_res
= pprPanic "chooseInstance" (ppr work_item $$ ppr lookup_res)
+checkInstanceOK :: CtLoc -> InstanceWhat -> TcPredType -> TcS CtLoc
+-- Check that it's OK to use this insstance:
+-- (a) the use is well staged in the Template Haskell sense
+-- (b) we have not recursed too deep
+-- Returns the CtLoc to used for sub-goals
+checkInstanceOK loc what pred
+ = do { checkWellStagedDFun loc what pred
+ ; checkReductionDepth deeper_loc pred
+ ; return deeper_loc }
+ where
+ deeper_loc = zap_origin (bumpCtLocDepth loc)
+ origin = ctLocOrigin loc
+
+ zap_origin loc -- After applying an instance we can set ScOrigin to
+ -- infinity, so that prohibitedSuperClassSolve never fires
+ | ScOrigin {} <- origin
+ = setCtLocOrigin loc (ScOrigin infinity)
+ | otherwise
+ = loc
+
{- Note [Instances in no-evidence implications]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In Trac #15290 we had
@@ -2331,40 +2328,10 @@ This test arranges to ignore the instance-based solution under these
(rare) circumstances. It's sad, but I really don't see what else we can do.
-}
-{- *******************************************************************
-* *
- Class lookup
-* *
-**********************************************************************-}
-
--- | Indicates if Instance met the Safe Haskell overlapping instances safety
--- check.
---
--- See Note [Safe Haskell Overlapping Instances] in TcSimplify
--- See Note [Safe Haskell Overlapping Instances Implementation] in TcSimplify
-type SafeOverlapping = Bool
-
-data LookupInstResult
- = NoInstance -- Definitely no instance
-
- | OneInst { lir_new_theta :: [TcPredType]
- , lir_mk_ev :: [EvExpr] -> EvTerm
- , lir_safe_over :: SafeOverlapping }
-
- | NotSure -- Multiple matches and/or one or more unifiers
-
-instance Outputable LookupInstResult where
- ppr NoInstance = text "NoInstance"
- ppr NotSure = text "NotSure"
- ppr (OneInst { lir_new_theta = ev
- , lir_safe_over = s })
- = text "OneInst" <+> vcat [ppr ev, ss]
- where ss = text $ if s then "[safe]" else "[unsafe]"
-
matchClassInst :: DynFlags -> InertSet
-> Class -> [Type]
- -> CtLoc -> TcS LookupInstResult
+ -> CtLoc -> TcS ClsInstResult
matchClassInst dflags inerts clas tys loc
-- First check whether there is an in-scope Given that could
-- match this constraint. In that case, do not use any instance
@@ -2393,28 +2360,12 @@ matchClassInst dflags inerts clas tys loc
; return local_res }
NoInstance -- No local instances, so try global ones
- -> do { global_res <- matchGlobalInst dflags False clas tys loc
+ -> do { global_res <- matchGlobalInst dflags False clas tys
; traceTcS "} matchClassInst global result" $ ppr global_res
; return global_res } }
where
pred = mkClassPred clas tys
-matchGlobalInst :: DynFlags
- -> Bool -- True <=> caller is the short-cut solver
- -- See Note [Shortcut solving: overlap]
- -> Class -> [Type] -> CtLoc -> TcS LookupInstResult
-matchGlobalInst dflags short_cut clas tys loc
- | cls_name == knownNatClassName = matchKnownNat clas tys
- | cls_name == knownSymbolClassName = matchKnownSymbol clas tys
- | isCTupleClass clas = matchCTuple clas tys
- | cls_name == typeableClassName = matchTypeable clas tys
- | clas `hasKey` heqTyConKey = matchLiftedEquality tys
- | clas `hasKey` coercibleTyConKey = matchLiftedCoercible tys
- | cls_name == hasFieldClassName = matchHasField dflags short_cut clas tys loc
- | otherwise = matchInstEnv dflags short_cut clas tys loc
- where
- cls_name = className clas
-
-- | If a class is "naturally coherent", then we needn't worry at all, in any
-- way, about overlapping/incoherent instances. Just solve the thing!
-- See Note [Naturally coherent classes]
@@ -2581,7 +2532,7 @@ those instances to build evidence to pass to f. That's just the
nullary case of what's happening here.
-}
-matchLocalInst :: TcPredType -> CtLoc -> TcS LookupInstResult
+matchLocalInst :: TcPredType -> CtLoc -> TcS ClsInstResult
-- Try any Given quantified constraints, which are
-- effectively just local instance declarations.
matchLocalInst pred loc
@@ -2590,7 +2541,11 @@ matchLocalInst pred loc
([], False) -> return NoInstance
([(dfun_ev, inst_tys)], unifs)
| not unifs
- -> match_one pred loc True (ctEvEvId dfun_ev) inst_tys
+ -> do { let dfun_id = ctEvEvId dfun_ev
+ ; (tys, theta) <- instDFunType dfun_id inst_tys
+ ; return $ OneInst { cir_new_theta = theta
+ , cir_mk_ev = evDFunApp dfun_id tys
+ , cir_what = LocalInstance } }
_ -> return NotSure }
where
pred_tv_set = tyCoVarsOfType pred
@@ -2620,478 +2575,3 @@ matchLocalInst pred loc
this_unif = mightMatchLater qpred (ctEvLoc ev) pred loc
(matches, unif) = match_local_inst qcis
-matchInstEnv :: DynFlags -> Bool -> Class -> [Type] -> CtLoc -> TcS LookupInstResult
-matchInstEnv dflags short_cut_solver clas tys loc
- = do { instEnvs <- getInstEnvs
- ; let safeOverlapCheck = safeHaskell dflags `elem` [Sf_Safe, Sf_Trustworthy]
- (matches, unify, unsafeOverlaps) = lookupInstEnv True instEnvs clas tys
- safeHaskFail = safeOverlapCheck && not (null unsafeOverlaps)
- ; traceTcS "matchInstEnv" $
- vcat [ text "goal:" <+> ppr clas <+> ppr tys
- , text "matches:" <+> ppr matches
- , text "unify:" <+> ppr unify ]
- ; case (matches, unify, safeHaskFail) of
-
- -- Nothing matches
- ([], [], _)
- -> do { traceTcS "matchClass not matching" (ppr pred)
- ; return NoInstance }
-
- -- A single match (& no safe haskell failure)
- ([(ispec, inst_tys)], [], False)
- | short_cut_solver -- Called from the short-cut solver
- , isOverlappable ispec
- -- If the instance has OVERLAPPABLE or OVERLAPS or INCOHERENT
- -- then don't let the short-cut solver choose it, because a
- -- later instance might overlap it. Trac #14434 is an example
- -- See Note [Shortcut solving: overlap]
- -> do { traceTcS "matchClass: ignoring overlappable" (ppr pred)
- ; return NotSure }
-
- | otherwise
- -> do { let dfun_id = instanceDFunId ispec
- ; traceTcS "matchClass success" $
- vcat [text "dict" <+> ppr pred,
- text "witness" <+> ppr dfun_id
- <+> ppr (idType dfun_id) ]
- -- Record that this dfun is needed
- ; match_one pred loc (null unsafeOverlaps) dfun_id inst_tys }
-
- -- More than one matches (or Safe Haskell fail!). Defer any
- -- reactions of a multitude until we learn more about the reagent
- _ -> do { traceTcS "matchClass multiple matches, deferring choice" $
- vcat [text "dict" <+> ppr pred,
- text "matches" <+> ppr matches]
- ; return NotSure } }
- where
- pred = mkClassPred clas tys
-
-match_one :: TcPredType -> CtLoc -> SafeOverlapping
- -> DFunId -> [DFunInstType] -> TcS LookupInstResult
- -- See Note [DFunInstType: instantiating types] in InstEnv
-match_one pred loc so dfun_id mb_inst_tys
- = do { traceTcS "match_one" (ppr dfun_id $$ ppr mb_inst_tys)
- ; checkWellStagedDFun pred dfun_id loc
- ; (tys, theta) <- instDFunType dfun_id mb_inst_tys
- ; traceTcS "match_one 2" (ppr dfun_id $$ ppr tys $$ ppr theta)
- ; return $ OneInst { lir_new_theta = theta
- , lir_mk_ev = evDFunApp dfun_id tys
- , lir_safe_over = so } }
-
-
-{- ********************************************************************
-* *
- Class lookup for CTuples
-* *
-***********************************************************************-}
-
-matchCTuple :: Class -> [Type] -> TcS LookupInstResult
-matchCTuple clas tys -- (isCTupleClass clas) holds
- = return (OneInst { lir_new_theta = tys
- , lir_mk_ev = tuple_ev
- , lir_safe_over = True })
- -- The dfun *is* the data constructor!
- where
- data_con = tyConSingleDataCon (classTyCon clas)
- tuple_ev = evDFunApp (dataConWrapId data_con) tys
-
-{- ********************************************************************
-* *
- Class lookup for Literals
-* *
-***********************************************************************-}
-
-{-
-Note [KnownNat & KnownSymbol and EvLit]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-A part of the type-level literals implementation are the classes
-"KnownNat" and "KnownSymbol", which provide a "smart" constructor for
-defining singleton values. Here is the key stuff from GHC.TypeLits
-
- class KnownNat (n :: Nat) where
- natSing :: SNat n
-
- newtype SNat (n :: Nat) = SNat Integer
-
-Conceptually, this class has infinitely many instances:
-
- instance KnownNat 0 where natSing = SNat 0
- instance KnownNat 1 where natSing = SNat 1
- instance KnownNat 2 where natSing = SNat 2
- ...
-
-In practice, we solve `KnownNat` predicates in the type-checker
-(see typecheck/TcInteract.hs) because we can't have infinitely many instances.
-The evidence (aka "dictionary") for `KnownNat` is of the form `EvLit (EvNum n)`.
-
-We make the following assumptions about dictionaries in GHC:
- 1. The "dictionary" for classes with a single method---like `KnownNat`---is
- a newtype for the type of the method, so using a evidence amounts
- to a coercion, and
- 2. Newtypes use the same representation as their definition types.
-
-So, the evidence for `KnownNat` is just a value of the representation type,
-wrapped in two newtype constructors: one to make it into a `SNat` value,
-and another to make it into a `KnownNat` dictionary.
-
-Also note that `natSing` and `SNat` are never actually exposed from the
-library---they are just an implementation detail. Instead, users see
-a more convenient function, defined in terms of `natSing`:
-
- natVal :: KnownNat n => proxy n -> Integer
-
-The reason we don't use this directly in the class is that it is simpler
-and more efficient to pass around an integer rather than an entire function,
-especially when the `KnowNat` evidence is packaged up in an existential.
-
-The story for kind `Symbol` is analogous:
- * class KnownSymbol
- * newtype SSymbol
- * Evidence: a Core literal (e.g. mkNaturalExpr)
--}
-
-matchKnownNat :: Class -> [Type] -> TcS LookupInstResult
-matchKnownNat clas [ty] -- clas = KnownNat
- | Just n <- isNumLitTy ty = do
- et <- mkNaturalExpr n
- makeLitDict clas ty et
-matchKnownNat _ _ = return NoInstance
-
-matchKnownSymbol :: Class -> [Type] -> TcS LookupInstResult
-matchKnownSymbol clas [ty] -- clas = KnownSymbol
- | Just s <- isStrLitTy ty = do
- et <- mkStringExprFS s
- makeLitDict clas ty et
-matchKnownSymbol _ _ = return NoInstance
-
-makeLitDict :: Class -> Type -> EvExpr -> TcS LookupInstResult
--- makeLitDict adds a coercion that will convert the literal into a dictionary
--- of the appropriate type. See Note [KnownNat & KnownSymbol and EvLit]
--- in TcEvidence. The coercion happens in 2 steps:
---
--- Integer -> SNat n -- representation of literal to singleton
--- SNat n -> KnownNat n -- singleton to dictionary
---
--- The process is mirrored for Symbols:
--- String -> SSymbol n
--- SSymbol n -> KnownSymbol n
-makeLitDict clas ty et
- | Just (_, co_dict) <- tcInstNewTyCon_maybe (classTyCon clas) [ty]
- -- co_dict :: KnownNat n ~ SNat n
- , [ meth ] <- classMethods clas
- , Just tcRep <- tyConAppTyCon_maybe -- SNat
- $ funResultTy -- SNat n
- $ dropForAlls -- KnownNat n => SNat n
- $ idType meth -- forall n. KnownNat n => SNat n
- , Just (_, co_rep) <- tcInstNewTyCon_maybe tcRep [ty]
- -- SNat n ~ Integer
- , let ev_tm = mkEvCast et (mkTcSymCo (mkTcTransCo co_dict co_rep))
- = return $ OneInst { lir_new_theta = []
- , lir_mk_ev = \_ -> ev_tm
- , lir_safe_over = True }
-
- | otherwise
- = panicTcS (text "Unexpected evidence for" <+> ppr (className clas)
- $$ vcat (map (ppr . idType) (classMethods clas)))
-
-{- ********************************************************************
-* *
- Class lookup for Typeable
-* *
-***********************************************************************-}
-
--- | Assumes that we've checked that this is the 'Typeable' class,
--- and it was applied to the correct argument.
-matchTypeable :: Class -> [Type] -> TcS LookupInstResult
-matchTypeable clas [k,t] -- clas = Typeable
- -- For the first two cases, See Note [No Typeable for polytypes or qualified types]
- | isForAllTy k = return NoInstance -- Polytype
- | isJust (tcSplitPredFunTy_maybe t) = return NoInstance -- Qualified type
-
- -- Now cases that do work
- | k `eqType` typeNatKind = doTyLit knownNatClassName t
- | k `eqType` typeSymbolKind = doTyLit knownSymbolClassName t
- | isConstraintKind t = doTyConApp clas t constraintKindTyCon []
- | Just (arg,ret) <- splitFunTy_maybe t = doFunTy clas t arg ret
- | Just (tc, ks) <- splitTyConApp_maybe t -- See Note [Typeable (T a b c)]
- , onlyNamedBndrsApplied tc ks = doTyConApp clas t tc ks
- | Just (f,kt) <- splitAppTy_maybe t = doTyApp clas t f kt
-
-matchTypeable _ _ = return NoInstance
-
--- | Representation for a type @ty@ of the form @arg -> ret@.
-doFunTy :: Class -> Type -> Type -> Type -> TcS LookupInstResult
-doFunTy clas ty arg_ty ret_ty
- = return $ OneInst { lir_new_theta = preds
- , lir_mk_ev = mk_ev
- , lir_safe_over = True }
- where
- preds = map (mk_typeable_pred clas) [arg_ty, ret_ty]
- mk_ev [arg_ev, ret_ev] = evTypeable ty $
- EvTypeableTrFun (EvExpr arg_ev) (EvExpr ret_ev)
- mk_ev _ = panic "TcInteract.doFunTy"
-
-
--- | Representation for type constructor applied to some kinds.
--- 'onlyNamedBndrsApplied' has ensured that this application results in a type
--- of monomorphic kind (e.g. all kind variables have been instantiated).
-doTyConApp :: Class -> Type -> TyCon -> [Kind] -> TcS LookupInstResult
-doTyConApp clas ty tc kind_args
- | Just _ <- tyConRepName_maybe tc
- = return $ OneInst { lir_new_theta = (map (mk_typeable_pred clas) kind_args)
- , lir_mk_ev = mk_ev
- , lir_safe_over = True }
- | otherwise
- = return NoInstance
- where
- mk_ev kinds = evTypeable ty $ EvTypeableTyCon tc (map EvExpr kinds)
-
--- | Representation for TyCon applications of a concrete kind. We just use the
--- kind itself, but first we must make sure that we've instantiated all kind-
--- polymorphism, but no more.
-onlyNamedBndrsApplied :: TyCon -> [KindOrType] -> Bool
-onlyNamedBndrsApplied tc ks
- = all isNamedTyConBinder used_bndrs &&
- not (any isNamedTyConBinder leftover_bndrs)
- where
- bndrs = tyConBinders tc
- (used_bndrs, leftover_bndrs) = splitAtList ks bndrs
-
-doTyApp :: Class -> Type -> Type -> KindOrType -> TcS LookupInstResult
--- Representation for an application of a type to a type-or-kind.
--- This may happen when the type expression starts with a type variable.
--- Example (ignoring kind parameter):
--- Typeable (f Int Char) -->
--- (Typeable (f Int), Typeable Char) -->
--- (Typeable f, Typeable Int, Typeable Char) --> (after some simp. steps)
--- Typeable f
-doTyApp clas ty f tk
- | isForAllTy (typeKind f)
- = return NoInstance -- We can't solve until we know the ctr.
- | otherwise
- = return $ OneInst { lir_new_theta = map (mk_typeable_pred clas) [f, tk]
- , lir_mk_ev = mk_ev
- , lir_safe_over = True }
- where
- mk_ev [t1,t2] = evTypeable ty $ EvTypeableTyApp (EvExpr t1) (EvExpr t2)
- mk_ev _ = panic "doTyApp"
-
-
--- Emit a `Typeable` constraint for the given type.
-mk_typeable_pred :: Class -> Type -> PredType
-mk_typeable_pred clas ty = mkClassPred clas [ typeKind ty, ty ]
-
- -- Typeable is implied by KnownNat/KnownSymbol. In the case of a type literal
- -- we generate a sub-goal for the appropriate class.
- -- See Note [Typeable for Nat and Symbol]
-doTyLit :: Name -> Type -> TcS LookupInstResult
-doTyLit kc t = do { kc_clas <- tcLookupClass kc
- ; let kc_pred = mkClassPred kc_clas [ t ]
- mk_ev [ev] = evTypeable t $ EvTypeableTyLit (EvExpr ev)
- mk_ev _ = panic "doTyLit"
- ; return (OneInst { lir_new_theta = [kc_pred]
- , lir_mk_ev = mk_ev
- , lir_safe_over = True }) }
-
-{- Note [Typeable (T a b c)]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-For type applications we always decompose using binary application,
-via doTyApp, until we get to a *kind* instantiation. Example
- Proxy :: forall k. k -> *
-
-To solve Typeable (Proxy (* -> *) Maybe) we
- - First decompose with doTyApp,
- to get (Typeable (Proxy (* -> *))) and Typeable Maybe
- - Then solve (Typeable (Proxy (* -> *))) with doTyConApp
-
-If we attempt to short-cut by solving it all at once, via
-doTyConApp
-
-(this note is sadly truncated FIXME)
-
-
-Note [No Typeable for polytypes or qualified types]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We do not support impredicative typeable, such as
- Typeable (forall a. a->a)
- Typeable (Eq a => a -> a)
- Typeable (() => Int)
- Typeable (((),()) => Int)
-
-See Trac #9858. For forall's the case is clear: we simply don't have
-a TypeRep for them. For qualified but not polymorphic types, like
-(Eq a => a -> a), things are murkier. But:
-
- * We don't need a TypeRep for these things. TypeReps are for
- monotypes only.
-
- * Perhaps we could treat `=>` as another type constructor for `Typeable`
- purposes, and thus support things like `Eq Int => Int`, however,
- at the current state of affairs this would be an odd exception as
- no other class works with impredicative types.
- For now we leave it off, until we have a better story for impredicativity.
-
-
-Note [Typeable for Nat and Symbol]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We have special Typeable instances for Nat and Symbol. Roughly we
-have this instance, implemented here by doTyLit:
- instance KnownNat n => Typeable (n :: Nat) where
- typeRep = tyepNatTypeRep @n
-where
- Data.Typeable.Internals.typeNatTypeRep :: KnownNat a => TypeRep a
-
-Ultimately typeNatTypeRep uses 'natSing' from KnownNat to get a
-runtime value 'n'; it turns it into a string with 'show' and uses
-that to whiz up a TypeRep TyCon for 'n', with mkTypeLitTyCon.
-See #10348.
-
-Because of this rule it's inadvisable (see #15322) to have a constraint
- f :: (Typeable (n :: Nat)) => blah
-in a function signature; it gives rise to overlap problems just as
-if you'd written
- f :: Eq [a] => blah
--}
-
-{- ********************************************************************
-* *
- Class lookup for lifted equality
-* *
-***********************************************************************-}
-
--- See also Note [The equality types story] in TysPrim
-matchLiftedEquality :: [Type] -> TcS LookupInstResult
-matchLiftedEquality args
- = return (OneInst { lir_new_theta = [ mkTyConApp eqPrimTyCon args ]
- , lir_mk_ev = evDFunApp (dataConWrapId heqDataCon) args
- , lir_safe_over = True })
-
--- See also Note [The equality types story] in TysPrim
-matchLiftedCoercible :: [Type] -> TcS LookupInstResult
-matchLiftedCoercible args@[k, t1, t2]
- = return (OneInst { lir_new_theta = [ mkTyConApp eqReprPrimTyCon args' ]
- , lir_mk_ev = evDFunApp (dataConWrapId coercibleDataCon)
- args
- , lir_safe_over = True })
- where
- args' = [k, k, t1, t2]
-matchLiftedCoercible args = pprPanic "matchLiftedCoercible" (ppr args)
-
-
-{- ********************************************************************
-* *
- Class lookup for overloaded record fields
-* *
-***********************************************************************-}
-
-{-
-Note [HasField instances]
-~~~~~~~~~~~~~~~~~~~~~~~~~
-Suppose we have
-
- data T y = MkT { foo :: [y] }
-
-and `foo` is in scope. Then GHC will automatically solve a constraint like
-
- HasField "foo" (T Int) b
-
-by emitting a new wanted
-
- T alpha -> [alpha] ~# T Int -> b
-
-and building a HasField dictionary out of the selector function `foo`,
-appropriately cast.
-
-The HasField class is defined (in GHC.Records) thus:
-
- class HasField (x :: k) r a | x r -> a where
- getField :: r -> a
-
-Since this is a one-method class, it is represented as a newtype.
-Hence we can solve `HasField "foo" (T Int) b` by taking an expression
-of type `T Int -> b` and casting it using the newtype coercion.
-Note that
-
- foo :: forall y . T y -> [y]
-
-so the expression we construct is
-
- foo @alpha |> co
-
-where
-
- co :: (T alpha -> [alpha]) ~# HasField "foo" (T Int) b
-
-is built from
-
- co1 :: (T alpha -> [alpha]) ~# (T Int -> b)
-
-which is the new wanted, and
-
- co2 :: (T Int -> b) ~# HasField "foo" (T Int) b
-
-which can be derived from the newtype coercion.
-
-If `foo` is not in scope, or has a higher-rank or existentially
-quantified type, then the constraint is not solved automatically, but
-may be solved by a user-supplied HasField instance. Similarly, if we
-encounter a HasField constraint where the field is not a literal
-string, or does not belong to the type, then we fall back on the
-normal constraint solver behaviour.
--}
-
--- See Note [HasField instances]
-matchHasField :: DynFlags -> Bool -> Class -> [Type] -> CtLoc -> TcS LookupInstResult
-matchHasField dflags short_cut clas tys loc
- = do { fam_inst_envs <- getFamInstEnvs
- ; rdr_env <- getGlobalRdrEnvTcS
- ; case tys of
- -- We are matching HasField {k} x r a...
- [_k_ty, x_ty, r_ty, a_ty]
- -- x should be a literal string
- | Just x <- isStrLitTy x_ty
- -- r should be an applied type constructor
- , Just (tc, args) <- tcSplitTyConApp_maybe r_ty
- -- use representation tycon (if data family); it has the fields
- , let r_tc = fstOf3 (tcLookupDataFamInst fam_inst_envs tc args)
- -- x should be a field of r
- , Just fl <- lookupTyConFieldLabel x r_tc
- -- the field selector should be in scope
- , Just gre <- lookupGRE_FieldLabel rdr_env fl
-
- -> do { sel_id <- tcLookupId (flSelector fl)
- ; (tv_prs, preds, sel_ty) <- tcInstType newMetaTyVars sel_id
-
- -- The first new wanted constraint equates the actual
- -- type of the selector with the type (r -> a) within
- -- the HasField x r a dictionary. The preds will
- -- typically be empty, but if the datatype has a
- -- "stupid theta" then we have to include it here.
- ; let theta = mkPrimEqPred sel_ty (mkFunTy r_ty a_ty) : preds
-
- -- Use the equality proof to cast the selector Id to
- -- type (r -> a), then use the newtype coercion to cast
- -- it to a HasField dictionary.
- mk_ev (ev1:evs) = evSelector sel_id tvs evs `evCast` co
- where
- co = mkTcSubCo (evTermCoercion (EvExpr ev1))
- `mkTcTransCo` mkTcSymCo co2
- mk_ev [] = panic "matchHasField.mk_ev"
-
- Just (_, co2) = tcInstNewTyCon_maybe (classTyCon clas)
- tys
-
- tvs = mkTyVarTys (map snd tv_prs)
-
- -- The selector must not be "naughty" (i.e. the field
- -- cannot have an existentially quantified type), and
- -- it must not be higher-rank.
- ; if not (isNaughtyRecordSelector sel_id) && isTauTy sel_ty
- then do { addUsedGRE True gre
- ; return OneInst { lir_new_theta = theta
- , lir_mk_ev = mk_ev
- , lir_safe_over = True
- } }
- else matchInstEnv dflags short_cut clas tys loc }
-
- _ -> matchInstEnv dflags short_cut clas tys loc }
diff --git a/compiler/typecheck/TcSMonad.hs b/compiler/typecheck/TcSMonad.hs
index 0ac91a1ab7..3f0db9c012 100644
--- a/compiler/typecheck/TcSMonad.hs
+++ b/compiler/typecheck/TcSMonad.hs
@@ -20,6 +20,7 @@ module TcSMonad (
checkConstraintsTcS, checkTvConstraintsTcS,
runTcPluginTcS, addUsedGRE, addUsedGREs,
+ matchGlobalInst, TcM.ClsInstResult(..),
QCInst(..),
@@ -97,7 +98,7 @@ module TcSMonad (
-- MetaTyVars
newFlexiTcSTy, instFlexi, instFlexiX,
cloneMetaTyVar, demoteUnfilledFmv,
- tcInstType, tcInstSkolTyVarsX,
+ tcInstSkolTyVarsX,
TcLevel,
isFilledMetaTyVar_maybe, isFilledMetaTyVar,
@@ -107,7 +108,7 @@ module TcSMonad (
zonkTcTyCoVarBndr,
-- References
- newTcRef, readTcRef, updTcRef,
+ newTcRef, readTcRef, writeTcRef, updTcRef,
-- Misc
getDefaultInfo, getDynFlags, getGlobalRdrEnvTcS,
@@ -133,9 +134,11 @@ import FamInstEnv
import qualified TcRnMonad as TcM
import qualified TcMType as TcM
+import qualified ClsInst as TcM( matchGlobalInst, ClsInstResult(..) )
import qualified TcEnv as TcM
- ( checkWellStaged, topIdLvl, tcGetDefaultTys, tcLookupClass, tcLookupId )
+ ( checkWellStaged, tcGetDefaultTys, tcLookupClass, tcLookupId, topIdLvl )
import PrelNames( heqTyConKey, eqTyConKey )
+import ClsInst( InstanceWhat(..) )
import Kind
import TcType
import DynFlags
@@ -363,13 +366,13 @@ selectNextWorkItem :: TcS (Maybe Ct)
-- See Note [Prioritise equalities]
selectNextWorkItem
= do { wl_var <- getTcSWorkListRef
- ; wl <- wrapTcS (TcM.readTcRef wl_var)
+ ; wl <- readTcRef wl_var
; case selectWorkItem wl of {
Nothing -> return Nothing ;
Just (ct, new_wl) ->
do { -- checkReductionDepth (ctLoc ct) (ctPred ct)
-- This is done by TcInteract.chooseInstance
- ; wrapTcS (TcM.writeTcRef wl_var new_wl)
+ ; writeTcRef wl_var new_wl
; return (Just ct) } } }
-- Pretty printing
@@ -2927,21 +2930,21 @@ getTcSWorkListRef :: TcS (IORef WorkList)
getTcSWorkListRef = TcS (return . tcs_worklist)
getTcSInerts :: TcS InertSet
-getTcSInerts = getTcSInertsRef >>= wrapTcS . (TcM.readTcRef)
+getTcSInerts = getTcSInertsRef >>= readTcRef
setTcSInerts :: InertSet -> TcS ()
-setTcSInerts ics = do { r <- getTcSInertsRef; wrapTcS (TcM.writeTcRef r ics) }
+setTcSInerts ics = do { r <- getTcSInertsRef; writeTcRef r ics }
getWorkListImplics :: TcS (Bag Implication)
getWorkListImplics
= do { wl_var <- getTcSWorkListRef
- ; wl_curr <- wrapTcS (TcM.readTcRef wl_var)
+ ; wl_curr <- readTcRef wl_var
; return (wl_implics wl_curr) }
updWorkListTcS :: (WorkList -> WorkList) -> TcS ()
updWorkListTcS f
= do { wl_var <- getTcSWorkListRef
- ; wrapTcS (TcM.updTcRef wl_var f)}
+ ; updTcRef wl_var f }
emitWorkNC :: [CtEvidence] -> TcS ()
emitWorkNC evs
@@ -2961,6 +2964,9 @@ newTcRef x = wrapTcS (TcM.newTcRef x)
readTcRef :: TcRef a -> TcS a
readTcRef ref = wrapTcS (TcM.readTcRef ref)
+writeTcRef :: TcRef a -> a -> TcS ()
+writeTcRef ref val = wrapTcS (TcM.writeTcRef ref val)
+
updTcRef :: TcRef a -> (a->a) -> TcS ()
updTcRef ref upd_fn = wrapTcS (TcM.updTcRef ref upd_fn)
@@ -3043,14 +3049,24 @@ addUsedGRE warn_if_deprec gre = wrapTcS $ TcM.addUsedGRE warn_if_deprec gre
-- Various smaller utilities [TODO, maybe will be absorbed in the instance matcher]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-checkWellStagedDFun :: PredType -> DFunId -> CtLoc -> TcS ()
-checkWellStagedDFun pred dfun_id loc
+checkWellStagedDFun :: CtLoc -> InstanceWhat -> PredType -> TcS ()
+-- Check that we do not try to use an instance before it is available. E.g.
+-- instance Eq T where ...
+-- f x = $( ... (\(p::T) -> p == p)... )
+-- Here we can't use the equality function from the instance in the splice
+
+checkWellStagedDFun loc what pred
+ | TopLevInstance { iw_dfun_id = dfun_id } <- what
+ , let bind_lvl = TcM.topIdLvl dfun_id
+ , bind_lvl > impLevel
= wrapTcS $ TcM.setCtLocM loc $
do { use_stage <- TcM.getStage
; TcM.checkWellStaged pp_thing bind_lvl (thLevel use_stage) }
+
+ | otherwise
+ = return () -- Fast path for common case
where
pp_thing = text "instance for" <+> quotes (ppr pred)
- bind_lvl = TcM.topIdLvl dfun_id
pprEq :: TcType -> TcType -> SDoc
pprEq ty1 ty2 = pprParendType ty1 <+> char '~' <+> pprParendType ty2
@@ -3059,7 +3075,7 @@ isFilledMetaTyVar_maybe :: TcTyVar -> TcS (Maybe Type)
isFilledMetaTyVar_maybe tv
= case tcTyVarDetails tv of
MetaTv { mtv_ref = ref }
- -> do { cts <- wrapTcS (TcM.readTcRef ref)
+ -> do { cts <- readTcRef ref
; case cts of
Indirect ty -> return (Just ty)
Flexi -> return Nothing }
@@ -3268,12 +3284,12 @@ instFlexiHelper subst tv
; TcM.traceTc "instFlexi" (ppr ty')
; return (extendTvSubst subst tv ty') }
-tcInstType :: ([TyVar] -> TcM (TCvSubst, [TcTyVar]))
- -- ^ How to instantiate the type variables
- -> Id -- ^ Type to instantiate
- -> TcS ([(Name, TcTyVar)], TcThetaType, TcType) -- ^ Result
- -- (type vars, preds (incl equalities), rho)
-tcInstType inst_tyvars id = wrapTcS (TcM.tcInstType inst_tyvars id)
+matchGlobalInst :: DynFlags
+ -> Bool -- True <=> caller is the short-cut solver
+ -- See Note [Shortcut solving: overlap]
+ -> Class -> [Type] -> TcS TcM.ClsInstResult
+matchGlobalInst dflags short_cut cls tys
+ = wrapTcS (TcM.matchGlobalInst dflags short_cut cls tys)
tcInstSkolTyVarsX :: TCvSubst -> [TyVar] -> TcS (TCvSubst, [TcTyVar])
tcInstSkolTyVarsX subst tvs = wrapTcS $ TcM.tcInstSkolTyVarsX subst tvs
diff --git a/compiler/typecheck/TcSimplify.hs b/compiler/typecheck/TcSimplify.hs
index c504ad9bdb..8f9b72b20d 100644
--- a/compiler/typecheck/TcSimplify.hs
+++ b/compiler/typecheck/TcSimplify.hs
@@ -410,7 +410,7 @@ How is this implemented? It's complicated! So we'll step through it all:
the list is null.
2) `TcInteract.matchClassInst` -- This module drives the instance resolution
- / dictionary generation. The return type is `LookupInstResult`, which either
+ / dictionary generation. The return type is `ClsInstResult`, which either
says no instance matched, or one found, and if it was a safe or unsafe
overlap.
diff --git a/compiler/typecheck/TcValidity.hs b/compiler/typecheck/TcValidity.hs
index 0dc5664baf..86cb922b4a 100644
--- a/compiler/typecheck/TcValidity.hs
+++ b/compiler/typecheck/TcValidity.hs
@@ -27,6 +27,7 @@ import Maybes
-- friends:
import TcUnify ( tcSubType_NC )
import TcSimplify ( simplifyAmbiguityCheck )
+import ClsInst ( matchGlobalInst, ClsInstResult(..), InstanceWhat(..) )
import TyCoRep
import TcType hiding ( sizeType, sizeTypes )
import PrelNames
@@ -40,15 +41,15 @@ import TyCon
-- others:
import HsSyn -- HsType
import TcRnMonad -- TcType, amongst others
-import TcEnv ( tcGetInstEnvs, tcInitTidyEnv, tcInitOpenTidyEnv )
+import TcEnv ( tcInitTidyEnv, tcInitOpenTidyEnv )
import FunDeps
-import InstEnv ( InstMatch, lookupInstEnv )
import FamInstEnv ( isDominatedBy, injectiveBranches,
InjectivityCheckResult(..) )
import FamInst ( makeInjectivityErrors )
import Name
import VarEnv
import VarSet
+import Id ( idType, idName )
import Var ( TyVarBndr(..), mkTyVar )
import ErrUtils
import DynFlags
@@ -680,9 +681,9 @@ applying the instance decl would show up two uses of ?x. Trac #8912.
checkValidTheta :: UserTypeCtxt -> ThetaType -> TcM ()
-- Assumes argument is fully zonked
checkValidTheta ctxt theta
- = do { env <- tcInitOpenTidyEnv (tyCoVarsOfTypesList theta)
- ; addErrCtxtM (checkThetaCtxt ctxt theta) $
- check_valid_theta env ctxt theta }
+ = addErrCtxtM (checkThetaCtxt ctxt theta) $
+ do { env <- tcInitOpenTidyEnv (tyCoVarsOfTypesList theta)
+ ; check_valid_theta env ctxt theta }
-------------------------
check_valid_theta :: TidyEnv -> UserTypeCtxt -> [PredType] -> TcM ()
@@ -748,32 +749,47 @@ check_pred_help under_syn env dflags ctxt pred
| otherwise -- A bit like classifyPredType, but not the same
-- E.g. we treat (~) like (~#); and we look inside tuples
- = case splitTyConApp_maybe pred of
- Just (tc, tys)
- | isTupleTyCon tc
- -> check_tuple_pred under_syn env dflags ctxt pred tys
-
- | tc `hasKey` heqTyConKey ||
- tc `hasKey` eqTyConKey ||
- tc `hasKey` eqPrimTyConKey
- -- NB: this equality check must come first,
- -- because (~) is a class,too.
- -> check_eq_pred env dflags pred tc tys
-
- | Just cls <- tyConClass_maybe tc
- -- Includes Coercible
- -> check_class_pred env dflags ctxt pred cls tys
-
- _ -> check_irred_pred under_syn env dflags ctxt pred
-
-check_eq_pred :: TidyEnv -> DynFlags -> PredType -> TyCon -> [TcType] -> TcM ()
-check_eq_pred env dflags pred tc tys
+ = case classifyPredType pred of
+ ClassPred cls tys
+ | isCTupleClass cls -> check_tuple_pred under_syn env dflags ctxt pred tys
+ | otherwise -> check_class_pred env dflags ctxt pred cls tys
+
+ EqPred NomEq _ _ -> -- a ~# b
+ check_eq_pred env dflags pred
+
+ EqPred ReprEq _ _ -> -- Ugh! When inferring types we may get
+ -- f :: (a ~R# b) => blha
+ -- And we want to treat that like (Coercible a b)
+ -- We should probably check argument shapes, but we
+ -- didn't do so before, so I'm leaving it for now
+ return ()
+
+ ForAllPred _ theta head -> check_quant_pred env dflags pred theta head
+ IrredPred {} -> check_irred_pred under_syn env dflags ctxt pred
+
+check_eq_pred :: TidyEnv -> DynFlags -> PredType -> TcM ()
+check_eq_pred env dflags pred
= -- Equational constraints are valid in all contexts if type
-- families are permitted
- do { checkTc (tys `lengthIs` tyConArity tc) (tyConArityErr tc tys)
- ; checkTcM (xopt LangExt.TypeFamilies dflags
- || xopt LangExt.GADTs dflags)
- (eqPredTyErr env pred) }
+ checkTcM (xopt LangExt.TypeFamilies dflags
+ || xopt LangExt.GADTs dflags)
+ (eqPredTyErr env pred)
+
+check_quant_pred :: TidyEnv -> DynFlags -> PredType
+ -> ThetaType -> PredType -> TcM ()
+check_quant_pred env dflags pred theta head_pred
+ = addErrCtxt (text "In the quantified constraint"
+ <+> quotes (ppr pred)) $
+ do { checkTcM head_ok (badQuantHeadErr env pred)
+
+ ; unless (xopt LangExt.UndecidableInstances dflags) $
+ checkInstTermination theta head_pred
+ }
+ where
+ head_ok = case classifyPredType head_pred of
+ ClassPred {} -> True
+ IrredPred {} -> hasTyVarHead head_pred
+ _ -> False
check_tuple_pred :: Bool -> TidyEnv -> DynFlags -> UserTypeCtxt -> PredType -> [PredType] -> TcM ()
check_tuple_pred under_syn env dflags ctxt pred ts
@@ -833,16 +849,21 @@ This will cause the constraint simplifier to loop because every time we canonica
solved to add+canonicalise another (Foo a) constraint. -}
-------------------------
-check_class_pred :: TidyEnv -> DynFlags -> UserTypeCtxt -> PredType -> Class -> [TcType] -> TcM ()
+check_class_pred :: TidyEnv -> DynFlags -> UserTypeCtxt
+ -> PredType -> Class -> [TcType] -> TcM ()
check_class_pred env dflags ctxt pred cls tys
+ | cls `hasKey` heqTyConKey -- (~) and (~~) are classified as classes,
+ || cls `hasKey` eqTyConKey -- but here we want to treat them as equalities
+ = pprTrace "check_class" (ppr cls) $
+ check_eq_pred env dflags pred
+
| isIPClass cls
= do { check_arity
; checkTcM (okIPCtxt ctxt) (badIPPred env pred) }
- | otherwise
+ | otherwise -- Includes Coercible
= do { check_arity
- ; warn_simp <- woptM Opt_WarnSimplifiableClassConstraints
- ; when warn_simp check_simplifiable_class_constraint
+ ; checkSimplifiableClassConstraint env dflags ctxt cls tys
; checkTcM arg_tys_ok (predTyVarErr env pred) }
where
check_arity = checkTc (tys `lengthIs` classArity cls)
@@ -858,27 +879,48 @@ check_class_pred env dflags ctxt pred cls tys
-- in checkInstTermination
_ -> checkValidClsArgs flexible_contexts cls tys
- -- See Note [Simplifiable given constraints]
- check_simplifiable_class_constraint
- | xopt LangExt.MonoLocalBinds dflags
- = return ()
- | DataTyCtxt {} <- ctxt -- Don't do this check for the "stupid theta"
- = return () -- of a data type declaration
- | otherwise
- = 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
+checkSimplifiableClassConstraint :: TidyEnv -> DynFlags -> UserTypeCtxt
+ -> Class -> [TcType] -> TcM ()
+-- See Note [Simplifiable given constraints]
+checkSimplifiableClassConstraint env dflags ctxt cls tys
+ | not (wopt Opt_WarnSimplifiableClassConstraints dflags)
+ = return ()
+ | xopt LangExt.MonoLocalBinds dflags
+ = return ()
+
+ | DataTyCtxt {} <- ctxt -- Don't do this check for the "stupid theta"
+ = return () -- of a data type declaration
+
+ | cls `hasKey` coercibleTyConKey
+ = return () -- Oddly, we treat (Coercible t1 t2) as unconditionally OK
+ -- matchGlobalInst will reply "yes" because we can reduce
+ -- (Coercible a b) to (a ~R# b)
+
+ | otherwise
+ = do { result <- matchGlobalInst dflags False cls tys
+ ; case result of
+ OneInst { cir_what = what }
+ -> addWarnTc (Reason Opt_WarnSimplifiableClassConstraints)
+ (simplifiable_constraint_warn what)
+ _ -> return () }
+ where
+ pred = mkClassPred cls tys
+
+ simplifiable_constraint_warn :: InstanceWhat -> SDoc
+ simplifiable_constraint_warn what
+ = vcat [ hang (text "The constraint" <+> quotes (ppr (tidyType env pred))
+ <+> text "matches")
+ 2 (ppr_what what)
, hang (text "This makes type inference for inner bindings fragile;")
2 (text "either use MonoLocalBinds, or simplify it using the instance") ]
+ ppr_what BuiltinInstance = text "a built-in instance"
+ ppr_what LocalInstance = text "a locally-quantified instance"
+ ppr_what (TopLevInstance { iw_dfun_id = dfun })
+ = hang (text "instance" <+> pprSigmaType (idType dfun))
+ 2 (text "--" <+> pprDefinedAt (idName dfun))
+
+
{- Note [Simplifiable given constraints]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A type signature like
@@ -973,7 +1015,12 @@ checkThetaCtxt ctxt theta env
, vcat [ text "In the context:" <+> pprTheta (tidyTypes env theta)
, text "While checking" <+> pprUserTypeCtxt ctxt ] )
-eqPredTyErr, predTupleErr, predIrredErr, predSuperClassErr :: TidyEnv -> PredType -> (TidyEnv, SDoc)
+eqPredTyErr, predTupleErr, predIrredErr,
+ predSuperClassErr, badQuantHeadErr :: TidyEnv -> PredType -> (TidyEnv, SDoc)
+badQuantHeadErr env pred
+ = ( env
+ , hang (text "Quantified predicate must have a class or type variable head:")
+ 2 (ppr_tidy env pred) )
eqPredTyErr env pred
= ( env
, text "Illegal equational constraint" <+> ppr_tidy env pred $$
@@ -1329,7 +1376,9 @@ checkValidInstance ctxt hs_type ty
| otherwise
= do { setSrcSpan head_loc (checkValidInstHead ctxt clas inst_tys)
; traceTc "checkValidInstance {" (ppr ty)
- ; checkValidTheta ctxt theta
+
+ ; env0 <- tcInitTidyEnv
+ ; check_valid_theta env0 ctxt theta
-- The Termination and Coverate Conditions
-- Check that instance inference will terminate (if we care)
@@ -1415,16 +1464,15 @@ checkInstTermination theta head_pred
bogus_size = 1 + sizeTypes (filterOutInvisibleTypes (classTyCon cls) tys)
-- See Note [Invisible arguments and termination]
- ForAllPred tvs theta' head_pred'
- -> do { check (foralld_tvs `extendVarSetList` binderVars tvs) head_pred'
- ; addErrCtxt (text "In the quantified constraint"
- <+> quotes (ppr pred)) $
- checkInstTermination theta' head_pred' }
+ ForAllPred tvs _ head_pred'
+ -> check (foralld_tvs `extendVarSetList` binderVars tvs) head_pred'
+ -- Termination of the quantified predicate itself is checked
+ -- when the predicates are individually checked for validity
check2 foralld_tvs pred pred_size
- | not (null bad_tvs) = addErrTc (noMoreMsg bad_tvs what (ppr head_pred))
- | not (isTyFamFree pred) = addErrTc (nestedMsg what)
- | pred_size >= head_size = addErrTc (smallerMsg what (ppr head_pred))
+ | not (null bad_tvs) = failWithTc (noMoreMsg bad_tvs what (ppr head_pred))
+ | not (isTyFamFree pred) = failWithTc (nestedMsg what)
+ | pred_size >= head_size = failWithTc (smallerMsg what (ppr head_pred))
| otherwise = return ()
-- isTyFamFree: see Note [Type families in instance contexts]
where
diff --git a/testsuite/tests/indexed-types/should_compile/T15322.hs b/testsuite/tests/indexed-types/should_compile/T15322.hs
new file mode 100644
index 0000000000..5a0cd179b8
--- /dev/null
+++ b/testsuite/tests/indexed-types/should_compile/T15322.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE ScopedTypeVariables, FlexibleContexts #-}
+{-# LANGUAGE TypeOperators #-}
+
+module T15322 where
+
+import Data.Proxy (Proxy (..))
+import Type.Reflection
+import GHC.TypeLits (KnownNat, type (+))
+
+f :: forall n . (Typeable (n+1), KnownNat n) => Proxy n -> TypeRep (n+1)
+f _ = typeRep
diff --git a/testsuite/tests/indexed-types/should_compile/T15322.stderr b/testsuite/tests/indexed-types/should_compile/T15322.stderr
new file mode 100644
index 0000000000..7447a9ece2
--- /dev/null
+++ b/testsuite/tests/indexed-types/should_compile/T15322.stderr
@@ -0,0 +1,8 @@
+
+T15322.hs:11:6: warning: [-Wsimplifiable-class-constraints (in -Wdefault)]
+ • The constraint ‘Typeable (n + 1)’ matches a built-in instance
+ This makes type inference for inner bindings fragile;
+ either use MonoLocalBinds, or simplify it using the instance
+ • In the type signature:
+ f :: forall n.
+ (Typeable (n + 1), KnownNat n) => Proxy n -> TypeRep (n + 1)
diff --git a/testsuite/tests/indexed-types/should_compile/T15322a.hs b/testsuite/tests/indexed-types/should_compile/T15322a.hs
new file mode 100644
index 0000000000..93d0830b26
--- /dev/null
+++ b/testsuite/tests/indexed-types/should_compile/T15322a.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE ScopedTypeVariables, FlexibleContexts #-}
+{-# LANGUAGE TypeOperators #-}
+
+module T15322a where
+
+import Data.Proxy (Proxy (..))
+import Type.Reflection
+import GHC.TypeLits (KnownNat, type (+))
+
+f :: forall n . (KnownNat n) => Proxy n -> TypeRep (n+1)
+f _ = typeRep
diff --git a/testsuite/tests/indexed-types/should_compile/T15322a.stderr b/testsuite/tests/indexed-types/should_compile/T15322a.stderr
new file mode 100644
index 0000000000..37a9070e27
--- /dev/null
+++ b/testsuite/tests/indexed-types/should_compile/T15322a.stderr
@@ -0,0 +1,12 @@
+
+T15322a.hs:12:7: error:
+ • Could not deduce (KnownNat (n + 1))
+ arising from a use of ‘typeRep’
+ from the context: KnownNat n
+ bound by the type signature for:
+ f :: forall (n :: GHC.Types.Nat).
+ KnownNat n =>
+ Proxy n -> TypeRep (n + 1)
+ at T15322a.hs:11:1-56
+ • In the expression: typeRep
+ In an equation for ‘f’: f _ = typeRep
diff --git a/testsuite/tests/indexed-types/should_compile/all.T b/testsuite/tests/indexed-types/should_compile/all.T
index 56448ac75b..6255dd2c79 100644
--- a/testsuite/tests/indexed-types/should_compile/all.T
+++ b/testsuite/tests/indexed-types/should_compile/all.T
@@ -284,3 +284,5 @@ test('T15144', normal, compile, [''])
test('T15122', normal, compile, [''])
test('T13777', normal, compile, [''])
test('T14164', normal, compile, [''])
+test('T15322', normal, compile, [''])
+test('T15322a', normal, compile_fail, [''])
diff --git a/testsuite/tests/partial-sigs/should_compile/SomethingShowable.stderr b/testsuite/tests/partial-sigs/should_compile/SomethingShowable.stderr
index 4b72ec4520..262b76d60a 100644
--- a/testsuite/tests/partial-sigs/should_compile/SomethingShowable.stderr
+++ b/testsuite/tests/partial-sigs/should_compile/SomethingShowable.stderr
@@ -7,8 +7,8 @@ Dependent packages: [base-4.12.0.0, ghc-prim-0.5.3,
integer-gmp-1.0.2.0]
SomethingShowable.hs:5:1: warning: [-Wsimplifiable-class-constraints (in -Wdefault)]
- • The constraint ‘Show Bool’ matches an instance declaration
- instance Show Bool -- Defined in ‘GHC.Show’
+ • The constraint ‘Show Bool’ matches
+ instance Show Bool -- Defined in ‘GHC.Show’
This makes type inference for inner bindings fragile;
either use MonoLocalBinds, or simplify it using the instance
• When checking the inferred type
diff --git a/testsuite/tests/polykinds/T11466.stderr b/testsuite/tests/polykinds/T11466.stderr
index f584731934..616f317250 100644
--- a/testsuite/tests/polykinds/T11466.stderr
+++ b/testsuite/tests/polykinds/T11466.stderr
@@ -1,6 +1,4 @@
T11466.hs:15:10: error:
• Illegal implicit parameter ‘?x::Int’
- • In the context: Bla
- While checking an instance declaration
- In the instance declaration for ‘Eq T’
+ • In the instance declaration for ‘Eq T’
diff --git a/testsuite/tests/quantified-constraints/T15316.hs b/testsuite/tests/quantified-constraints/T15316.hs
new file mode 100644
index 0000000000..07539e3183
--- /dev/null
+++ b/testsuite/tests/quantified-constraints/T15316.hs
@@ -0,0 +1,21 @@
+{-# LANGUAGE RankNTypes, QuantifiedConstraints, ConstraintKinds #-}
+-- NB: disabling these if enabled:
+{-# LANGUAGE NoUndecidableInstances, NoUndecidableSuperClasses #-}
+
+module T15316 where
+
+import Data.Proxy
+
+{-
+class Class a where
+ method :: a
+
+subsume :: (Class a => Class b) => Proxy a -> Proxy b -> ((Class a => Class b) => r) -> r
+subsume _ _ x = x
+
+value :: Proxy a -> a
+value p = subsume p p method
+-}
+
+subsume' :: Proxy c -> ((c => c) => r) -> r
+subsume' _ x = x
diff --git a/testsuite/tests/quantified-constraints/T15316.stderr b/testsuite/tests/quantified-constraints/T15316.stderr
new file mode 100644
index 0000000000..4444c2c453
--- /dev/null
+++ b/testsuite/tests/quantified-constraints/T15316.stderr
@@ -0,0 +1,6 @@
+
+T15316.hs:20:13: error:
+ • The constraint ‘c’ is no smaller than the instance head ‘c’
+ (Use UndecidableInstances to permit this)
+ • In the quantified constraint ‘c => c’
+ In the type signature: subsume' :: Proxy c -> ((c => c) => r) -> r
diff --git a/testsuite/tests/quantified-constraints/all.T b/testsuite/tests/quantified-constraints/all.T
index 65e636744f..3145f47cf1 100644
--- a/testsuite/tests/quantified-constraints/all.T
+++ b/testsuite/tests/quantified-constraints/all.T
@@ -14,3 +14,4 @@ test('T15231', normal, compile_fail, [''])
test('T15290', normal, compile, [''])
test('T15290a', normal, compile_fail, [''])
test('T15290b', normal, compile_fail, [''])
+test('T15316', normal, compile_fail, [''])
diff --git a/testsuite/tests/typecheck/should_compile/T10177.hs b/testsuite/tests/typecheck/should_compile/T10177.hs
index fd84396f67..43aac8afd4 100644
--- a/testsuite/tests/typecheck/should_compile/T10177.hs
+++ b/testsuite/tests/typecheck/should_compile/T10177.hs
@@ -1,5 +1,8 @@
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE FlexibleContexts #-}
+{-# OPTIONS_GHC -Wno-simplifiable-class-constraints #-}
+ -- This test deliberately uses a simplifiable class constraint
+
module T10177 where
import Data.Typeable
diff --git a/testsuite/tests/typecheck/should_compile/T13526.stderr b/testsuite/tests/typecheck/should_compile/T13526.stderr
index 7a0f2ae7c6..ad5876ec9e 100644
--- a/testsuite/tests/typecheck/should_compile/T13526.stderr
+++ b/testsuite/tests/typecheck/should_compile/T13526.stderr
@@ -1,7 +1,7 @@
T13526.hs:21:8: warning: [-Wsimplifiable-class-constraints (in -Wdefault)]
- • The constraint ‘C (Maybe a)’ matches an instance declaration
- instance C a => C (Maybe a) -- Defined at T13526.hs:14:10
+ • The constraint ‘C (Maybe a)’ matches
+ instance C a => C (Maybe a) -- Defined at T13526.hs:14:10
This makes type inference for inner bindings fragile;
either use MonoLocalBinds, or simplify it using the instance
• In the type signature: bar :: C (Maybe a) => a -> Maybe a
diff --git a/testsuite/tests/typecheck/should_compile/TcCustomSolverSuper.hs b/testsuite/tests/typecheck/should_compile/TcCustomSolverSuper.hs
index c401e1c446..b5e20be448 100644
--- a/testsuite/tests/typecheck/should_compile/TcCustomSolverSuper.hs
+++ b/testsuite/tests/typecheck/should_compile/TcCustomSolverSuper.hs
@@ -13,11 +13,17 @@ using the solver (see `tcSuperClasses` in `TcInstDecls`).
However, some classes need to be excepted from this behavior,
as they have custom solving rules, and this test checks that
we got this right.
+
+PS: this test used to have Typeable in the context too, but
+ that's a redundant constraint, so I removed it
+
+PPS: the whole structre of tcSuperClasses has changed,
+ so I'm no longer sure what is being tested here
-}
-class (Typeable x, KnownNat x) => C x
-class (Typeable x, KnownSymbol x) => D x
+class (KnownNat x) => C x
+class (KnownSymbol x) => D x
instance C 2
instance D "2"
diff --git a/testsuite/tests/typecheck/should_fail/T8912.stderr b/testsuite/tests/typecheck/should_fail/T8912.stderr
index bfe06c1511..7d6f37dca2 100644
--- a/testsuite/tests/typecheck/should_fail/T8912.stderr
+++ b/testsuite/tests/typecheck/should_fail/T8912.stderr
@@ -1,6 +1,4 @@
T8912.hs:7:10: error:
• Illegal implicit parameter ‘?imp::Int’
- • In the context: ?imp::Int
- While checking an instance declaration
- In the instance declaration for ‘C [a]’
+ • In the instance declaration for ‘C [a]’
diff --git a/testsuite/tests/typecheck/should_fail/fd-loop.stderr b/testsuite/tests/typecheck/should_fail/fd-loop.stderr
index 31fd91b08a..86a70f5b76 100644
--- a/testsuite/tests/typecheck/should_fail/fd-loop.stderr
+++ b/testsuite/tests/typecheck/should_fail/fd-loop.stderr
@@ -4,9 +4,3 @@ fd-loop.hs:12:10: error:
in the constraint ‘C a b’ than in the instance head ‘Eq (T a)’
(Use UndecidableInstances to permit this)
• In the instance declaration for ‘Eq (T a)’
-
-fd-loop.hs:12:10: error:
- • Variable ‘b’ occurs more often
- in the constraint ‘Eq b’ than in the instance head ‘Eq (T a)’
- (Use UndecidableInstances to permit this)
- • In the instance declaration for ‘Eq (T a)’
diff --git a/testsuite/tests/typecheck/should_fail/tcfail157.stderr b/testsuite/tests/typecheck/should_fail/tcfail157.stderr
index e81778cb0c..4cb2af7e9f 100644
--- a/testsuite/tests/typecheck/should_fail/tcfail157.stderr
+++ b/testsuite/tests/typecheck/should_fail/tcfail157.stderr
@@ -5,10 +5,3 @@ tcfail157.hs:27:10: error:
than in the instance head ‘Foo m (a -> ())’
(Use UndecidableInstances to permit this)
• In the instance declaration for ‘Foo m (a -> ())’
-
-tcfail157.hs:27:10: error:
- • Variable ‘b’ occurs more often
- in the constraint ‘Foo m b’
- than in the instance head ‘Foo m (a -> ())’
- (Use UndecidableInstances to permit this)
- • In the instance declaration for ‘Foo m (a -> ())’
diff --git a/testsuite/tests/typecheck/should_fail/tcfail211.stderr b/testsuite/tests/typecheck/should_fail/tcfail211.stderr
index 7a5053a092..fb1192b0ca 100644
--- a/testsuite/tests/typecheck/should_fail/tcfail211.stderr
+++ b/testsuite/tests/typecheck/should_fail/tcfail211.stderr
@@ -7,6 +7,4 @@ tcfail211.hs:5:1: error:
tcfail211.hs:8:10: error:
• Illegal implicit parameter ‘?imp::Int’
- • In the context: ?imp::Int
- While checking an instance declaration
- In the instance declaration for ‘D Int’
+ • In the instance declaration for ‘D Int’