Adding import in GHC plugin shows unused-import
Summary
In a compiler plugin, I'm hooking into parsedActionResult
to modify the module being compiled. I'm adding an import and then using something from the import, but GHC still complains about unused-import.
Update 1: It seems like this happens because of generatedSrcSpan
. See Reddit thread for more details.
More generally, is there a way to use an identifier without needing to import it? I know with Template Haskell, if you use a ticked Name, it'll resolve successfully, even if it's not imported.
Original Reddit post: https://www.reddit.com/r/haskell/comments/vbwuzk/writing_a_ghc_plugin_autogenerated_import/
Steps to reproduce
Minimal repro:
module Plugin (plugin) where
import GHC.Hs
import GHC.Plugins
import qualified GHC.Types.Name.Occurrence as NameSpace
plugin :: Plugin
plugin =
defaultPlugin
{ parsedResultAction = \_ _ modl -> pure modl{hpm_module = update <$> hpm_module modl}
}
update :: HsModule -> HsModule
update modl =
modl
{ hsmodImports =
[ genLoc $ simpleImportDecl $ mkModuleName "Data.List"
]
, hsmodDecls =
[ genLoc . genFuncDecl (mkRdrName "intercalate2") [] $
genLoc $ HsVar NoExtField (mkRdrName "intercalate")
]
}
-- | Make simple function declaration of the form `<funcName> <funcArgs> = <funcBody>`
genFuncDecl :: Located RdrName -> [LPat GhcPs] -> LHsExpr GhcPs -> HsDecl GhcPs
genFuncDecl funcName funcArgs funcBody =
(\body -> ValD NoExtField $ FunBind NoExtField funcName body [])
. (\match -> MG NoExtField (genLoc [genLoc match]) Generated)
. Match NoExtField (FunRhs funcName Prefix NoSrcStrict) funcArgs
. (\grhs -> GRHSs NoExtField [genLoc grhs] funcWhere)
$ GRHS NoExtField [] funcBody
where
funcWhere = genLoc $ EmptyLocalBinds NoExtField
genLoc :: e -> Located e
genLoc = L generatedSrcSpan
mkRdrName :: String -> Located RdrName
mkRdrName = genLoc . mkRdrUnqual . mkOccName NameSpace.varName
{-# OPTIONS_GHC -fplugin=Plugin #-}
module Foo where
stack ghc --resolver=ghc-9.0 --package ghc -- Foo.hs -Wunused-imports -Werror -dynamic-too
Expected behavior
This should generate the equivalent of
module Foo where
import Data.List
intercalate2 = intercalate
So Data.List
is being used; indeed, when removing the import, the use of intercalate
fails. So Data.List
shouldn't be marked unused.
Environment
- GHC version used: 9.0 (I haven't tested with 9.2 because I'm using the 9.0 version of the GHC API, and I didn't want to update it to 9.2 yet)
Optional:
- Operating System:
- System Architecture: