Skip to content

Seemingly unused qualified import affects method visibility

Here is a simple test case:

module MyLib where

class MyClass a where
  myMethod :: a -> a
module MyModule where
import MyLib (MyClass)
--import qualified MyLib as L

data Foo = Foo

instance MyClass Foo where
  -- error: ‘myMethod’ is not a (visible) method of class ‘MyClass’
  myMethod Foo = Foo

Since I have only imported MyClass and not its methods (that would be import MyLib (MyClass(..))), the error is correct, myMethod is not visible. But if I uncomment the import qualified MyLib as L line, the error disappears even though I do not use L anywhere. Writing L.myMethod Foo = Foo is not even legal!


I filed this under "confusing error message", so let me show you the conditions under which the above behaviour was confusing. We were using classy-prelude instead of Prelude, but we were not familiar with all the differences between the two preludes. We started with code like this, which did not compile:

{-# LANGUAGE NoImplicitPrelude #-}
module MyModule
import ClassyPrelude

data Foo a = Foo

instance Foldable Foo where
  -- 'foldMap' is not a (visible) method of class 'Foldable'
  foldMap = undefined

So we clarified that we meant Prelude.Foldable, in case ClassyFoldable.Foldable meant something different.

{-# LANGUAGE NoImplicitPrelude #-}
module MyModule
import ClassyPrelude
import qualified Prelude

data Foo a = Foo

instance Prelude.Foldable Foo where
  foldMap = undefined

This compiled, so we first thought that Prelude.Foldable and ClassyPrelude.Foldable were two different type classes, but we later discovered that ClassyPrelude.Foldable is a re-export of Prelude.Foldable. So the following means the same thing and also compiles:

{-# LANGUAGE NoImplicitPrelude #-}
module MyModule
import ClassyPrelude
import qualified Prelude

data Foo a = Foo

instance ClassyPrelude.Foldable Foo where
  foldMap = undefined

At this point, the qualified Prelude import doesn't seem used anywhere, so we thought it was safe to remove it:

{-# LANGUAGE NoImplicitPrelude #-}
import ClassyPrelude

data Foo a = Foo

instance ClassyPrelude.Foldable Foo where
  -- 'foldMap' is not a (visible) method of class 'Foldable'
  foldMap = undefined

But ClassyPrelude.foldMap is not the same as Prelude.foldMap, so this did not compile and it wasn't clear why.

One way to make this less confusing would be to allow qualified method names; this way, we would have tried both Prelude.foldMap = undefined and ClassyPrelude.foldMap = undefined, and we would have discovered the source of the problem.

Trac metadata
Trac field Value
Version 8.2.2
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information