Skip to content

-Wunused-pattern-binds is over-eager in a TH quote

Summary

If, in a TH quote, a pattern only binds variables inserted through splices, -Wunused-pattern-binds misses that fact and incorrectly decides that the pattern is useless.

Steps to reproduce

{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS -Wall #-}
module Thing (thing) where

import Language.Haskell.TH

thing :: Q ()
thing = do
  name <- newName "x"
  -- warning:
  _ <- [| let ($(pure (VarP name)), _) = (3.0, 4.0) in $(pure (VarE name)) |]
  -- warning:
  _ <- [| let ($(pure (VarP name))   ) =  3.0       in $(pure (VarE name)) |]
  -- no warning:
  _ <- [| let  $(pure (VarP name))     =  3.0       in $(pure (VarE name)) |]
  return ()

Output (GHC 9.4.1):

a.hs:11:15: warning: [-Wunused-pattern-binds]
    This pattern-binding binds no variables:
      ($(pure (VarP name)), _) = (3.0, 4.0)
   |
11 |   _ <- [| let ($(pure (VarP name)), _) = (3.0, 4.0) in $(pure (VarE name)) |]
   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

a.hs:13:15: warning: [-Wunused-pattern-binds]
    This pattern-binding binds no variables:
      ($(pure (VarP name))) = 3.0
   |
13 |   _ <- [| let ($(pure (VarP name))   ) =  3.0       in $(pure (VarE name)) |]
   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expected behavior

I would expect none of the patterns to give a -Wunused-pattern-binds warning. Furthermore, even if the warning is explicitly over-eager to avoid having to evaluate the splices in a quote before generating warnings for it, I would still expect the second and third example to behave the same: adding parentheses around a pattern ought not to change whether the pattern binds any variables!

Environment

  • GHC version used: 9.4.1

Optional:

  • Operating System: Arch Linux
  • System Architecture: x86_64
Edited by Tom Smeding
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information