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 |