Reinstate unused variable warnings for typed Template Haskell
Motivation
In GHC.Rename.Splice there is the following Note:
Note [Free variables of typed splices]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Consider renaming this:
f = ...
h = ...$(thing "f")...
where the splice is a *typed* splice. The splice can expand into
literally anything, so when we do dependency analysis we must assume
that it might mention 'f'. So we simply treat all locally-defined
names as mentioned by any splice. This is terribly brutal, but I
don't see what else to do. For example, it'll mean that every
locally-defined thing will appear to be used, so no unused-binding
warnings. But if we miss the dependency, then we might typecheck 'h'
before 'f', and that will crash the type checker because 'f' isn't in
scope.
Currently, I'm not treating a splice as also mentioning every import,
which is a bit inconsistent -- but there are a lot of them. We might
thereby get some bogus unused-import warnings, but we won't crash the
type checker. Not very satisfactory really.
This Note was introduced in 22818ab0 for untyped splices and then repurposed for typed splices in 6a1c05f0 (my hypothesis for why untyped splices are excempt from this can be found under "Proposal").
The logic associated to this Note prevents -Wunused-{local-binds,matches,...}
from firing for code involving typed TH splices.
@kosmikus and me find that excessive; after all, typed TH code isn't supposed to do unhygienic shenenigans involving dyn
.
Proposal
Re-instate the warning by taking the free variables of the typed splice as the free variables of its expansion.
(Note that for untyped splices, we simply expand the splice before taking free variables, which is the proper solution. But at the moment we cannot expand typed splices in the renamer.)
Drawbacks
The free variables of the splice are not really a good proxy for the free variables of its expansion. That is the implicit message of the Note as well, which conservatively defaults to all free variables. In implementing the proposal, we lose a desirable property about typed TH:
- If I start with an untyped splice that is a bit unhygienic but works well,
- and manage to turn it into a typed splice, with just some uses of "unsafe" coerces to support the unhygienic bits,
- then my program should keep working; its semantics should stay unchanged. But with this proposal, we lose this property, because "unhygienic" is the very definition of "expansion uses more variables than original splice".
So the question is: Do we want to break unhygienic typed TH splices in order to get more warnings?
(An alternative would be to interleave renaming with type-checking in order to expand typed splices before computing its free variables. But we are quite a few refactorings away from achieving that.)