summaryrefslogtreecommitdiff
path: root/compiler/GHC/Rename/Module.hs
diff options
context:
space:
mode:
authorSimon Peyton Jones <simon.peytonjones@gmail.com>2023-03-02 11:26:17 +0000
committerSimon Peyton Jones <simon.peytonjones@gmail.com>2023-03-03 08:13:44 +0000
commit53c4b80add408db9f305b61a5fe3abe23b0a55e1 (patch)
tree5cdfaf6b8289500a3968a086d6f95df3c3cb4156 /compiler/GHC/Rename/Module.hs
parent2f97c86151d7eed115ddcbdee1842684aed63176 (diff)
downloadhaskell-wip/T22023.tar.gz
More fixes for `type data` declarationswip/T22023
This MR fixes #23022 and #23023. Specifically * Beef up Note [Type data declarations] in GHC.Rename.Module, to make invariant (I1) explicit, and to name the several wrinkles. And add references to these specific wrinkles. * Add a Lint check for invariant (I1) above. See GHC.Core.Lint.checkTypeDataConOcc * Disable the `caseRules` for dataToTag# for `type data` values. See Wrinkle (W2c) in the Note above. Fixes #23023. * Refine the assertion in dataConRepArgTys, so that it does not complain about the absence of a wrapper for a `type data` constructor Fixes #23022. Acked-by: Simon Peyton Jones <simon.peytonjones@gmail.com>
Diffstat (limited to 'compiler/GHC/Rename/Module.hs')
-rw-r--r--compiler/GHC/Rename/Module.hs120
1 files changed, 71 insertions, 49 deletions
diff --git a/compiler/GHC/Rename/Module.hs b/compiler/GHC/Rename/Module.hs
index 29a12299c4..5441d0419a 100644
--- a/compiler/GHC/Rename/Module.hs
+++ b/compiler/GHC/Rename/Module.hs
@@ -2073,9 +2073,79 @@ preceded by `type`, with the following restrictions:
(R5) There are no deriving clauses.
+The data constructors of a `type data` declaration obey the following
+Core invariant:
+
+(I1) The data constructors of a `type data` declaration may be mentioned in
+ /types/, but never in /terms/ or the /pattern of a case alternative/.
+
+Wrinkles:
+
+(W0) Wrappers. The data constructor of a `type data` declaration has a worker
+ (like every data constructor) but does /not/ have a wrapper. Wrappers
+ only make sense for value-level data constructors. Indeed, the worker Id
+ is never used (invariant (I1)), so it barely makes sense to talk about
+ the worker. A `type data` constructor only shows up in types, where it
+ appears as a TyCon, specifically a PromotedDataCon -- no Id in sight.
+
+ See `wrapped_reqd` in GHC.Types.Id.Make.mkDataConRep` for the place where
+ this check is implemented.
+
+ This specifically includes `type data` declarations implemented as GADTs,
+ such as this example from #22948:
+
+ type data T a where
+ A :: T Int
+ B :: T a
+
+ If `T` were an ordinary `data` declaration, then `A` would have a wrapper
+ to account for the GADT-like equality in its return type. Because `T` is
+ declared as a `type data` declaration, however, the wrapper is omitted.
+
+(W1) To prevent users from conjuring up `type data` values at the term level,
+ we disallow using the tagToEnum# function on a type headed by a `type
+ data` type. For instance, GHC will reject this code:
+
+ type data Letter = A | B | C
+
+ f :: Letter
+ f = tagToEnum# 0#
+
+ See `GHC.Tc.Gen.App.checkTagToEnum`, specifically `check_enumeration`.
+
+(W2) Although `type data` data constructors do not exist at the value level,
+ it is still possible to match on a value whose type is headed by a `type data`
+ type constructor, such as this example from #22964:
+
+ type data T a where
+ A :: T Int
+ B :: T a
+
+ f :: T a -> ()
+ f x = case x of {}
+
+ And yet we must guarantee invariant (I1). This has three consequences:
+
+ (W2a) During checking the coverage of `f`'s pattern matches, we treat `T`
+ as if it were an empty data type so that GHC does not warn the user
+ to match against `A` or `B`. (Otherwise, you end up with the bug
+ reported in #22964.) See GHC.HsToCore.Pmc.Solver.vanillaCompleteMatchTC.
+
+ (W2b) In `GHC.Core.Utils.refineDataAlt`, do /not/ fill in the DEFAULT case
+ with the data constructor, else (I1) is violated. See GHC.Core.Utils
+ Note [Refine DEFAULT case alternatives] Exception 2
+
+ (W2c) In `GHC.Core.Opt.ConstantFold.caseRules`, disable the rule for
+ `dataToTag#` in the case of `type data`. We do not want to transform
+ case dataToTag# x of t -> blah
+ into
+ case x of { A -> ...; B -> .. }
+ because again that conjures up the type-level-only data contructors
+ `A` and `B` in a pattern, violating (I1) (#23023).
+
The main parts of the implementation are:
-* (R0): The parser recognizes `type data` (but not `type newtype`).
+* The parser recognizes `type data` (but not `type newtype`); this ensures (R0).
* During the initial construction of the AST,
GHC.Parser.PostProcess.checkNewOrData sets the `Bool` argument of the
@@ -2134,54 +2204,6 @@ The main parts of the implementation are:
`type data` declarations. When these are converted back to Hs types
in a splice, the constructors are placed in the TcCls namespace.
-* A `type data` declaration _never_ generates wrappers for its data
- constructors, as they only make sense for value-level data constructors.
- See `wrapped_reqd` in GHC.Types.Id.Make.mkDataConRep` for the place where
- this check is implemented.
-
- This includes `type data` declarations implemented as GADTs, such as
- this example from #22948:
-
- type data T a where
- A :: T Int
- B :: T a
-
- If `T` were an ordinary `data` declaration, then `A` would have a wrapper
- to account for the GADT-like equality in its return type. Because `T` is
- declared as a `type data` declaration, however, the wrapper is omitted.
-
-* Although `type data` data constructors do not exist at the value level,
- it is still possible to match on a value whose type is headed by a `type data`
- type constructor, such as this example from #22964:
-
- type data T a where
- A :: T Int
- B :: T a
-
- f :: T a -> ()
- f x = case x of {}
-
- This has two consequences:
-
- * During checking the coverage of `f`'s pattern matches, we treat `T` as if it
- were an empty data type so that GHC does not warn the user to match against
- `A` or `B`. (Otherwise, you end up with the bug reported in #22964.)
- See GHC.HsToCore.Pmc.Solver.vanillaCompleteMatchTC.
-
- * In `GHC.Core.Utils.refineDataAlt`, do /not/ fill in the DEFAULT case with
- the data constructor. See
- Note [Refine DEFAULT case alternatives] Exception 2, in GHC.Core.Utils.
-
-* To prevent users from conjuring up `type data` values at the term level, we
- disallow using the tagToEnum# function on a type headed by a `type data`
- type. For instance, GHC will reject this code:
-
- type data Letter = A | B | C
-
- f :: Letter
- f = tagToEnum# 0#
-
- See `GHC.Tc.Gen.App.checkTagToEnum`, specifically `check_enumeration`.
-}
warnNoDerivStrat :: Maybe (LDerivStrategy GhcRn)