DuplicateRecordFields trigger false import warnings
Summary
This is a bit of a tricky bug, but there's a bad interaction between DuplicateRecordFields
and redundant import warnings.
Suppose you have a module:
module Lib where
data X = X { name :: String }
data Y = Y { age :: Int }
You might want to consume that module like this:
module Main where
import qualified Lib
import qualified Lib as X (X(..))
import qualified Lib as Y (Y(..))
main :: IO ()
main = do
let x = Lib.X { X.name = "hello" }
print x
print $ Lib.Y { Y.age = 3 }
This compiles just fine. But, suppose you add the {-# LANGUAGE DuplicateRecordFields #-}
pragma to the top of the file. It will now give you a warning:
/home/matt/Projects/dupfield/app/Main.hs:6:1: warning: [-Wunused-imports]
The qualified import of ‘Lib’ is redundant
except perhaps to import instances from ‘Lib’
To import instances alone, use: import Lib()
|
6 | import qualified Lib as X (X(..))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/home/matt/Projects/dupfield/app/Main.hs:7:1: warning: [-Wunused-imports]
The qualified import of ‘Lib’ is redundant
except perhaps to import instances from ‘Lib’
To import instances alone, use: import Lib()
|
7 | import qualified Lib as Y (Y(..))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If I delete the import, then I'll get compiler errors:
/home/matt/Projects/dupfield/app/Main.hs:11:21: error:
Not in scope: ‘X.name’
No module named ‘X’ is imported.
|
11 | let x = Lib.X { X.name = "hello" }
| ^^^^^^
/home/matt/Projects/dupfield/app/Main.hs:13:21: error:
Not in scope: ‘Y.age’
No module named ‘Y’ is imported.
|
13 | print $ Lib.Y { Y.age = 3 }
| ^^^^^
It appears that using the field label as a constructor does not trigger as a "use" if DuplicateRecordFields
is present in the module. Using it as an accessor counts, as well as using it as an update. It seems to only be creation that does not count.
Now, in the real Lib
in our codebase, we have many uses of DuplicateRecordFields
, but that's actually not necessary to trigger the bug, and so it's trimmed out. We use DuplicateRecordFields
enough that it's a default-extension in our cabal file.
Steps to reproduce
I made a reproduction here. To reproduce, stack build --fast --file-watch
. I made some comments in the app/Main.hs
module, feel free to play with commenting out various parts of the file to see behavior change.
Expected behavior
I expect that using a field label in record construction syntax would not warn that the identifier isn't used.
Environment
- GHC version used: 8.8.2
Optional:
- Operating System: Ubuntu 18.04
- Stackage LTS-15.0