
#11345: Template Haskell's handling of infix GADT constructors is broken -------------------------------------+------------------------------------- Reporter: RyanGlScott | Owner: RyanGlScott Type: bug | Status: new Priority: normal | Milestone: Component: Template Haskell | Version: 8.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by RyanGlScott): * owner: => RyanGlScott Comment: Actually, I realized that I was a little too careless in writing solutions 2 and 3—to the point where I skipped over an important detail: `InfixC` and `reifyFixity` serve distinct purposes. `InfixC` just tells you that a constructor was ''declared'' infix rather than prefix, i.e., it's the difference between {{{#!hs data T1 a = T1 a a }}} and {{{#!hs data T2 a = a `T2` a }}} But it tells you nothing about its actual fixity ''when used as an infix operator''. In fact, calling `reifyFixity` on both `'T1` and `'T2` would yield the same answer (`Fixity 9 InfixL`) since neither have an explicit fixity declaration. This is a minor distinction, but an important one. As a motivating example, when a datatype has a derived `Show` instance: * If one of its constructors is declared prefix, then the constructor will be shown before its fields, and the fields will always be shown with precedence 11. This is regardless of whether a fixity declaration is present. * If one of its constructors is declared infix, then the constructor will be shown between its two arguments, and the fields will shown according to the precedence in the fixity declaration plus 1 (if none is present, it defaults to 9+1). This is extremely important for GADTs because it is a special case. A GADT constructor is only considered to be declared infix if (a) it is an operator symbol, (b) it has two arguments, (c) it has a fixity declaration. Only then would a derived `Show` instance for a GADT constructor show the constructor between its arguments. For these reasons, proposals 2 and 3 above aren't quite accurate: * `InfixC` can't be subsumed under `NormalC` neatly because they discern a property of the datatype declaration that can't necessarily be gleaned from `reifyFixity`. Unless you were to add another field to `NormalC` to mark whether it was declared infix, that it—but that is another breaking change. * `InfixC` can't be subsumed under `RecC` at all, since if a constructor has records, it is automatically considered not to be declared infix. Considering all this, proposal 1 looks by far the most attractive in terms of ease of implementation and the least API changes (barring `GadtC`/`RecGadtC`). I think I'll go ahead and add an `InfixGadtC` constructor to `Con`. Any objections? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/11345#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler