Skip to content

Typed holes' "valid substitutions" suggestions are oblivious to type class constraints

This example is taken from Chris Allen's blog post here:

pleaseShow :: Show a => Bool -> a -> Maybe String
pleaseShow False _ = Nothing
pleaseShow True a = Just (show _a)

On a recent GHC HEAD build, compiling this outputs:

Bug.hs:3:32: error:
    • Found hole: _a :: a0
      Where: ‘a0’ is an ambiguous type variable
      Or perhaps ‘_a’ is mis-spelled, or not in scope
    • In the first argument of ‘show’, namely ‘_a’
      In the first argument of ‘Just’, namely ‘(show _a)’
      In the expression: Just (show _a)
    • Relevant bindings include
        a :: a (bound at Bug.hs:3:17)
        pleaseShow :: Bool -> a -> Maybe String (bound at Bug.hs:2:1)
      Valid substitutions include
        (++) :: forall a. [a] -> [a] -> [a]
          (imported from ‘Prelude’ at Bug.hs:1:1
           (and originally defined in ‘GHC.Base’))
        fail :: forall (m :: * -> *). Monad m => forall a. String -> m a
          (imported from ‘Prelude’ at Bug.hs:1:1
           (and originally defined in ‘GHC.Base’))
        return :: forall (m :: * -> *). Monad m => forall a. a -> m a
          (imported from ‘Prelude’ at Bug.hs:1:1
           (and originally defined in ‘GHC.Base’))
        errorWithoutStackTrace :: forall (a :: TYPE r). [Char] -> a
          (imported from ‘Prelude’ at Bug.hs:1:1
           (and originally defined in ‘GHC.Err’))
        seq :: forall a b. a -> b -> b
          (imported from ‘Prelude’ at Bug.hs:1:1
           (and originally defined in ‘GHC.Prim’))
        (<>) :: forall a. Semigroup a => a -> a -> a
          (imported from ‘Prelude’ at Bug.hs:1:1
           (and originally defined in ‘GHC.Base’))
        (Some substitutions suppressed; use -fmax-valid-substitutions=N or -fno-max-valid-substitutions)
  |
3 | pleaseShow True a = Just (show _a)
  |                                ^^

There are a couple very unsavory things about this error:

  1. GHC makes no attempt to inform me that a0 is a Show instance! This is the primary gripe in the blog post, and it's worth emphasizing, since without the Show constraint, a0 just looks like any other random type variable. Speaking of which...
  2. The list of valid substitutions is incorrect! It suggests several things which have function types, such as (++) and fail, but (->) does not have a Show instance! This list ought to be pruned based on the current type class constraints in scope.
Trac metadata
Trac field Value
Version 8.3
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler (Type checker)
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
Edited by Ryan Scott
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information