Opened 3 years ago

Closed 3 years ago

Last modified 2 years ago

#12080 closed bug (fixed)

RebindableSyntax breaks deriving Ord

Reported by: afarmer Owned by: afarmer
Priority: normal Milestone: 8.0.2
Component: Compiler Version: 7.10.3
Keywords: deriving Cc: simonmar
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: #11396 Differential Rev(s): Phab:D2247
Wiki Page:

Description

The code generated with deriving (Ord) includes if-expressions which are subject to rebindable syntax:

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RebindableSyntax #-}

import Prelude

class IfThenElse a b where
  ifThenElse :: a -> b -> b -> b

instance IfThenElse Bool b where
  ifThenElse c x y = if c then x else y

data Foo = Foo | Bar | Baz deriving (Eq, Ord)

main :: IO ()
main = print $ Foo < Bar

when loaded into ghci (7.10, but not specific to that version):

[1 of 1] Compiling Main             ( Foo.hs, interpreted )

Foo.hs:13:42:
    Bad call to tagToEnum# at type a_aQy
      Specify the type by giving a type signature
      e.g. (tagToEnum# x) :: Bool
    In the expression: (GHC.Prim.tagToEnum# (a# GHC.Prim.<# b#))
    In the expression:
      if (GHC.Prim.tagToEnum# (a# GHC.Prim.<# b#)) then
          LT
      else
          if (GHC.Prim.tagToEnum# (a# GHC.Prim.==# b#)) then EQ else GT
    In a case alternative:
        b#
          -> if (GHC.Prim.tagToEnum# (a# GHC.Prim.<# b#)) then
                 LT
             else
                 if (GHC.Prim.tagToEnum# (a# GHC.Prim.==# b#)) then EQ else GT
    When typechecking the code for  ‘compare’
      in a derived instance for ‘Ord Foo’:
      To see the code I am typechecking, use -ddump-deriv

Foo.hs:13:42:
    No instance for (IfThenElse a0 Ordering)
      arising from an if statement
    The type variable ‘a0’ is ambiguous
    Note: there is a potential instance available:
      instance IfThenElse Bool b -- Defined at Foo.hs:10:10
    In the expression:
      if (GHC.Prim.tagToEnum# (a# GHC.Prim.<# b#)) then
          LT
      else
          if (GHC.Prim.tagToEnum# (a# GHC.Prim.==# b#)) then EQ else GT
    In a case alternative:
        b#
          -> if (GHC.Prim.tagToEnum# (a# GHC.Prim.<# b#)) then
                 LT
             else
                 if (GHC.Prim.tagToEnum# (a# GHC.Prim.==# b#)) then EQ else GT
    In the expression:
      case (Main.$con2tag_rjG b) of {
        b#
          -> if (GHC.Prim.tagToEnum# (a# GHC.Prim.<# b#)) then
                 LT
             else
                 if (GHC.Prim.tagToEnum# (a# GHC.Prim.==# b#)) then EQ else GT }
    When typechecking the code for  ‘compare’
      in a derived instance for ‘Ord Foo’:
      To see the code I am typechecking, use -ddump-deriv
Failed, modules loaded: none.

The if-expressions are generated by nlHsIf, which calls mkHsIf, which uses Just noSyntaxExpr as its first argument. I'm going to add a new function nlBuiltInHsIf which uses Nothing as the first argument, forcing the built-in if (according to Note [Rebindable if]), then use this new function when deriving stuff.

I'll post a patch soonish.

Change History (8)

comment:1 Changed 3 years ago by simonpj

Good catch. Shouldn't nlHsIf always use builtin syntax? Do we really need a new function?

comment:2 Changed 3 years ago by afarmer

Ah good point. I thought nlHsIf was used in more places. I'll just change it.

comment:3 Changed 3 years ago by simonpj

OK. Please comment nHsIf to point out the significance of the Nothing and explain why that choice is important.

comment:4 Changed 3 years ago by afarmer

Differential Rev(s): Phab:D2247

comment:5 Changed 3 years ago by Ben Gamari <ben@…>

In 527ed72/ghc:

Fix deriving Ord when RebindableSyntax is enabled

Deriving clauses (Ord especially) generated if-expressions with nlHsIf
which were subject to RebindableSyntax. This changes nlHsIf to generate
concrete if-expressions.

There was also an error about calling tagToEnum# at a polymorphic type,
which is not allowed. Fixing nlHsIf didn't fix this for some reason, so
I generated a type ascription around the call to tagToEnum#. Not sure
why the typechecker could not figure this out.

Test Plan: Added a test, ran validate.

Reviewers: simonpj, simonmar, austin, bgamari

Reviewed By: bgamari

Subscribers: thomie

Differential Revision: https://phabricator.haskell.org/D2247

GHC Trac Issues: #12080

comment:6 Changed 3 years ago by bgamari

Milestone: 8.0.2
Status: newmerge

comment:7 Changed 3 years ago by bgamari

Resolution: fixed
Status: mergeclosed
Last edited 3 years ago by bgamari (previous) (diff)

comment:8 Changed 2 years ago by RyanGlScott

Keywords: deriving added
Note: See TracTickets for help on using tickets.