How to practically enable `-Wmissing-import-lists`?

Edit:

On further thought I think I might be able to achieve the below using hlint importStyle directives, but that’s WIP. Will post results here. But I will leave the original post if people have a simpler way of working this out:

Original post:

So I’ve started working on a medium size Haskell codebase (high five figures in LOC) built using GHC and I’m working on making the warnings stricter to clean up the codebase and keep it clean. What I would like to do is enable -Wmissing-import-lists and naturally -Werror. I like to be able to at a glance be able to see where a function is coming from, and -Wmissing-import-lists achieves this, by requiring imports to be either qualified or explicit [1].

Here’s the issue. I have in the codebase a number of imports like the following:

import Prelude hiding (...)

-Wmissing-import-lists complains about this. Which I think is silly, because it doesn’t complain about an implicit Prelude import, despite the fact it has no import list, and import Prelude hiding (...) actually imports LESS than an implicit Prelude import.

This forces me to do explicit Prelude import lists anywhere where there’s a Prelude hiding clause.

Whilst I do think there’s too much in the Prelude, I think -Wmissing-import-lists forcing one to import Bool(True, False) just so one can hide something from the Prelude is a bit silly.

What I would probably ideally like to do is leave on -Wmissing-import-lists, also turn on NoImplicitPrelude, and write my own Prelude module (say MiniPrelude) that only exports a subset of Prelude, but allow that module, and only that module, to be imported without an import list.

I don’t really know what to do here. It seems like -Wmissing-import-lists, whilst a useful warning, is completely impractical unless one is okay with:

  1. Not being able to hide anything from the Prelude OR
  2. Having to explicitly list all Prelude imports, including things like Bool and ..

-Wmissing-import-lists even makes NoImplicitPrelude impractical, because wherever one uses their alternative Prelude one needs to import everything explicitly (when presumably one’s explicit prelude is carefully curated anyway).

I’ve even considered creating a CCP macro that spits out all the default imports I want from the Prelude in the form:

import Prelude (Bool(True, False), (.), ($), ...)

won’t work because then I’ll get -Wunused-import warnings everywhere.

Suppressing the warning by line would help, but apparently this isn’t possible, assuming this 21 year old ticket is still actually open.

Anyone have any idea how I can move forward here. I would really like to enable -Wmissing-import-lists, as it really helps me navigate and keep clean a currently messy codebase where the interdependencies are far from clear, but the resulting requiring of explicit Prelude exports and not allowing for a practical smaller custom Prelude is proving a very annoying showstopper.


  1. I know HLS when it’s working well can give you this information as well but it’s flaky and sometimes slow to load and adjust to refactors on large projects so I don’t want to rely on it. ↩︎

1 Like

You could use an implicit custom prelude:

1 Like

You could also use cabal’s mixins to replace prelude in another manner: 7. Package Description — Cabal 3.4.0.0 User's Guide

I considered this too, but don’t you then have to create two packages? I guess you could make a private sublibrary, but it seems like more work. Perhaps you can use mix-ins to rename the normal prelude to avoid having to use package imports in your custom prelude module.

1 Like

I’m not sure; unfortunately I don’t get to play with mixins like this too often, I just wanted to make sure that rewriting module names from packages like this wasn’t left to the wayside.

Can you use internal cabal library packages?

I tried this recently and it doesn’t work with “multiple home units” which is crucial for HLS to work smoothly in large projects, among other things.

1 Like

This does not quite address your concerns exactly, but it is related. I maintain a compiler plugin called om-plugin-imports, which dumps a canonical list of imports that you can copy-paste into your module that satisfies -Wmissing-import-lists. (see the readme)

It could be easily modified to create a plugin-based solution for exactly what you want. i.e. you wouldn’t actually use -Wmissing-importlists in your codebase. You would instead use a modified version of this plugin, which gave you the exact behavior you were looking for (a compile error when there are any missing imports except Prelude).

-Rick

2 Likes