Commit 8df24474 authored by Vladislav Zavialov's avatar Vladislav Zavialov Committed by Ben Gamari
Browse files

Warn about implicit kind variables with -Wcompat

According to an accepted proposal
https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/002
4-no-kind-vars.rst

    With -Wcompat, warn if a kind variable is brought into scope
    implicitly in a type with an explicit forall. This applies to type
    signatures and to other contexts that allow a forall with the
    forall-or-nothing rule in effect (for example, class instances).

Test Plan: Validate

Reviewers: goldfire, hvr, bgamari, RyanGlScott

Reviewed By: goldfire

Subscribers: RyanGlScott, rwbarton, thomie, carter

GHC Trac Issues: #15264

Differential Revision: https://phabricator.haskell.org/D4834
parent 4cd55218
......@@ -807,6 +807,7 @@ data WarningFlag =
| Opt_WarnMissingExportList
| Opt_WarnInaccessibleCode
| Opt_WarnStarIsType -- Since 8.6
| Opt_WarnImplicitKindVars -- Since 8.6
deriving (Eq, Show, Enum)
data Language = Haskell98 | Haskell2010
......@@ -3784,6 +3785,7 @@ wWarningFlagsDeps = [
flagSpec "hi-shadowing" Opt_WarnHiShadows,
flagSpec "inaccessible-code" Opt_WarnInaccessibleCode,
flagSpec "implicit-prelude" Opt_WarnImplicitPrelude,
flagSpec "implicit-kind-vars" Opt_WarnImplicitKindVars,
flagSpec "incomplete-patterns" Opt_WarnIncompletePatterns,
flagSpec "incomplete-record-updates" Opt_WarnIncompletePatternsRecUpd,
flagSpec "incomplete-uni-patterns" Opt_WarnIncompleteUniPatterns,
......@@ -4593,6 +4595,7 @@ minusWcompatOpts
= [ Opt_WarnMissingMonadFailInstances
, Opt_WarnSemigroup
, Opt_WarnNonCanonicalMonoidInstances
, Opt_WarnImplicitKindVars
]
enableUnusedBinds :: DynP ()
......
......@@ -334,6 +334,11 @@ rnImplicitBndrs bind_free_tvs
; traceRn "rnImplicitBndrs" (vcat [ ppr kvs, ppr tvs, ppr real_tvs ])
; whenWOptM Opt_WarnImplicitKindVars $
unless (bind_free_tvs || null kvs) $
addWarnAt (Reason Opt_WarnImplicitKindVars) (getLoc (head kvs)) $
implicit_kind_vars_msg kvs
; loc <- getSrcSpanM
; vars <- mapM (newLocalBndrRn . L loc . unLoc) (kvs ++ real_tvs)
......@@ -343,6 +348,16 @@ rnImplicitBndrs bind_free_tvs
; bindLocalNamesFV vars $
thing_inside vars }
where
implicit_kind_vars_msg kvs =
vcat [ text "An explicit" <+> quotes (text "forall") <+>
text "was used, but the following kind variables" <+>
text "are not quantified:" <+>
hsep (punctuate comma (map (quotes . ppr) kvs))
, text "Despite this fact, GHC will introduce them into scope," <+>
text "but it will stop doing so in the future."
, text "Suggested fix: add" <+>
quotes (text "forall" <+> hsep (map ppr kvs) <> char '.') ]
rnLHsInstType :: SDoc -> LHsSigType GhcPs -> RnM (LHsSigType GhcRn, FreeVars)
-- Rename the type in an instance.
......
......@@ -152,6 +152,12 @@ Compiler
:ghc-flag:`-fexternal-dynamic-refs`. If you don't know why you might
need this, you don't need it.
- :ghc-flag:`-Wcompat` now includes :ghc-flag:`-Wimplicit-kind-vars` to
provide early detection of breakage that will be caused by implementation of
`GHC proposal #24
<https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0024-no-kind-vars.rst>`__
in a future release.
Plugins
~~~~~~~
......
......@@ -109,6 +109,7 @@ The following flags are simple ways to select standard "packages" of warnings:
* :ghc-flag:`-Wmissing-monadfail-instances`
* :ghc-flag:`-Wsemigroup`
* :ghc-flag:`-Wnoncanonical-monoid-instances`
* :ghc-flag:`-Wimplicit-kind-vars`
.. ghc-flag:: -Wno-compat
:shortdesc: Disables all warnings enabled by :ghc-flag:`-Wcompat`.
......@@ -768,6 +769,58 @@ of ``-W(no-)*``.
This warning is off by default.
.. ghc-flag:: -Wimplicit-kind-vars
:shortdesc: warn when kind variables are brought into scope implicitly despite
the "forall-or-nothing" rule
:type: dynamic
:reverse: -Wno-implicit-kind-vars
:category:
:since: 8.6
`GHC proposal #24
<https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0024-no-kind-vars.rst>`__
prescribes to treat kind variables and type variables identically in
``forall``, removing the legacy distinction between them.
Consider the following examples: ::
f :: Proxy a -> Proxy b -> ()
g :: forall a b. Proxy a -> Proxy b -> ()
``f`` does not use an explicit ``forall``, so type variables ``a`` and ``b``
are brought into scope implicitly. ``g`` quantifies both ``a`` and ``b``
explicitly. Both ``f`` and ``g`` work today and will continue to work in the
future because they adhere to the "forall-or-nothing" rule: either all type
variables in a function definition are introduced explicitly or implicitly,
there is no middle ground.
A violation of the "forall-or-nothing" rule looks like this: ::
m :: forall a. Proxy a -> Proxy b -> ()
``m`` does not introduce one of the variables, ``b``, and thus is rejected.
However, consider the following example: ::
n :: forall a. Proxy (a :: k) -> ()
While ``n`` uses ``k`` without introducing it and thus violates the rule, it
is currently accepted. This is because ``k`` in ``n`` is considered a kind
variable, as it occurs in a kind signature. In reality, the line between
type variables and kind variables is blurry, as the following example
demonstrates: ::
kindOf :: forall a. Proxy (a :: k) -> Proxy k
In ``kindOf``, the ``k`` variable is used both in a kind position and a type
position. Currently, ``kindOf`` happens to be accepted as well.
In a future release of GHC, both ``n`` and ``kindOf`` will be rejected per
the "forall-or-nothing" rule. This warning, being part of the
:ghc-flag:`-Wcompat` option group, allows to detect this before the actual
breaking change takes place.
.. ghc-flag:: -Wincomplete-patterns
:shortdesc: warn when a pattern match could fail
:type: dynamic
......
......@@ -476,7 +476,7 @@ splitApp (TrTyCon{trTyCon = con, trKindVars = kinds})
Refl -> IsCon con kinds
-- | Use a 'TypeRep' as 'Typeable' evidence.
withTypeable :: forall (a :: k) (r :: TYPE rep). ()
withTypeable :: forall k (a :: k) rep (r :: TYPE rep). ()
=> TypeRep a -> (Typeable a => r) -> r
withTypeable rep k = unsafeCoerce k' rep
where k' :: Gift a r
......@@ -631,7 +631,7 @@ unkindedTypeRep :: SomeKindedTypeRep k -> SomeTypeRep
unkindedTypeRep (SomeKindedTypeRep x) = SomeTypeRep x
data SomeKindedTypeRep k where
SomeKindedTypeRep :: forall (a :: k). TypeRep a
SomeKindedTypeRep :: forall k (a :: k). TypeRep a
-> SomeKindedTypeRep k
kApp :: SomeKindedTypeRep (k -> k')
......@@ -640,7 +640,7 @@ kApp :: SomeKindedTypeRep (k -> k')
kApp (SomeKindedTypeRep f) (SomeKindedTypeRep a) =
SomeKindedTypeRep (mkTrApp f a)
kindedTypeRep :: forall (a :: k). Typeable a => SomeKindedTypeRep k
kindedTypeRep :: forall k (a :: k). Typeable a => SomeKindedTypeRep k
kindedTypeRep = SomeKindedTypeRep (typeRep @a)
buildList :: forall k. Typeable k
......@@ -980,7 +980,8 @@ tcNat :: TyCon
tcNat = typeRepTyCon (typeRep @Nat)
-- | An internal function, to make representations for type literals.
typeLitTypeRep :: forall (a :: k). (Typeable k) => String -> TyCon -> TypeRep a
typeLitTypeRep :: forall k (a :: k). (Typeable k) =>
String -> TyCon -> TypeRep a
typeLitTypeRep nm kind_tycon = mkTrCon (mkTypeLitTyCon nm kind_tycon) []
-- | For compiler use.
......
{-# LANGUAGE ExplicitForAll, PolyKinds #-}
{-# OPTIONS -Wcompat #-}
module T15264 where
import Data.Proxy
bad1 :: forall (a :: k). Proxy a -> ()
bad1 _ = ()
bad2 :: forall (a :: k1) (b :: k2). Proxy a -> ()
bad2 _ = ()
good :: forall k (a :: k). Proxy a -> ()
good _ = ()
T15264.hs:8:22: warning: [-Wimplicit-kind-vars (in -Wcompat)]
An explicit ‘forall’ was used, but the following kind variables are not quantified: ‘k’
Despite this fact, GHC will introduce them into scope, but it will stop doing so in the future.
Suggested fix: add ‘forall k.’
T15264.hs:11:22: warning: [-Wimplicit-kind-vars (in -Wcompat)]
An explicit ‘forall’ was used, but the following kind variables are not quantified: ‘k1’, ‘k2’
Despite this fact, GHC will introduce them into scope, but it will stop doing so in the future.
Suggested fix: add ‘forall k1 k2.’
......@@ -48,4 +48,5 @@ test('T14720', normal, compile, [''])
test('T14066a', normal, compile, [''])
test('T14749', normal, compile, [''])
test('T14991', normal, compile, [''])
test('T15264', normal, compile, [''])
test('DkNameRes', normal, compile, [''])
\ No newline at end of file
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