Commit 71006532 authored by Ryan Scott's avatar Ryan Scott Committed by Marge Bot

Reject nested foralls/contexts in instance types more consistently

GHC is very wishy-washy about rejecting instance declarations with
nested `forall`s or contexts that are surrounded by outermost
parentheses. This can even lead to some strange interactions with
`ScopedTypeVariables`, as demonstrated in #18240. This patch makes
GHC more consistently reject instance types with nested
`forall`s/contexts so as to prevent these strange interactions.

On the implementation side, this patch tweaks `splitLHsInstDeclTy`
and `getLHsInstDeclHead` to not look through parentheses, which can
be semantically significant. I've added a
`Note [No nested foralls or contexts in instance types]` in
`GHC.Hs.Type` to explain why. This also introduces a
`no_nested_foralls_contexts_err` function in `GHC.Rename.HsType` to
catch nested `forall`s/contexts in instance types. This function is
now used in `rnClsInstDecl` (for ordinary instance declarations) and
`rnSrcDerivDecl` (for standalone `deriving` declarations), the latter
of which fixes #18271.

On the documentation side, this adds a new
"Formal syntax for instance declaration types" section to the GHC
User's Guide that presents a BNF-style grammar for what is and isn't
allowed in instance types.

Fixes #18240. Fixes #18271.
parent bfa5698b
This diff is collapsed.
This diff is collapsed.
......@@ -150,6 +150,22 @@ Language
data U a where
MkU :: (Show a => U a)
* GHC more strictly enforces the rule that the type in the top of an instance
declaration is not permitted to contain nested ``forall``\ s or contexts, as
documented in :ref:`formal-instance-syntax`. For example, the following
examples, which previous versions of GHC would accept, are now rejected:
instance (forall a. C a) where ...
instance (Show a => C a) where ...
In addition, GHC now enforces the rule that the types in ``deriving`` clauses
and ``via`` types (for instances derived with :extension:`DerivingVia`)
cannot contain nested ``forall``\ s or contexts. For example, the following
examples, which previous versions of GHC would accept, are now rejected: ::
data T = MkT deriving (C1, (forall x. C2 x))
deriving via (forall x. V x) instance C (S x)
* A new language extension :extension:`QualifiedDo` is implemented, allowing
to qualify a do block to control which operations to use for desugaring do
syntax. ::
......
......@@ -37,6 +37,11 @@ Notes:
instance forall a. Eq a => Eq [a] where ...
Note that the use of ``forall``s in instance declarations is somewhat
restricted in comparison to other types. For example, instance declarations
are not allowed to contain nested ``forall``s. See
:ref:`formal-instance-syntax` for more information.
- If the :ghc-flag:`-Wunused-foralls` flag is enabled, a warning will be emitted
when you write a type variable in an explicit ``forall`` statement that is
otherwise unused. For instance: ::
......
......@@ -99,6 +99,77 @@ GHC relaxes this rule in two ways:
However, the instance declaration must still conform to the rules for
instance termination: see :ref:`instance-termination`.
.. _formal-instance-syntax:
Formal syntax for instance declaration types
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The top of an instance declaration only permits very specific forms of types.
To make more precise what forms of types are or are not permitted, we provide a
BNF-style grammar for the tops of instance declarations below: ::
inst_top ::= 'instance' opt_forall opt_ctxt inst_head opt_where
opt_forall ::= <empty>
| 'forall' tv_bndrs '.'
tv_bndrs ::= <empty>
| tv_bndr tv_bndrs
tv_bndr ::= tyvar
| '(' tyvar '::' ctype ')'
opt_ctxt ::= <empty>
| btype '=>'
| '(' ctxt ')' '=>'
ctxt ::= ctype
| ctype ',' ctxt
inst_head ::= '(' inst_head ')'
| prefix_cls_tycon arg_types
| arg_type infix_cls_tycon arg_type
| '(' arg_type infix_cls_tycon arg_type ')' arg_types
arg_type ::= <empty>
| arg_type arg_types
opt_where ::= <empty>
| 'where'
Where:
- ``btype`` is a type that is not allowed to have an outermost
``forall``/``=>`` unless it is surrounded by parentheses. For example,
``forall a. a`` and ``Eq a => a`` are not legal ``btype``s, but
``(forall a. a)`` and ``(Eq a => a)`` are legal.
- ``ctype`` is a ``btype`` that has no restrictions on an outermost
``forall``/``=>``, so ``forall a. a`` and ``Eq a => a`` are legal ``ctype``s.
- ``arg_type`` is a type that is not allowed to have ``forall``s or ``=>``s
- ``prefix_cls_tycon`` is a class type constructor written prefix (e.g.,
``Show`` or ``(&&&)``), while ``infix_cls_tycon`` is a class type constructor
written infix (e.g., ```Show``` or ``&&&``).
This is a simplified grammar that does not fully delve into all of the
implementation details of GHC's parser (such as the placement of Haddock
comments), but it is sufficient to attain an understanding of what is
syntactically allowed. Some further various observations about this grammar:
- Instance declarations are not allowed to be declared with nested ``forall``s
or ``=>``s. For example, this would be rejected: ::
instance forall a. forall b. C (Either a b) where ...
As a result, ``inst_top`` puts all of its quantification and constraints up
front with ``opt_forall`` and ``opt_context``.
- Furthermore, instance declarations types do not permit outermost parentheses
that surround the ``opt_forall`` or ``opt_ctxt``, if at least one of them are
used. For example, ``instance (forall a. C a)`` would be rejected, since GHC
would treat the ``forall`` as being nested.
Note that it is acceptable to use parentheses in a ``inst_head``. For
instance, ``instance (C a)`` is accepted, as is ``instance forall a. (C a)``.
.. _instance-rules:
Relaxed rules for instance contexts
......
......@@ -16,11 +16,11 @@ Lexically scoped type variables
.. tip::
``ScopedTypeVariables`` breaks GHC's usual rule that explicit ``forall`` is optional and doesn't affect semantics.
:extension:`ScopedTypeVariables` breaks GHC's usual rule that explicit ``forall`` is optional and doesn't affect semantics.
For the :ref:`decl-type-sigs` (or :ref:`exp-type-sigs`) examples in this section,
the explicit ``forall`` is required.
(If omitted, usually the program will not compile; in a few cases it will compile but the functions get a different signature.)
To trigger those forms of ``ScopedTypeVariables``, the ``forall`` must appear against the top-level signature (or outer expression)
To trigger those forms of :extension:`ScopedTypeVariables`, the ``forall`` must appear against the top-level signature (or outer expression)
but *not* against nested signatures referring to the same type variables.
Explicit ``forall`` is not always required -- see :ref:`pattern signature equivalent <pattern-equiv-form>` for the example in this section, or :ref:`pattern-type-sigs`.
......@@ -261,11 +261,12 @@ the pattern, rather than the pattern binding the variable.
Class and instance declarations
-------------------------------
The type variables in the head of a ``class`` or ``instance``
declaration scope over the methods defined in the ``where`` part. You do
not even need an explicit ``forall`` (although you are allowed an explicit
``forall`` in an ``instance`` declaration; see :ref:`explicit-foralls`).
For example: ::
:extension:`ScopedTypeVariables` allow the type variables bound by the top of a
``class`` or ``instance`` declaration to scope over the methods defined in the
``where`` part. Unlike :ref`decl-type-sigs`, type variables from class and
instance declarations can be lexically scoped without an explicit ``forall``
(although you are allowed an explicit ``forall`` in an ``instance``
declaration; see :ref:`explicit-foralls`). For example: ::
class C a where
op :: [a] -> a
......@@ -278,4 +279,36 @@ For example: ::
instance C b => C [b] where
op xs = reverse (head (xs :: [[b]]))
-- Alternatively, one could write the instance above as:
instance forall b. C b => C [b] where
op xs = reverse (head (xs :: [[b]]))
While :extension:`ScopedTypeVariables` is required for type variables from the
top of a class or instance declaration to scope over the /bodies/ of the
methods, it is not required for the type variables to scope over the /type
signatures/ of the methods. For example, the following will be accepted without
explicitly enabling :extension:`ScopedTypeVariables`: ::
class D a where
m :: [a] -> a
instance D [a] where
m :: [a] -> [a]
m = reverse
Note that writing ``m :: [a] -> [a]`` requires the use of the
:extension:`InstanceSigs` extension.
Similarly, :extension:`ScopedTypeVariables` is not required for type variables
from the top of the class or instance declaration to scope over associated type
families, which only requires the :extension:`TypeFamilies` extension. For
instance, the following will be accepted without explicitly enabling
:extension:`ScopedTypeVariables`: ::
class E a where
type T a
instance E [a] where
type T [a] = a
See :ref:`scoping-class-params` for further information.
T16326_Fail8.hs:7:10: error:
Illegal class instance: ‘forall a -> C (Blah a)’
Class instances must be of the form
context => C ty_1 ... ty_n
where ‘C’ is a class
Illegal visible, dependent quantification in the type of a term
(GHC does not yet support this)
In an instance declaration
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE StandaloneDeriving #-}
module T18271 where
class C a
deriving instance forall a -> C (Maybe a)
T18271.hs:7:19: error:
Illegal visible, dependent quantification in the type of a term
(GHC does not yet support this)
In a deriving declaration
......@@ -65,3 +65,4 @@ test('T14880-2', normal, compile_fail, [''])
test('T15076', normal, compile_fail, [''])
test('T15076b', normal, compile_fail, [''])
test('T17687', normal, compile_fail, [''])
test('T18271', normal, compile_fail, [''])
......@@ -13,21 +13,21 @@ newtype Age = MkAge Int
deriving Ord
via Const Int (Any :: k)
deriving Read
via (forall k. Const Int (Any :: k))
via forall k. Const Int (Any :: k)
deriving Show
via Const Int a
deriving Enum
via Const Int (a :: k)
deriving Bounded
via (forall a. Const Int a)
via forall a. Const Int a
deriving Num
via (forall k (a :: k). Const Int a)
via forall k (a :: k). Const Int a
newtype Age2 = MkAge2 Int
deriving via Const Int Any instance Eq Age2
deriving via Const Int (Any :: k) instance Ord Age2
deriving via (forall k. Const Int (Any :: k)) instance Read Age2
deriving via Const Int a instance Show Age2
deriving via Const Int (a :: k) instance Enum Age2
deriving via (forall a. Const Int a) instance Bounded Age2
deriving via (forall k (a :: k). Const Int a) instance Num Age2
deriving via Const Int Any instance Eq Age2
deriving via Const Int (Any :: k) instance Ord Age2
deriving via forall k. Const Int (Any :: k) instance Read Age2
deriving via Const Int a instance Show Age2
deriving via Const Int (a :: k) instance Enum Age2
deriving via forall a. Const Int a instance Bounded Age2
deriving via forall k (a :: k). Const Int a instance Num Age2
......@@ -37,6 +37,6 @@ data X1 a
data X2 a
data X3 a
deriving via (forall a. T a) instance Z a (X1 b)
deriving via (T a) instance forall b. Z a (X2 b)
deriving via (forall a. T a) instance forall b. Z a (X3 b)
deriving via forall a. T a instance Z a (X1 b)
deriving via T a instance forall b. Z a (X2 b)
deriving via forall a. T a instance forall b. Z a (X3 b)
......@@ -12,4 +12,4 @@ newtype Foo2 a b = Foo2 (a -> b)
deriving Category
via fooo
data Foo3 deriving Eq via (forall a. a)
data Foo3 deriving Eq via forall a. a
......@@ -14,4 +14,4 @@ newtype F1 = F1 Int
deriving Eq via Char
newtype F2 a = MkF2 a
deriving (C a) via (forall a. a)
deriving (C a) via forall a. a
T3811c.hs:6:10: error:
Illegal class instance: ‘!Show D’
Class instances must be of the form
context => C ty_1 ... ty_n
Illegal head of an instance declaration: ‘!Show D’
Instance heads must be of the form
C ty_1 ... ty_n
where ‘C’ is a class
In an instance declaration
T16114.hs:4:10: error:
Illegal class instance: ‘Eq a => Eq a => Eq (T a)’
Class instances must be of the form
context => C ty_1 ... ty_n
where ‘C’ is a class
T16114.hs:4:18: error:
Instance head cannot contain nested ‘forall’s or contexts
In an instance declaration
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module T18240a where
import Data.Proxy
class C a where
m :: Proxy a
instance (forall a. C [a]) where
m = Proxy @[a]
instance (Eq a => C [a]) where
m = Proxy @[a]
instance (forall a. C (Either a b)) where
m = Proxy @(Either a b)
instance forall a. (forall b. C (Either a b)) where
m = Proxy @(Either a b)
instance Eq a => (Eq b => C (Either a b)) where
m = Proxy @(Either a b)
-- Some other nonsensical instance types
instance 42
instance Int -> Int
T18240a.hs:11:11: error:
Instance head cannot contain nested ‘forall’s or contexts
In an instance declaration
T18240a.hs:12:15: error: Not in scope: type variable ‘a’
T18240a.hs:14:11: error:
Instance head cannot contain nested ‘forall’s or contexts
In an instance declaration
T18240a.hs:17:11: error:
Instance head cannot contain nested ‘forall’s or contexts
In an instance declaration
T18240a.hs:18:22: error: Not in scope: type variable ‘a’
T18240a.hs:20:21: error:
Instance head cannot contain nested ‘forall’s or contexts
In an instance declaration
T18240a.hs:21:24: error: Not in scope: type variable ‘b’
T18240a.hs:23:19: error:
Instance head cannot contain nested ‘forall’s or contexts
In an instance declaration
T18240a.hs:28:10: error:
Illegal head of an instance declaration: ‘42’
Instance heads must be of the form
C ty_1 ... ty_n
where ‘C’ is a class
In an instance declaration
T18240a.hs:29:10: error:
Illegal head of an instance declaration: ‘Int -> Int’
Instance heads must be of the form
C ty_1 ... ty_n
where ‘C’ is a class
In an instance declaration
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE StandaloneDeriving #-}
module T18240b where
import Data.Proxy
data T a b
class W x y z
instance W x y (T a b)
newtype Foo a b = MkFoo (T a b)
deriving via (forall x. T x y) instance W x y (Foo a b)
deriving via forall x. forall y. T x y instance W x y (Foo a b)
deriving via forall x. (forall y. T x y) instance W x y (Foo a b)
class C1 x
class C2 x y z
data Bar = MkBar
deriving anyclass ( C1
, (forall x. C2 x y)
, forall x. forall y. C2 x y
, forall x. (forall y. C2 x y)
)
T18240b.hs:17:15: error:
‘via’ type cannot contain nested ‘forall’s or contexts
In a deriving declaration
T18240b.hs:18:24: error:
‘via’ type cannot contain nested ‘forall’s or contexts
In a deriving declaration
T18240b.hs:19:25: error:
‘via’ type cannot contain nested ‘forall’s or contexts
In a deriving declaration
T18240b.hs:26:24: error:
Derived class type cannot contain nested ‘forall’s or contexts
In the data type declaration for ‘Bar’
T18240b.hs:27:33: error:
Derived class type cannot contain nested ‘forall’s or contexts
In the data type declaration for ‘Bar’
T18240b.hs:28:34: error:
Derived class type cannot contain nested ‘forall’s or contexts
In the data type declaration for ‘Bar’
T5951.hs:8:8: error:
Illegal class instance: ‘A => B => C’
Class instances must be of the form
context => C ty_1 ... ty_n
where ‘C’ is a class
T5951.hs:9:8: error:
Instance head cannot contain nested ‘forall’s or contexts
In an instance declaration
......@@ -154,3 +154,5 @@ test('T14548', normal, compile_fail, [''])
test('T16610', normal, compile_fail, [''])
test('T17593', normal, compile_fail, [''])
test('T18145', normal, compile_fail, [''])
test('T18240a', normal, compile_fail, [''])
test('T18240b', normal, compile_fail, [''])
T16394.hs:6:10: error:
Illegal class instance: ‘C a => C b => C (a, b)’
Class instances must be of the form
context => C ty_1 ... ty_n
where ‘C’ is a class
T16394.hs:6:17: error:
Instance head cannot contain nested ‘forall’s or contexts
In an instance declaration
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