summaryrefslogtreecommitdiff
path: root/compiler/GHC/Core/DataCon.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/Core/DataCon.hs')
-rw-r--r--compiler/GHC/Core/DataCon.hs77
1 files changed, 51 insertions, 26 deletions
diff --git a/compiler/GHC/Core/DataCon.hs b/compiler/GHC/Core/DataCon.hs
index c4c7f90a71..6c256cca10 100644
--- a/compiler/GHC/Core/DataCon.hs
+++ b/compiler/GHC/Core/DataCon.hs
@@ -251,12 +251,21 @@ Data types can have a context:
data (Eq a, Ord b) => T a b = T1 a b | T2 a
-and that makes the constructors have a context too
-(notice that T2's context is "thinned"):
+And that makes the constructors have a context too. A constructor's context
+isn't necessarily the same as the data type's context, however. Per the
+Haskell98 Report, the part of the datatype context that is used in a data
+constructor is the largest subset of the datatype context that constrains
+only the type variables free in the data constructor's field types. For
+example, here are the types of T1 and T2:
T1 :: (Eq a, Ord b) => a -> b -> T a b
T2 :: (Eq a) => a -> T a b
+Notice that T2's context is "thinned". Since its field is of type `a`, only
+the part of the datatype context that mentions `a`—that is, `Eq a`—is
+included in T2's context. On the other hand, T1's fields mention both `a`
+and `b`, so T1's context includes all of the datatype context.
+
Furthermore, this context pops up when pattern matching
(though GHC hasn't implemented this, but it is in H98, and
I've fixed GHC so that it now does):
@@ -267,36 +276,49 @@ gets inferred type
I say the context is "stupid" because the dictionaries passed
are immediately discarded -- they do nothing and have no benefit.
+(See Note [Instantiating stupid theta] in GHC.Tc.Gen.Head.)
It's a flaw in the language.
- Up to now [March 2002] I have put this stupid context into the
- type of the "wrapper" constructors functions, T1 and T2, but
- that turned out to be jolly inconvenient for generics, and
- record update, and other functions that build values of type T
- (because they don't have suitable dictionaries available).
+GHC has made some efforts to correct this flaw. In GHC, datatype contexts
+are not available by default. Instead, one must explicitly opt in to them by
+using the DatatypeContexts extension. To discourage their use, GHC has
+deprecated DatatypeContexts.
+
+Some other notes about stupid contexts:
+
+* Stupid contexts can interact badly with `deriving`. For instance, it's
+ unclear how to make this derived Functor instance typecheck:
- So now I've taken the stupid context out. I simply deal with
- it separately in the type checker on occurrences of a
- constructor, either in an expression or in a pattern.
+ data Eq a => T a = MkT a
+ deriving Functor
- [May 2003: actually I think this decision could easily be
- reversed now, and probably should be. Generics could be
- disabled for types with a stupid context; record updates now
- (H98) needs the context too; etc. It's an unforced change, so
- I'm leaving it for now --- but it does seem odd that the
- wrapper doesn't include the stupid context.]
+ This is because the derived instance would need to look something like
+ `instance Functor T where ...`, but there is nowhere to mention the
+ requisite `Eq a` constraint. For this reason, GHC will throw an error if a
+ user attempts to derive an instance for Functor (or a Functor-like class)
+ where the last type variable is used in a datatype context. For Generic(1),
+ the requirements are even harsher, as stupid contexts are not allowed at all
+ in derived Generic(1) instances. (We could consider relaxing this requirement
+ somewhat, although no one has asked for this yet.)
-[July 04] With the advent of generalised data types, it's less obvious
-what the "stupid context" is. Consider
- C :: forall a. Ord a => a -> a -> T (Foo a)
-Does the C constructor in Core contain the Ord dictionary? Yes, it must:
+ Stupid contexts are permitted when deriving instances of non-Functor-like
+ classes, or when deriving instances of Functor-like classes where the last
+ type variable isn't mentioned in the stupid context. For example, the
+ following is permitted:
- f :: T b -> Ordering
- f = /\b. \x:T b.
- case x of
- C a (d:Ord a) (p:a) (q:a) -> compare d p q
+ data Show a => T a = MkT deriving Eq
-Note that (Foo a) might not be an instance of Ord.
+ Note that because of the "thinning" behavior mentioned above, the generated
+ Eq instance should not mention `Show a`, as the type of MkT doesn't require
+ it. That is, the following should be generated (#20501):
+
+ instance Eq (T a) where
+ (MkT == MkT) = True
+
+* It's not obvious how stupid contexts should interact with GADTs. For this
+ reason, GHC disallows combining datatype contexts with GADT syntax. As a
+ result, dcStupidTheta is always empty for data types defined using GADT
+ syntax.
************************************************************************
* *
@@ -414,7 +436,8 @@ data DataCon
-- or, rather, a "thinned" version thereof
-- "Thinned", because the Report says
-- to eliminate any constraints that don't mention
- -- tyvars free in the arg types for this constructor
+ -- tyvars free in the arg types for this constructor.
+ -- See Note [The stupid context].
--
-- INVARIANT: the free tyvars of dcStupidTheta are a subset of dcUnivTyVars
-- Reason: dcStupidTeta is gotten by thinning the stupid theta from the tycon
@@ -1346,6 +1369,8 @@ dataConOrigResTy dc = dcOrigResTy dc
-- | The \"stupid theta\" of the 'DataCon', such as @data Eq a@ in:
--
-- > data Eq a => T a = ...
+--
+-- See @Note [The stupid context]@.
dataConStupidTheta :: DataCon -> ThetaType
dataConStupidTheta dc = dcStupidTheta dc