#15637 closed bug (fixed)

Ambiguous type variables in GeneralisedNewtypeDeriving

Reported by: i-am-tom Owned by:
Priority: normal Milestone: 8.8.1
Component: Compiler Version: 8.4.3
Keywords: deriving Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case: deriving/should_compile/T15637
Blocked By: Blocking:
Related Tickets: Differential Rev(s): Phab:D5148
Wiki Page:

Description

When deriving the C instance in the following code:

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE GeneralisedNewtypeDeriving #-}
module Test where

class C a where f :: String

instance C () where f = "foo"

newtype T = T () deriving C

The following error occurs:

Test.hs:10:27: error:
    • Ambiguous type variable ‘a0’ arising from a use of ‘f’
      prevents the constraint ‘(C a0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘a0’ should be.
      These potential instances exist:
        instance C T -- Defined at Test.hs:10:27
        instance C () -- Defined at Test.hs:8:10
    • In the third argument of ‘GHC.Prim.coerce’, namely ‘f’
      In the expression: GHC.Prim.coerce @String @String f :: String
      In an equation for ‘f’:
          f = GHC.Prim.coerce @String @String f :: String
      When typechecking the code for ‘f’
        in a derived instance for ‘C T’:
        To see the code I am typechecking, use -ddump-deriv
   |
10 | newtype T = T () deriving C
   |                           ^

... and the following core is produced:

==================== Derived instances ====================
Derived class instances:
  instance Test.C Test.T where
    Test.f
      = GHC.Prim.coerce @GHC.Base.String @GHC.Base.String Test.f ::
          GHC.Base.String


Derived type family instances:

The problem seems to be that the a should have been set to () within the coerced instance. I've been working round this with a newtype X a = X String as the result value so that the a is present in the signature, but I think this is a bug; should a more specialised instance be generated? I hope this is enough of an explanation!

Thanks, Tom

Change History (6)

comment:1 Changed 12 months ago by simonpj

I suppose we could generate

Test.f = coerce @String @String (Test.f @())

that is, explicitly instantiating f. (Then maybe we could omit the second type arg to coerce; I'm not sure.)

Ryan?

comment:2 in reply to:  1 Changed 12 months ago by RyanGlScott

Replying to simonpj:

I suppose we could generate

Test.f = coerce @String @String (Test.f @())

that is, explicitly instantiating f.

That would make this particular example work, yes.

Note that this strategy would not support GND'ing every class under the sun that uses AllowAmbiguousTypes, such as the example from #14266, which uses an ambiguous type variable in a class context. But your idea would still be an improvement over the status quo, so I'm inclined to adopt it.

(Then maybe we could omit the second type arg to coerce; I'm not sure.)

No, I don't think adding these extra type applications would change the fact that you need the second type argument to coerce. The reason for that is explained in Note [GND and QuantifiedConstraints] here; the short of it is the we need the second type argument to coerce to support GND'ing classes like:

class C a where
  c :: Int -> forall b. b -> a

That fact doesn't change even in the presence of this ticket.

comment:3 Changed 12 months ago by RyanGlScott

Differential Rev(s): Phab:D5148
Status: newpatch

comment:4 Changed 12 months ago by RyanGlScott

Keywords: deriving added; GeneralisedNewtypeDeriving GeneralizedNewtypeDeriving removed

comment:5 Changed 12 months ago by Ryan Scott <ryan.gl.scott@…>

In 309438e9/ghc:

Fix #15637 by using VTA more in GND

Summary:
The code that GND was generating before could crumple over
if it derived an instance for a class with an ambiguous type variable
in the class head, such as the example in #15637. The solution is
straightforward: simply instantiate all variables bound by the class
head explicitly using visible type application, which will nip any
ambiguity in the bud.

Test Plan: make test TEST=T15637

Reviewers: bgamari, simonpj, goldfire

Reviewed By: simonpj

Subscribers: simonpj, rwbarton, carter

GHC Trac Issues: #15637

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

comment:6 Changed 12 months ago by RyanGlScott

Milestone: 8.6.18.8.1
Resolution: fixed
Status: patchclosed
Test Case: deriving/should_compile/T15637
Note: See TracTickets for help on using tickets.