Commit 275dcafb authored by Krzysztof Gogolewski's avatar Krzysztof Gogolewski Committed by Edward Z. Yang

Add -fwarn-context-quantification (#4426)

Summary:
This warning (enabled by default) reports places where a context
implicitly binds a type variable, for example

type T a = {-forall m.-} Monad m => a -> m a

Also update Haddock submodule.

Test Plan: validate

Reviewers: hvr, goldfire, simonpj, austin

Reviewed By: austin

Subscribers: simonmar, ezyang, carter

Differential Revision: https://phabricator.haskell.org/D211

GHC Trac Issues: #4426
parent ed58ec05
......@@ -50,6 +50,7 @@ module HsDecls (
-- ** @default@ declarations
DefaultDecl(..), LDefaultDecl,
-- ** Template haskell declaration splice
SpliceExplicitFlag(..),
SpliceDecl(..), LSpliceDecl,
-- ** Foreign function interface declarations
ForeignDecl(..), LForeignDecl, ForeignImport(..), ForeignExport(..),
......@@ -294,12 +295,15 @@ instance OutputableBndr name => Outputable (HsGroup name) where
vcat_mb gap (Nothing : ds) = vcat_mb gap ds
vcat_mb gap (Just d : ds) = gap $$ d $$ vcat_mb blankLine ds
data SpliceExplicitFlag = ExplicitSplice | -- <=> $(f x y)
ImplicitSplice -- <=> f x y, i.e. a naked top level expression
deriving (Data, Typeable)
type LSpliceDecl name = Located (SpliceDecl name)
data SpliceDecl id
= SpliceDecl -- Top level splice
(Located (HsSplice id))
HsExplicitFlag -- Explicit <=> $(f x y)
-- Implicit <=> f x y, i.e. a naked top level expression
SpliceExplicitFlag
deriving (Typeable)
deriving instance (DataId id) => Data (SpliceDecl id)
......
......@@ -33,7 +33,8 @@ module HsTypes (
ConDeclField(..), pprConDeclFields,
mkHsQTvs, hsQTvBndrs, isHsKindedTyVar, hsTvbAllKinded,
mkExplicitHsForAllTy, mkImplicitHsForAllTy, hsExplicitTvs,
mkExplicitHsForAllTy, mkImplicitHsForAllTy, mkQualifiedHsForAllTy,
hsExplicitTvs,
hsTyVarName, mkHsWithBndrs, hsLKiTyVarNames,
hsLTyVarName, hsLTyVarNames, hsLTyVarLocName, hsLTyVarLocNames,
splitLHsInstDeclTy_maybe,
......@@ -301,6 +302,13 @@ After renaming
* Implicit => the *type* variables free in the type
Explicit => the variables the user wrote (renamed)
Qualified currently behaves exactly as Implicit,
but it is deprecated to use it for implicit quantification.
In this case, GHC 7.10 gives a warning; see
Note [Context quantification] and Trac #4426.
In GHC 7.12, Qualified will no longer bind variables
and this will become an error.
The kind variables bound in the hsq_kvs field come both
a) from the kind signatures on the kind vars (eg k1)
b) from the scope of the forall (eg k2)
......@@ -386,7 +394,7 @@ data HsTupleSort = HsUnboxedTuple
| HsBoxedOrConstraintTuple
deriving (Data, Typeable)
data HsExplicitFlag = Explicit | Implicit deriving (Data, Typeable)
data HsExplicitFlag = Qualified | Implicit | Explicit deriving (Data, Typeable)
data ConDeclField name -- Record fields have Haddoc docs on them
= ConDeclField { cd_fld_name :: Located name,
......@@ -405,10 +413,12 @@ deriving instance (DataId name) => Data (ConDeclField name)
--
-- A valid type must have one for-all at the top of the type, or of the fn arg types
mkImplicitHsForAllTy :: LHsContext RdrName -> LHsType RdrName -> HsType RdrName
mkExplicitHsForAllTy :: [LHsTyVarBndr RdrName] -> LHsContext RdrName -> LHsType RdrName -> HsType RdrName
mkImplicitHsForAllTy ctxt ty = mkHsForAllTy Implicit [] ctxt ty
mkExplicitHsForAllTy tvs ctxt ty = mkHsForAllTy Explicit tvs ctxt ty
mkImplicitHsForAllTy :: LHsContext RdrName -> LHsType RdrName -> HsType RdrName
mkExplicitHsForAllTy :: [LHsTyVarBndr RdrName] -> LHsContext RdrName -> LHsType RdrName -> HsType RdrName
mkQualifiedHsForAllTy :: LHsContext RdrName -> LHsType RdrName -> HsType RdrName
mkImplicitHsForAllTy ctxt ty = mkHsForAllTy Implicit [] ctxt ty
mkExplicitHsForAllTy tvs ctxt ty = mkHsForAllTy Explicit tvs ctxt ty
mkQualifiedHsForAllTy ctxt ty = mkHsForAllTy Qualified [] ctxt ty
mkHsForAllTy :: HsExplicitFlag -> [LHsTyVarBndr RdrName] -> LHsContext RdrName -> LHsType RdrName -> HsType RdrName
-- Smart constructor for HsForAllTy
......@@ -427,8 +437,10 @@ mk_forall_ty exp tvs ty = HsForAllTy exp (m
-- so that (forall. ty) isn't implicitly quantified
plus :: HsExplicitFlag -> HsExplicitFlag -> HsExplicitFlag
Implicit `plus` Implicit = Implicit
_ `plus` _ = Explicit
Qualified `plus` Qualified = Qualified
Explicit `plus` _ = Explicit
_ `plus` Explicit = Explicit
_ `plus` _ = Implicit
hsExplicitTvs :: LHsType Name -> [Name]
-- The explicitly-given forall'd type variables of a HsType
......@@ -588,7 +600,7 @@ pprHsForAll exp qtvs cxt
where
show_forall = opt_PprStyle_Debug
|| (not (null (hsQTvBndrs qtvs)) && is_explicit)
is_explicit = case exp of {Explicit -> True; Implicit -> False}
is_explicit = case exp of {Explicit -> True; Implicit -> False; Qualified -> False}
forall_part = forAllLit <+> ppr qtvs <> dot
pprHsContext :: (OutputableBndr name) => HsContext name -> SDoc
......
......@@ -452,6 +452,7 @@ data WarningFlag =
| Opt_WarnUnusedBinds
| Opt_WarnUnusedImports
| Opt_WarnUnusedMatches
| Opt_WarnContextQuantification
| Opt_WarnWarningsDeprecations
| Opt_WarnDeprecatedFlags
| Opt_WarnAMP
......@@ -2624,6 +2625,7 @@ fWarningFlags = [
( "warn-unused-binds", Opt_WarnUnusedBinds, nop ),
( "warn-unused-imports", Opt_WarnUnusedImports, nop ),
( "warn-unused-matches", Opt_WarnUnusedMatches, nop ),
( "warn-context-quantification", Opt_WarnContextQuantification, nop ),
( "warn-warnings-deprecations", Opt_WarnWarningsDeprecations, nop ),
( "warn-deprecations", Opt_WarnWarningsDeprecations, nop ),
( "warn-deprecated-flags", Opt_WarnDeprecatedFlags, nop ),
......@@ -3070,7 +3072,8 @@ standardWarnings
Opt_WarnDodgyForeignImports,
Opt_WarnInlineRuleShadowing,
Opt_WarnAlternativeLayoutRuleTransitional,
Opt_WarnUnsupportedLlvmVersion
Opt_WarnUnsupportedLlvmVersion,
Opt_WarnContextQuantification
]
minusWOpts :: [WarningFlag]
......
......@@ -199,7 +199,7 @@ printException err = do
liftIO $ printBagOfErrors dflags (srcErrorMessages err)
-- | A function called to log warnings and errors.
type WarnErrLogger = GhcMonad m => Maybe SourceError -> m ()
type WarnErrLogger = forall m. GhcMonad m => Maybe SourceError -> m ()
defaultWarnErrLogger :: WarnErrLogger
defaultWarnErrLogger Nothing = return ()
......
......@@ -1115,8 +1115,7 @@ strict_mark :: { Located HsBang }
ctype :: { LHsType RdrName }
: 'forall' tv_bndrs '.' ctype {% hintExplicitForall (getLoc $1) >>
return (LL $ mkExplicitHsForAllTy $2 (noLoc []) $4) }
| context '=>' ctype { LL $ mkImplicitHsForAllTy $1 $3 }
-- A type of form (context => type) is an *implicit* HsForAllTy
| context '=>' ctype { LL $ mkQualifiedHsForAllTy $1 $3 }
| ipvar '::' type { LL (HsIParamTy (unLoc $1) $3) }
| type { $1 }
......@@ -1134,8 +1133,7 @@ ctype :: { LHsType RdrName }
ctypedoc :: { LHsType RdrName }
: 'forall' tv_bndrs '.' ctypedoc {% hintExplicitForall (getLoc $1) >>
return (LL $ mkExplicitHsForAllTy $2 (noLoc []) $4) }
| context '=>' ctypedoc { LL $ mkImplicitHsForAllTy $1 $3 }
-- A type of form (context => type) is an *implicit* HsForAllTy
| context '=>' ctypedoc { LL $ mkQualifiedHsForAllTy $1 $3 }
| ipvar '::' type { LL (HsIParamTy (unLoc $1) $3) }
| typedoc { $1 }
......
......@@ -256,8 +256,8 @@ mkSpliceDecl :: LHsExpr RdrName -> HsDecl RdrName
mkSpliceDecl lexpr@(L loc expr)
| HsQuasiQuoteE qq <- expr = QuasiQuoteD qq
| HsSpliceE is_typed splice <- expr = ASSERT( not is_typed )
SpliceD (SpliceDecl (L loc splice) Explicit)
| otherwise = SpliceD (SpliceDecl (L loc splice) Implicit)
SpliceD (SpliceDecl (L loc splice) ExplicitSplice)
| otherwise = SpliceD (SpliceDecl (L loc splice) ImplicitSplice)
where
splice = mkHsSplice lexpr
......
......@@ -1286,8 +1286,13 @@ rnConDecl decl@(ConDecl { con_name = name, con_qvars = tvs
-- With an Explicit forall, check for unused binders
-- With Implicit, find the mentioned ones, and use them as binders
-- With Qualified, do the same as with Implicit, but give a warning
-- See Note [Context quantification]
; new_tvs <- case expl of
Implicit -> return (mkHsQTvs (userHsTyVarBndrs loc free_tvs))
Qualified -> do { warnContextQuantification (docOfHsDocContext doc)
(userHsTyVarBndrs loc free_tvs)
; return (mkHsQTvs (userHsTyVarBndrs loc free_tvs)) }
Explicit -> do { warnUnusedForAlls (docOfHsDocContext doc) tvs free_tvs
; return tvs }
......@@ -1471,10 +1476,10 @@ add gp loc (SpliceD splice@(SpliceDecl _ flag)) ds
= do { -- We've found a top-level splice. If it is an *implicit* one
-- (i.e. a naked top level expression)
case flag of
Explicit -> return ()
Implicit -> do { th_on <- xoptM Opt_TemplateHaskell
; unless th_on $ setSrcSpan loc $
failWith badImplicitSplice }
ExplicitSplice -> return ()
ImplicitSplice -> do { th_on <- xoptM Opt_TemplateHaskell
; unless th_on $ setSrcSpan loc $
failWith badImplicitSplice }
; return (gp, Just (splice, ds)) }
where
......
......@@ -15,9 +15,10 @@ module RnTypes (
-- Precence related stuff
mkOpAppRn, mkNegAppRn, mkOpFormRn, mkConOpPatRn,
checkPrecMatch, checkSectionPrec, warnUnusedForAlls,
checkPrecMatch, checkSectionPrec,
-- Binding related stuff
warnContextQuantification, warnUnusedForAlls,
bindSigTyVarsFV, bindHsTyVars, rnHsBndrSig,
extractHsTyRdrTyVars, extractHsTysRdrTyVars,
extractRdrKindSigVars, extractDataDefnKindVars, filterInScope
......@@ -84,6 +85,25 @@ badInstTy ty = ptext (sLit "Malformed instance:") <+> ppr ty
rnHsType is here because we call it from loadInstDecl, and I didn't
want a gratuitous knot.
Note [Context quantification]
-----------------------------
Variables in type signatures are implicitly quantified
when (1) they are in a type signature not beginning
with "forall" or (2) in any qualified type T => R.
We are phasing out (2) since it leads to inconsistencies
(Trac #4426):
data A = A (a -> a) is an error
data A = A (Eq a => a -> a) binds "a"
data A = A (Eq a => a -> b) binds "a" and "b"
data A = A (() => a -> b) binds "a" and "b"
f :: forall a. a -> b is an error
f :: forall a. () => a -> b is an error
f :: forall a. a -> (() => b) binds "a" and "b"
The -fwarn-context-quantification flag warns about
this situation. See rnHsTyKi for case HsForAllTy Qualified.
\begin{code}
rnLHsTyKi :: Bool -- True <=> renaming a type, False <=> a kind
-> HsDocContext -> LHsType RdrName -> RnM (LHsType Name, FreeVars)
......@@ -136,6 +156,20 @@ rnHsTyKi isType doc (HsForAllTy Implicit _ lctxt@(L _ ctxt) ty)
rnForAll doc Implicit forall_kvs (mkHsQTvs tyvar_bndrs) lctxt ty
rnHsTyKi isType doc fulltype@(HsForAllTy Qualified _ lctxt@(L _ ctxt) ty)
= ASSERT( isType ) do
rdr_env <- getLocalRdrEnv
loc <- getSrcSpanM
let
(forall_kvs, forall_tvs) = filterInScope rdr_env $
extractHsTysRdrTyVars (ty:ctxt)
tyvar_bndrs = userHsTyVarBndrs loc forall_tvs
in_type_doc = ptext (sLit "In the type") <+> quotes (ppr fulltype)
-- See Note [Context quantification]
warnContextQuantification (in_type_doc $$ docOfHsDocContext doc) tyvar_bndrs
rnForAll doc Implicit forall_kvs (mkHsQTvs tyvar_bndrs) lctxt ty
rnHsTyKi isType doc ty@(HsForAllTy Explicit forall_tyvars lctxt@(L _ ctxt) tau)
= ASSERT( isType ) do { -- Explicit quantification.
-- Check that the forall'd tyvars are actually
......@@ -825,6 +859,19 @@ warnUnusedForAlls in_doc bound mentioned_rdrs
vcat [ ptext (sLit "Unused quantified type variable") <+> quotes (ppr tv)
, in_doc ]
warnContextQuantification :: SDoc -> [LHsTyVarBndr RdrName] -> TcM ()
warnContextQuantification in_doc tvs
= whenWOptM Opt_WarnContextQuantification $
mapM_ add_warn tvs
where
add_warn (L loc tv)
= addWarnAt loc $
vcat [ ptext (sLit "Variable") <+> quotes (ppr tv) <+>
ptext (sLit "is implicitly quantified due to a context") $$
ptext (sLit "Use explicit forall syntax instead.") $$
ptext (sLit "This will become an error in GHC 7.12.")
, in_doc ]
opTyErr :: RdrName -> HsType RdrName -> SDoc
opTyErr op ty@(HsOpTy ty1 _ _)
= hang (ptext (sLit "Illegal operator") <+> quotes (ppr op) <+> ptext (sLit "in type") <+> quotes (ppr ty))
......
......@@ -34,6 +34,30 @@
Added support for <link linkend="binary-literals">binary integer literals</link>
</para>
</listitem>
<listitem>
<para>
Simplified rules for implicit quantification. In previous versions of GHC,
it was possible to use the <literal>=></literal> arrow
to quantify over type variables in <literal>data</literal> and
<literal>type</literal> declarations without a
<literal>forall</literal> quantifier. For example,
<literal>data Fun = Fun (Ord a => a -> b)</literal> was identical to
<literal>data Fun = Fun (forall a b. Ord a => a -> b)</literal>, while
<literal>data Fun = Fun (a -> b)</literal> caused a not-in-scope error.
This implicit quantification is now deprecated, and variables
in higher-rank constructors should be quantified with <literal>forall</literal>
regardless of whether a class context is present or not.
GHC 7.10 raises a warning (controlled by
<option>-fwarn-context-quantification</option>, enabled by default)
and GHC 7.12 will raise an error. See <link linkend="univ">examples</link>
in GHC documentation.
</para>
<para>
The change also applies to Template Haskell splices such as
<literal>[t|Ord a => a|]</literal>, which should be written as
<literal>[t|forall a. Ord a => a|]</literal>.
</para>
</listitem>
</itemizedlist>
</sect3>
......
......@@ -7702,7 +7702,7 @@ data MonadT m = MkMonad { return :: forall a. a -> m a,
bind :: forall a b. m a -> (a -> m b) -> m b
}
newtype Swizzle = MkSwizzle (Ord a => [a] -> [a])
newtype Swizzle = MkSwizzle (forall a. Ord a => [a] -> [a])
</programlisting>
</para>
......@@ -7718,22 +7718,22 @@ T1 :: forall a. (forall b. b -> b -> b) -> a -> T a
MkMonad :: forall m. (forall a. a -> m a)
-> (forall a b. m a -> (a -> m b) -> m b)
-> MonadT m
MkSwizzle :: (Ord a => [a] -> [a]) -> Swizzle
MkSwizzle :: (forall a. Ord a => [a] -> [a]) -> Swizzle
</programlisting>
</para>
<para>
Notice that you don't need to use a <literal>forall</literal> if there's an
explicit context. For example in the first argument of the
constructor <function>MkSwizzle</function>, an implicit "<literal>forall a.</literal>" is
prefixed to the argument type. The implicit <literal>forall</literal>
quantifies all type variables that are not already in scope, and are
mentioned in the type quantified over. (Arguably, it would be better
to <emphasis>require</emphasis> explicit quantification on constructor arguments
where that is what is wanted.
See <ulink url="http://ghc.haskell.org/trac/ghc/ticket/4426">Trac #4426</ulink>.)
In earlier versions of GHC, it was possible to omit the <literal>forall</literal>
in the type of the constructor if there was an explicit context. For example:
<programlisting>
newtype Swizzle' = MkSwizzle' (Ord a => [a] -> [a])
</programlisting>
As of GHC 7.10, this is deprecated. The <literal>-fwarn-context-quantification</literal>
flag detects this situation and issues a warning. In GHC 7.12, declarations
such as <literal>MkSwizzle'</literal> will cause an out-of-scope error.
</para>
<para>
......
......@@ -1033,8 +1033,9 @@ test.hs:(5,4)-(6,7):
<option>-fwarn-wrong-do-bind</option>,
<option>-fwarn-unsupported-calling-conventions</option>,
<option>-fwarn-dodgy-foreign-imports</option>,
<option>-fwarn-inline-rule-shadowing</option>, and
<option>-fwarn-unsupported-llvm-version</option>.
<option>-fwarn-inline-rule-shadowing</option>,
<option>-fwarn-unsupported-llvm-version</option>, and
<option>-fwarn-context-quantification</option>.
The following flags are simple ways to select standard
&ldquo;packages&rdquo; of warnings:
</para>
......@@ -1841,6 +1842,27 @@ _ = rhs3 -- No warning: lone wild-card pattern
</listitem>
</varlistentry>
<varlistentry>
<term><option>-fwarn-context-quantification</option>:</term>
<listitem>
<indexterm><primary><option>-fwarn-context-quantification</option></primary></indexterm>
<indexterm><primary>implicit context quantification, warning</primary></indexterm>
<indexterm><primary>context, implicit quantification</primary></indexterm>
<para>Report if a variable is quantified only due to its presence
in a context (see <xref linkend="universal-quantification"/>). For example,
<programlisting>
type T a = Monad m => a -> f a
</programlisting>
It is recommended to write this polymorphic type as
<programlisting>
type T a = forall m. Monad m => a -> f a
</programlisting>
instead.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-fwarn-wrong-do-bind</option>:</term>
<listitem>
......
{-# LANGUAGE RankNTypes #-}
{-# OPTIONS_GHC -fwarn-context-quantification #-}
module T4426 where
type F a = Monad m => a -> m a
data X a = X (Eq b => a -> b)
data Y a = Y { k :: Eq b => a -> b -> c }
f :: forall b. (Monad m => m b) -> b
f = undefined
type F' a = forall m. Monad m => a -> m a
data X' a = X' (forall b. Eq b => a -> b)
data Y' a = Y' { k' :: forall b c. Eq b => a -> b -> c }
f' :: forall b. (forall m. Monad m => m b) -> b
f' = undefined
T4426.hs:6:12: Warning:
Variable ‘m’ is implicitly quantified due to a context
Use explicit forall syntax instead.
This will become an error in GHC 7.12.
In the type ‘Monad m => a -> m a’
In the declaration for type synonym ‘F’
T4426.hs:8:15: Warning:
Variable ‘b’ is implicitly quantified due to a context
Use explicit forall syntax instead.
This will become an error in GHC 7.12.
In the type ‘Eq b => a -> b’
In the definition of data constructor ‘X’
T4426.hs:10:21: Warning:
Variable ‘b’ is implicitly quantified due to a context
Use explicit forall syntax instead.
This will become an error in GHC 7.12.
In the type ‘Eq b => a -> b -> c’
In the definition of data constructor ‘Y’
T4426.hs:10:21: Warning:
Variable ‘c’ is implicitly quantified due to a context
Use explicit forall syntax instead.
This will become an error in GHC 7.12.
In the type ‘Eq b => a -> b -> c’
In the definition of data constructor ‘Y’
T4426.hs:12:17: Warning:
Variable ‘m’ is implicitly quantified due to a context
Use explicit forall syntax instead.
This will become an error in GHC 7.12.
In the type ‘Monad m => m b’
In the type signature for ‘f’
......@@ -217,3 +217,4 @@ test('T7969',
run_command,
['$MAKE -s --no-print-directory T7969'])
test('T9127', normal, compile, [''])
test('T4426', normal, compile, [''])
{-# LANGUAGE ConstraintKinds, TemplateHaskell, PolyKinds, TypeFamilies #-}
{-# LANGUAGE ConstraintKinds, TemplateHaskell, PolyKinds, TypeFamilies, RankNTypes #-}
module T7021a where
......@@ -27,5 +27,5 @@ test = do
reify fooName
reify bazName
reify barName
[t| (Show a, (Read a, Num a)) => a -> a |]
[t| forall a. (Show a, (Read a, Num a)) => a -> a |]
[| \_ -> 0 |]
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE ConstraintKinds, RankNTypes #-}
module T8807 where
import Data.Proxy
foo :: $( [t| a b => Proxy a -> b -> b |] )
foo = undefined
\ No newline at end of file
foo :: $( [t| forall a b. a b => Proxy a -> b -> b |] )
foo = undefined
......@@ -20,7 +20,7 @@ class Sat a where dict :: a
class Subst_A a t t' where
subst_A :: (Monad m) => a -> t -> t' -> m t'
data SubstD_A a t t' = SubstD_A {substD_A:: (Monad m) => a -> t -> t' -> m t'}
data SubstD_A a t t' = SubstD_A {substD_A:: forall m. (Monad m) => a -> t -> t' -> m t'}
-- Allow override dictionary verion with implementation of type class Subst
instance Subst_A a t t' => Sat (SubstD_A a t t') where
......@@ -103,4 +103,4 @@ constraints, and only makes the attempt when it has all the evidence
in hand. I'm thinking quite a bit about constraint solving at the
moment and will bear that in mind. But I can't offer you an immediate
solution. At least I hope I've explained the problem.
-}
\ No newline at end of file
-}
......@@ -2,7 +2,7 @@
module ShouldSucceed where
data Empty q = Empty (Ord a => q a)
data Empty q = Empty (forall a. Ord a => q a)
q :: (Ord a) => [a]
q = []
e0, e1, e2 :: Empty []
......
Subproject commit c3a7d4701ee64f6c29b95a6bed519f6c16b9bffd
Subproject commit 4023817d7c0e46db012ba2eea28022626841ca9b
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment