Opened 4 years ago

Closed 9 months ago

#10905 closed bug (fixed)

Incorrect number of parameters in "role" errors

Reported by: crockeea Owned by:
Priority: normal Milestone:
Component: Compiler Version: 7.10.2
Keywords: roles Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Incorrect warning at compile-time Test Case: ghci/scripts/T16030
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description (last modified by crockeea)

The following code produces the error:

import Data.Coerce
import Data.Functor.Trans.Tagged

toTT :: Tagged t [a] -> TaggedT t [] a
toTT = coerce
Couldn't match representation of type ‘[a]’
                             with that of ‘Data.Functor.Identity.Identity [a]’
    arising from trying to show that the representations of
      ‘Tagged t [a]’ and
      ‘TaggedT t [] a’ are the same
    Relevant role signatures:
      type role [] representational
      type role Data.Functor.Identity.Identity representational
      type role TaggedT nominal nominal phantom representational nominal
    The data constructor ‘Data.Functor.Identity.Identity’
      of newtype ‘Data.Functor.Identity.Identity’ is not in scope
    Relevant bindings include
      toTT :: Tagged t [a] -> TaggedT t [] a (bound at Main.hs:9:1)
    In the expression: coerce
    In an equation for ‘toTT’: toTT = coerce

First, kudos for correctly identifying the problem: I failed to import the Identity constructor. However, it seems that the report for the roles of the TaggedT type has too many parameters. It is defined in tagged-transformer https://hackage.haskell.org/package/tagged-transformer-0.8/docs/Data-Functor-Trans-Tagged.html as newtype TaggedT s m b = TagT { untagT :: m b }, but is listed with 5 roles.

I did try to move the definition of TaggedT/Tagged into my module so I didn't have to import the library, but when I did the error didn't show up: TaggedT was listed with the expected roles phantom representational nominal.

As a user, it wasn't clear to me why there are 5 roles listed for a type with 3 parameters, and I didn't know which roles I should be looking at to help me debug the coerce error. It's also not clear why using the library vs defining the types locally changed the behavior.

Change History (7)

comment:1 Changed 4 years ago by goldfire

I know what's going on here: GHC is reporting the role of kind parameters (which are all nominal). It shouldn't (unless you say -fprint-explicit-kinds, I think). Easy to fix.

But Simon removed this role-signature-reporting code. From TcErrors:

-- SLPJ Jun 15: I could not convince myself that these hints were really
-- useful.  Maybe they are, but I think we need more work to make them
-- actually helpful.

So the error is therefore absent in HEAD. But I thought those role signatures were helpful, and it sounds like @crockeea does too.

So, Simon, care to elaborate on why you removed these? Are there too many signatures reported?

comment:2 Changed 4 years ago by goldfire

Here's my test case. It produces the bad output in 7.10, but (as noted above) not in HEAD.

{-# LANGUAGE PolyKinds #-}

module T10905 where

import Data.Coerce
import Data.Functor.Identity

data TaggedT s m b = TagT { untagT :: m b }

foo :: TaggedT () [] Int -> TaggedT () [] (Identity Int)
foo = coerce

-- test the printing of TaggedT's role signature

comment:3 Changed 4 years ago by crockeea

Description: modified (diff)

I agree with your test case, and it appears that 5 roles are printed with both -fprint-explicit-kinds and with -fno-print-explicit-kinds, which seems odd (or is that merely because of PolyKinds?).

I suppose it makes sense to print the roles of the kinds if you have fprint-explicit-kinds enabled, but in my original test case (without fprint-explicit-kinds or PolyKinds), the kind roles should probably not be printed.

Last edited 4 years ago by crockeea (previous) (diff)

comment:4 Changed 4 years ago by simonpj

I don't think my reasoning was any deeper than the comment says. In the example in the Description, the roles are a distraction from the main point: the constructor isn't in scope. They just get in the way, and for most people will be mysterious and confusing.

Do we even want to see these role, or perhaps the roles of type constructors we have decomposed on the way to getting this error?

To put it another way, can you give an example of where they are useful?

comment:5 Changed 4 years ago by goldfire

If I say

import Data.Coerce

data G a where
  MkG :: G Int

newtype Age = MkAge Int

go :: G Age -> G Int
go = coerce

I get

    Couldn't match type ‘Int’ with ‘Age’
    arising from trying to show that the representations of
      ‘G Age’ and
      ‘G Int’ are the same
    Relevant role signatures: type role G nominal
    In the expression: coerce
    In an equation for ‘go’: go = coerce

That role signature looks helpful. Perhaps TcErrors could be more selective in deciding which signatures to include (though I'm not quite sure how to get this right), but I do think they're good to see.

comment:6 in reply to:  4 ; Changed 4 years ago by crockeea

To me this is a separate issue from the bug I reported. I have no problem with the fact that roles were reported for a missing constructor error. If anything I think the roles *help* in my example. The ticket as reported is really just about when the kind-roles should be printed, as that's the part I found confusing.

Replying to simonpj:

I don't think my reasoning was any deeper than the comment says. In the example in the Description, the roles are a distraction from the main point: the constructor isn't in scope. They just get in the way, and for most people will be mysterious and confusing.

Do we even want to see these role, or perhaps the roles of type constructors we have decomposed on the way to getting this error?

To put it another way, can you give an example of where they are useful?

comment:7 in reply to:  6 Changed 9 months ago by RyanGlScott

Resolution: fixed
Status: newclosed
Test Case: ghci/scripts/T16030

Replying to crockeea:

The ticket as reported is really just about when the kind-roles should be printed, as that's the part I found confusing.

In that case, this ticket is fixed. The T16030 test case provides a regression test for this, as it displays:

type role Foo1 phantom

When -fprint-explicit-kinds is disabled, and displays:

type role Foo1 nominal phantom

When -fprint-explicit-kinds is enabled.

Note: See TracTickets for help on using tickets.