+
+functorLikeClassKeys :: [Unique]
+functorLikeClassKeys = [functorClassKey, foldableClassKey, traversableClassKey]
+
+cond_functorOK :: Bool -> Condition
+-- OK for Functor/Foldable/Traversable class
+-- Currently: (a) at least one argument
+-- (b) don't use argument contravariantly
+-- (c) don't use argument in the wrong place, e.g. data T a = T (X a a)
+-- (d) optionally: don't use function types
+-- (e) no "stupid context" on data type
+cond_functorOK allowFunctions (dflags, rep_tc)
+ | not (xopt Opt_DeriveFunctor dflags)
+ = Just (ptext (sLit "You need -XDeriveFunctor to derive an instance for this class"))
+
+ | null tc_tvs
+ = Just (ptext (sLit "Data type") <+> quotes (ppr rep_tc)
+ <+> ptext (sLit "has no parameters"))
+
+ | not (null bad_stupid_theta)
+ = Just (ptext (sLit "Data type") <+> quotes (ppr rep_tc)
+ <+> ptext (sLit "has a class context") <+> pprTheta bad_stupid_theta)
+
+ | otherwise
+ = msum (map check_con data_cons) -- msum picks the first 'Just', if any
+ where
+ tc_tvs = tyConTyVars rep_tc
+ Just (_, last_tv) = snocView tc_tvs
+ bad_stupid_theta = filter is_bad (tyConStupidTheta rep_tc)
+ is_bad pred = last_tv `elemVarSet` tyVarsOfPred pred
+
+ data_cons = tyConDataCons rep_tc
+ check_con con = msum (check_vanilla con : foldDataConArgs (ft_check con) con)
+
+ check_vanilla :: DataCon -> Maybe SDoc
+ check_vanilla con | isVanillaDataCon con = Nothing
+ | otherwise = Just (badCon con existential)
+
+ ft_check :: DataCon -> FFoldType (Maybe SDoc)
+ ft_check con = FT { ft_triv = Nothing, ft_var = Nothing
+ , ft_co_var = Just (badCon con covariant)
+ , ft_fun = \x y -> if allowFunctions then x `mplus` y
+ else Just (badCon con functions)
+ , ft_tup = \_ xs -> msum xs
+ , ft_ty_app = \_ x -> x
+ , ft_bad_app = Just (badCon con wrong_arg)
+ , ft_forall = \_ x -> x }
+
+ existential = ptext (sLit "has existential arguments")
+ covariant = ptext (sLit "uses the type variable in a function argument")
+ functions = ptext (sLit "contains function types")
+ wrong_arg = ptext (sLit "uses the type variable in an argument other than the last")
+
+checkFlag :: ExtensionFlag -> Condition
+checkFlag flag (dflags, _)
+ | xopt flag dflags = Nothing
+ | otherwise = Just why