[GHC] #15815: problem with splicing type into constraint

GHC ghc-devs at haskell.org
Sat Oct 27 22:15:55 UTC 2018


#15815: problem with splicing type into constraint
-------------------------------------+-------------------------------------
        Reporter:  int-e             |                Owner:  RyanGlScott
            Type:  bug               |               Status:  new
        Priority:  highest           |            Milestone:
       Component:  Template Haskell  |              Version:  8.6.1
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
 Type of failure:  GHC rejects       |  Unknown/Multiple
  valid program                      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:  #15760            |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------
Changes (by RyanGlScott):

 * cc: goldfire (added)
 * related:   => #15760


Comment:

 I believe I understand what is happening here. The problem is that when
 you roundtrip the following declaration through Template Haskell:

 {{{#!hs
 $([d| foo :: a ~ (Int -> Int) => a
       foo = undefined |])
 }}}

 Then all parentheses are stripped away when converting this to the GHC
 AST. This has important consequences when processing `foo`'s type
 signature. Before the offending commit (that I linked to in comment:2),
 the context of `foo`'s type signature would become:

 {{{
 HsEqTy a (HsOpTy Int (->) Int)
 }}}

 But after the offending commit, this becomes:

 {{{
 HsOpTy a (~) (HsOpTy Int (->) Int)
 }}}

 Upon first glance, these would appear to be identical. But as it turns
 out, `HsEqTy` actually had special treatment in the renamer, which means
 that it was renamed as though one had implicitly added `HsParTy`s around
 both of its arguments. On the other hand, when GHC renaming sequences of
 `HsOpTy`s (as in the second example), no such thing happens. In essence,
 that AST corresponds to:

 {{{#!hs
 a ~ Int -> Int
 }}}

 GHC thinks that should be parenthesized as:

 {{{#!hs
 (a ~ Int) -> Int
 }}}

 Which leads to the error that we see in this ticket.

 A quick-and-dirty way to fix this would be to change `cvtTypeKind` such
 that when we convert an `EqualityT`, we parenthesize `~`'s arguments if
 they aren't parenthesized. In other words, apply this patch:

 {{{#!diff
 diff --git a/compiler/hsSyn/Convert.hs b/compiler/hsSyn/Convert.hs
 index 8b12a78..74a6011 100644
 --- a/compiler/hsSyn/Convert.hs
 +++ b/compiler/hsSyn/Convert.hs
 @@ -1437,7 +1437,9 @@ cvtTypeKind ty_str ty

             EqualityT
               | [x',y'] <- tys' ->
 -                   returnL (HsOpTy noExt x' (noLoc eqTyCon_RDR) y')
 +                   let px = parenthesizeHsType opPrec x'
 +                       py = parenthesizeHsType opPrec y'
 +                   in returnL (HsOpTy noExt px (noLoc eqTyCon_RDR) py)
               | otherwise ->
                     mk_apps (HsTyVar noExt NotPromoted
                              (noLoc eqTyCon_RDR)) tys'
 }}}

 That makes the original program compile again, although it's just applying
 a bandage over a deeper wound—namely, that TH conversion strips away
 parentheses in the first place.

 goldfire, weren't you looking into fixing the parentheses issue in #15760?
 If so, perhaps your patch there would make for a more elegant fix for this
 ticket. On the other hand, if that still needs some work, I could whip up
 a stopgap solution now (based on the code above) so that this could be
 backported to a patch release if necessary.

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15815#comment:4>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list