[GHC] #9244: Compiler could warn about type variable shadowing, and hint about ScopedTypeVariables

#9244: Compiler could warn about type variable shadowing, and hint about ScopedTypeVariables -------------------------+------------------------------------------------- Reporter: | Owner: stusmith | Status: new Type: | Milestone: feature request | Version: 7.6.3 Priority: | Operating System: Unknown/Multiple normal | Type of failure: Incorrect warning at Component: | compile-time Compiler | Test Case: Keywords: | Blocking: Architecture: | Unknown/Multiple | Difficulty: | Unknown | Blocked By: | Related Tickets: | -------------------------+------------------------------------------------- GHC already warns about variable shadowing: {{{ timesTwoPlusOne x = timesTwo x + 1 where timesTwo x = x * 2 Warning: This binding for `x' shadows the existing binding bound at <location> }}} However the similar warning doesn't happen for type variables. {{{ tryMaybe :: IO a -> IO (Maybe a) tryMaybe action = do result <- (try action) :: IO (Either SomeException a) return $ case result of Left _ -> Nothing Right v -> Just v Couldn't match type `a' with `a1' `a' is a rigid type variable bound by the type signature for tryMaybe :: IO a -> IO (Maybe a) at types.hs:<line>:13 `a1' is a rigid type variable bound by an expression type signature: IO (Either SomeException a1) at types.hs:<line>:15 Expected type: IO a1 Actual type: IO a ... }}} Here, I thought that the 'a' in the function's type declaration was the same 'a' in the expression type declaration. However in Haskell 98, they are completely different variables. Suggestion: if a type variable is renamed by the compiler due to a clash with another type variable, issue a warning that the second shadows the first, and give a hint about using -XScopedTypeVariables and forall. Alternative suggestion: if an error is displayed, where the error contains a renamed type variable, issue a hint that the second shadows the first, and give a hint about using -XScopedTypeVariables and forall. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9244 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9244: Compiler could warn about type variable shadowing, and hint about ScopedTypeVariables -------------------------------------------------+------------------------- Reporter: stusmith | Owner: Type: feature request | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.6.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect warning at | Unknown/Multiple compile-time | Difficulty: Test Case: | Unknown Blocking: | Blocked By: | Related Tickets: -------------------------------------------------+------------------------- Comment (by simonpj): I think that's a fine idea. The easiest place to try this might be the renamer. At the moment the type signature for `tryMaybe` {{{ tryMaybe :: IO a -> IO (Maybe a) }}} does not bring `a` into scope in the body. You need `-XScopedTypeVariables`, ''and'' you need an explicit forall: {{{ tryMaybe :: forall a. IO a -> IO (Maybe a) }}} But it might be reasonable for the renamer to suggest that this is perhaps what you intended, when it comes across that `a` mentioned in {{{ (try action) :: IO (Either SomeException a) }}} Simon -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9244#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9244: Compiler could warn about type variable shadowing, and hint about ScopedTypeVariables -------------------------------------+------------------------------------- Reporter: stusmith | Owner: Type: feature | Status: new request | Milestone: Priority: normal | Version: 7.6.3 Component: Compiler | Keywords: Resolution: | Architecture: Unknown/Multiple Operating System: | Difficulty: Unknown Unknown/Multiple | Blocked By: Type of failure: Incorrect | Related Tickets: warning at compile-time | Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Description changed by thomie: Old description:
GHC already warns about variable shadowing:
{{{ timesTwoPlusOne x = timesTwo x + 1 where timesTwo x = x * 2
Warning: This binding for `x' shadows the existing binding bound at <location> }}}
However the similar warning doesn't happen for type variables.
{{{ tryMaybe :: IO a -> IO (Maybe a) tryMaybe action = do result <- (try action) :: IO (Either SomeException a) return $ case result of Left _ -> Nothing Right v -> Just v
Couldn't match type `a' with `a1' `a' is a rigid type variable bound by the type signature for tryMaybe :: IO a -> IO (Maybe a) at types.hs:<line>:13 `a1' is a rigid type variable bound by an expression type signature: IO (Either SomeException a1) at types.hs:<line>:15 Expected type: IO a1 Actual type: IO a ... }}}
Here, I thought that the 'a' in the function's type declaration was the same 'a' in the expression type declaration. However in Haskell 98, they are completely different variables.
Suggestion: if a type variable is renamed by the compiler due to a clash with another type variable, issue a warning that the second shadows the first, and give a hint about using -XScopedTypeVariables and forall.
Alternative suggestion: if an error is displayed, where the error contains a renamed type variable, issue a hint that the second shadows the first, and give a hint about using -XScopedTypeVariables and forall.
New description: GHC already warns about variable shadowing: {{{ $ cat test.hs module Test where timesTwoPlusOne x = timesTwo x + 1 where timesTwo x = x * 2 $ ghc -fwarn-name-shadowing test.hs ... Warning: This binding for `x' shadows the existing binding bound at <location> }}} However the similar warning doesn't happen for type variables. {{{ $ cat T9244.hs module T9244 where import Control.Exception tryMaybe :: IO a -> IO (Maybe a) tryMaybe action = do result <- (try action) :: IO (Either SomeException a) return $ case result of Left _ -> Nothing Right v -> Just v $ ghc -fwarn-name-shadowing T9244.hs ... Couldn't match type `a' with `a1' `a' is a rigid type variable bound by the type signature for tryMaybe :: IO a -> IO (Maybe a) at types.hs:<line>:13 `a1' is a rigid type variable bound by an expression type signature: IO (Either SomeException a1) at types.hs:<line>:15 Expected type: IO a1 Actual type: IO a ... }}} Here, I thought that the 'a' in the function's type declaration was the same 'a' in the expression type declaration. However in Haskell 98, they are completely different variables. Suggestion: if a type variable is renamed by the compiler due to a clash with another type variable, issue a warning that the second shadows the first, and give a hint about using -XScopedTypeVariables and forall. Alternative suggestion: if an error is displayed, where the error contains a renamed type variable, issue a hint that the second shadows the first, and give a hint about using -XScopedTypeVariables and forall. -- -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9244#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

An easy way of suggesting ScopedTypeVariables just came to mind: pretend
#9244: Compiler could warn about type variable shadowing, and hint about ScopedTypeVariables -------------------------------------+------------------------------------- Reporter: stusmith | Owner: Type: feature request | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 7.6.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect | Unknown/Multiple warning at compile-time | Test Case: Blocked By: | Blocking: Related Tickets: #1316, #3691, | Differential Rev(s): #11438 | Wiki Page: | -------------------------------------+------------------------------------- Changes (by thomie): * related: => #1316, #3691, #11438 * milestone: => 8.2.1 Comment: Also reported as #1316, #3691, #11438 and maybe others. @goldfire writes in ticket:11438#comment:1 (I'm moving the discussion here): the extension is always on. When looking up a type variable, if the extension is off but the variable would be in scope otherwise, suggest the extension, while returning a lookup failure (because the variable really isn't in scope!). Getting caught on ScopedTypeVariables is a fairly common occurrence in my experience, so I think it's worth putting in a bit of effort to do better here. (Even better would be to look for type variables in a signature that's missing a forall to suggest adding the forall, but that can be a separate task.) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9244#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

The ScopedTypeVariables extension is one of the few that doesn't recommend itself when it should be used.
I recognize that this may be hard to do, but here is a strawman
#9244: Compiler could warn about type variable shadowing, and hint about ScopedTypeVariables -------------------------------------+------------------------------------- Reporter: stusmith | Owner: Type: feature request | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 7.6.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect | Unknown/Multiple warning at compile-time | Test Case: Blocked By: | Blocking: Related Tickets: #1316, #3691, | Differential Rev(s): #11438,10581 | Wiki Page: | -------------------------------------+------------------------------------- Changes (by thomie): * related: #1316, #3691, #11438 => #1316, #3691, #11438,10581 Comment: @goldfire in #10581: proposal: Always behave as if ScopedTypeVariables is on at binding sites for type variables (in an annotation with forall). Then, at occurrences of type variables, check if the extension is on. If a type variable is in scope but the extension is off, remember that the user probably wants the extension, but then rename the type variable occurrence away from the in- scope one. If a type error ensues, we've remembered that the lack of ScopedTypeVariables may be to blame, and we recommend turning it on. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9244#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9244: Compiler could warn about type variable shadowing, and hint about ScopedTypeVariables -------------------------------------+------------------------------------- Reporter: stusmith | Owner: Type: feature request | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 7.6.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect | Unknown/Multiple warning at compile-time | Test Case: Blocked By: | Blocking: Related Tickets: #1316, #3691, | Differential Rev(s): #11438, #10581, #11539 | Wiki Page: | -------------------------------------+------------------------------------- Changes (by thomie): * related: #1316, #3691, #11438,10581 => #1316, #3691, #11438, #10581, #11539 Comment: #11539 requests to warn about missing forall when `-XScopedTypeVariables` is on. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9244#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9244: Compiler could warn about type variable shadowing, and hint about ScopedTypeVariables -------------------------------------+------------------------------------- Reporter: stusmith | Owner: Type: feature request | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 7.6.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect | Unknown/Multiple warning at compile-time | Test Case: Blocked By: | Blocking: Related Tickets: #1316, #3691, | Differential Rev(s): #11438, #10581, #11539 | Wiki Page: | -------------------------------------+------------------------------------- Changes (by kanetw): * cc: kanetw (added) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9244#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9244: Compiler could warn about type variable shadowing, and hint about ScopedTypeVariables -------------------------------------+------------------------------------- Reporter: stusmith | Owner: Type: feature request | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 7.6.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect | Unknown/Multiple warning at compile-time | Test Case: Blocked By: | Blocking: Related Tickets: #1316, #3691, | Differential Rev(s): #11438, #10581, #11539, #12716 | Wiki Page: | -------------------------------------+------------------------------------- Changes (by thomie): * related: #1316, #3691, #11438, #10581, #11539 => #1316, #3691, #11438, #10581, #11539, #12716 Comment: Another request for this feature: #12716. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9244#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9244: Compiler could warn about type variable shadowing, and hint about ScopedTypeVariables -------------------------------------+------------------------------------- Reporter: stusmith | Owner: Type: feature request | Status: new Priority: normal | Milestone: 8.4.1 Component: Compiler | Version: 7.6.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect | Unknown/Multiple warning at compile-time | Test Case: Blocked By: | Blocking: Related Tickets: #1316, #3691, | Differential Rev(s): #11438, #10581, #11539, #12716 | Wiki Page: | -------------------------------------+------------------------------------- Changes (by bgamari): * milestone: 8.2.1 => 8.4.1 Comment: It doesn't look like this will happen for 8.2. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9244#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9244: Compiler could warn about type variable shadowing, and hint about ScopedTypeVariables -------------------------------------+------------------------------------- Reporter: stusmith | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: 8.4.1 Component: Compiler | Version: 7.6.3 Resolution: | Keywords: | TypeErrorMessages Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect | Unknown/Multiple warning at compile-time | Test Case: Blocked By: | Blocking: Related Tickets: #1316, #3691, | Differential Rev(s): #11438, #10581, #11539, #12716 | Wiki Page: | -------------------------------------+------------------------------------- Changes (by simonpj): * keywords: => TypeErrorMessages -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9244#comment:9 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9244: Compiler could warn about type variable shadowing, and hint about ScopedTypeVariables -------------------------------------+------------------------------------- Reporter: stusmith | Owner: kanetw Type: feature request | Status: new Priority: normal | Milestone: 8.4.1 Component: Compiler | Version: 7.6.3 Resolution: | Keywords: | TypeErrorMessages Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect | Unknown/Multiple warning at compile-time | Test Case: Blocked By: | Blocking: Related Tickets: #1316, #3691, | Differential Rev(s): #11438, #10581, #11539, #12716 | Wiki Page: | -------------------------------------+------------------------------------- Changes (by kanetw): * owner: (none) => kanetw Comment: Working on this, but it seems pretty complicated. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9244#comment:10 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9244: Compiler could warn about type variable shadowing, and hint about ScopedTypeVariables -------------------------------------+------------------------------------- Reporter: stusmith | Owner: kanetw Type: feature request | Status: new Priority: normal | Milestone: 8.4.1 Component: Compiler | Version: 7.6.3 Resolution: | Keywords: | TypeErrorMessages Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect | Unknown/Multiple warning at compile-time | Test Case: Blocked By: | Blocking: Related Tickets: #1316, #3691, | Differential Rev(s): #11438, #10581, #11539, #12716 | Wiki Page: | -------------------------------------+------------------------------------- Comment (by simonpj): Before implementing much, it'd be good to write a specification of what you are trying to implement. I think it may be something like this: * When compiling without `-XScopedTypevariables`... * ...and type variable `a` ''would'' have been in scope if you were compiling ''with'' `-XScopedTypeVariables`... * ...and when you are about to add implicit quantification over `a` * ...then emit a warning Example {{{ f :: forall a. [a] -> [a] f = ....(let g :: a -> a g = ... in blah).... }}} With `-XScopedTypeVariables` the tyvar `a` would have been in scope in the body of `f`. Because it isn't in scope, we are going to implicitly quantify over `a` in the type signature for `g`, treating its signature as `g :: forall a. a->a`. That implicit quantification is what we want to warn about. Question: what if we had instead written {{{ f :: [a] -> [a] f = ....(let g :: a -> a g = ... in blah).... }}} Now, even with `-XScopedTypeVariables` the tyvar `a` would not be in scope. Do we want to warn then too? I guess so. Writing all this down, with a series of examples, would be helpful. I can see that it's a bit tricky to implement. We kind of need an extra set of tyvars that would be in scope if `-XScopedTypeVariables` was on, but aren't in scope because it isn't. Is it worth the fuss? Perhaps. Anyway, it'd be worth explaining your proposed implementation path before investing effort in implementing it. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9244#comment:11 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC