Opened 6 months ago

Last modified 6 weeks ago

#13512 new bug

GHC incorrectly warns that a variable used in a type application is unused

Reported by: RyanGlScott Owned by:
Priority: normal Milestone:
Component: Compiler (Type checker) Version: 8.0.1
Keywords: TypeApplications Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Incorrect error/warning at compile-time Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

This bug is reproducible on GHC 8.0.1, 8.0.2, 8.2, and HEAD.

{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeInType #-}

{-# OPTIONS_GHC -Wunused-foralls #-}
module Bug where

import Data.Proxy

proxy :: forall k (a :: k). Proxy a
proxy = Proxy

data SomeProxy where
  SomeProxy :: forall k (a :: k). Proxy a -> SomeProxy

someProxy :: forall k (a :: k). SomeProxy
someProxy = SomeProxy (proxy @k @a)
$ /opt/ghc/head/bin/ghci Bug.hs
GHCi, version 8.3.20170327: http://www.haskell.org/ghc/  :? for help
Loaded GHCi configuration from /home/rgscott/.ghci
[1 of 1] Compiling Bug              ( Bug.hs, interpreted )

Bug.hs:17:23: warning: [-Wunused-foralls]
    Unused quantified type variable ‘(a :: k)’
    In the type ‘forall k (a :: k). SomeProxy’
   |
17 | someProxy :: forall k (a :: k). SomeProxy
   |                       ^^^^^^^^
Ok, modules loaded: Bug.

But that a is used in proxy @k @a!

Change History (6)

comment:1 Changed 6 months ago by mpickering

Keywords: newcomer added

comment:2 Changed 6 months ago by simonpj

Ugh, yes, quite right. To fix this the renamer needs to propagate usages of type variables in a binding to their binding sites in the corresponding type signature. That is somewhat fiddly,and would require some refactoring in RnBinds.rnValBindsRHS.

Volunteers welcome!

Simon

comment:3 Changed 7 weeks ago by RyanGlScott

Similarly, using a scoped type variable in a type annotation doesn't count as a use:

{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeInType #-}

{-# OPTIONS_GHC -Wunused-foralls #-}
module Bug where

import Data.Proxy

proxy :: forall k (a :: k). Proxy a
proxy = Proxy

data SomeProxy where
  SomeProxy :: forall k (a :: k). Proxy a -> SomeProxy

someProxy :: forall k (a :: k). SomeProxy
someProxy = SomeProxy (proxy :: Proxy a)
$ /opt/ghc/8.2.1/bin/ghci Bug.hs
GHCi, version 8.2.1: http://www.haskell.org/ghc/  :? for help
Loaded GHCi configuration from /home/rgscott/.ghci
[1 of 1] Compiling Bug              ( Bug.hs, interpreted )

Bug.hs:17:23: warning: [-Wunused-foralls]
    Unused quantified type variable ‘(a :: k)’
    In the type ‘forall k (a :: k). SomeProxy’
   |
17 | someProxy :: forall k (a :: k). SomeProxy
   |                       ^^^^^^^^
Last edited 7 weeks ago by RyanGlScott (previous) (diff)

comment:4 Changed 7 weeks ago by RyanGlScott

Keywords: newcomer removed

By the way, at one point I looked into how one might fix this bug, but I didn't get very far. There's chicken-and-egg problem: the Unused quantified type variable analysis (and subsequent warning) are done entirely within bindLHsTyVarBndrs, which is called from rnValBindsLHS. However, to account for uses of type variables from type annotations or visible type applications, we'd need the results of rnValBindsRHS, but this must be run after rnValBindsLHS!

This leads me to believe that either:

  • This Unused quantified type variable check shouldn't belong in bindLHsTyVarBndrs.
  • We need to somehow make bindLHsTyVarBndrs aware of function RHSes as well for warning purposes.

Either way, I don't think is quite a newcomer bug :)

comment:5 Changed 6 weeks ago by ulysses4ever

@RyanGlScott How did you trace usage of bindLHsTyVarBndrs to rnValBindsLHS? I was only able to trace it to rnValBindsRHS as @simonpj told:

-- RnTypes.hs

warnUnusedForAll  ← 
bindLHsTyVarBndrs ← 
rnWcBody          ← 
rn_hs_sig_wc_type ← 
rnHsSigWcType     ← 

-- RnBinds.hs

renameSig         ← 
renameSigs        ← 
rnValBindsRHS
Last edited 6 weeks ago by ulysses4ever (previous) (diff)

comment:6 Changed 6 weeks ago by RyanGlScott

Ah, you're right, it is in fact rnValBindsRHS that handles the renaming of function type signatures, not rnValBindsLHS. My mistake.

But my point about there being a chicken-and-egg problem is still relevant, I believe. Here is the current definition of rnValBindsRHS:

rnValBindsRHS :: HsSigCtxt
              -> HsValBindsLR GhcRn GhcPs
              -> RnM (HsValBinds GhcRn, DefUses)
rnValBindsRHS ctxt (ValBindsIn mbinds sigs)
  = do { (sigs', sig_fvs) <- renameSigs ctxt sigs
       ; binds_w_dus <- mapBagM (rnLBind (mkSigTvFn sigs')) mbinds
       ; let !(anal_binds, anal_dus) = depAnalBinds binds_w_dus
       ; let patsyn_fvs = foldr (unionNameSet . psb_fvs) emptyNameSet $
                          getPatSynBinds anal_binds
             valbind'_dus = anal_dus `plusDU` usesOnly sig_fvs
                                     `plusDU` usesOnly patsyn_fvs
        ; return (ValBindsOut anal_binds sigs', valbind'_dus) }
rnValBindsRHS _ b = pprPanic "rnValBindsRHS" (ppr b)

Notice that the call to renameSigs (in which all Unused quantified type variable warnings are emitted) occurs before the call to rnLBind (which would handle, e.g., SomeProxy (proxy @k @a)). Moreover, this has to be the case, since the result of renameSigs is fed into rnLBind. This makes me believe that the Unused quantified type variable analysis needs to be moved out of bindLHsTyVarBndrs and somewhere that can take into account the results of rnValBindsRHS.

Note: See TracTickets for help on using tickets.