Skip to content

GitLab

  • Menu
Projects Groups Snippets
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
  • GHC GHC
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 4,826
    • Issues 4,826
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 443
    • Merge requests 443
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Releases
  • Analytics
    • Analytics
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
    • Value stream
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #18850

Closed
Open
Created Oct 15, 2020 by Richard Eisenberg@raeDeveloper

Instance/given overlap trips up the ambiguity check

Thursday is a good day to abuse GHC. So I said this:

{-# LANGUAGE TypeFamilies, FlexibleInstances #-}

module Bug where

class IsBool bool
instance bool ~ Bool => IsBool bool

class C a
instance C Bool

f :: (C bool, IsBool bool) => ()
f = ()

To me, f's type is unambiguous: the IsBool bool constraint fixes the type variable bool to be Bool. But GHC says

/Users/rae/temp/Bug2.hs:11:6: error:
    • Could not deduce (C bool0)
      from the context: (C bool, IsBool bool)
        bound by the type signature for:
                   f :: forall bool. (C bool, IsBool bool) => ()
        at /Users/rae/temp/Bug2.hs:11:6-32
      The type variable ‘bool0’ is ambiguous
    • In the ambiguity check for ‘f’
      To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
      In the type signature: f :: (C bool, IsBool bool) => ()
   |
11 | f :: (C bool, IsBool bool) => ()
   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^

But maybe I'm wrong. Is the type really ambiguous? No. When I say

{-# LANGUAGE TypeFamilies, FlexibleInstances, AllowAmbiguousTypes #-}

module Bug where

class IsBool bool
instance bool ~ Bool => IsBool bool

class C a
instance C Bool

f :: (C bool, IsBool bool) => ()
f = ()

g = f

my program is accepted. I've added AllowAmbiguousTypes and the binding g = f. That binding is accepted -- no type applications or other funny business. This suggests that f's type is not actually ambiguous.

What's going on is an over-eager instance/given overlap; see Note [Instance and Given overlap] in GHC.Tc.Solver.Interact. That Note ends with

All of this is disgustingly delicate, so to discourage people from writing
simplifiable class givens, we warn about signatures that contain them;
see GHC.Tc.Validity Note [Simplifiable given constraints].

But I don't get the warning! Even in my second program, which is error-free. Hunting further into GHC.Tc.Validity, I find this code:

checkSimplifiableClassConstraint env dflags ctxt cls tys
  | not (wopt Opt_WarnSimplifiableClassConstraints dflags)
  = return ()
  | xopt LangExt.MonoLocalBinds dflags
  = return ()
  | ...

where the ... includes generating a warning. Of course, I do have -XMonoLocalBinds, as implied by -XTypeFamilies. What happens when I disable this (with an explicit -XNoMonoLocalBinds)?

/Users/rae/temp/Bug2.hs:11:6: warning: [-Wsimplifiable-class-constraints]
    • The constraint ‘IsBool bool’ matches
        instance (bool ~ Bool) => IsBool bool
          -- Defined at /Users/rae/temp/Bug2.hs:6:10
      This makes type inference for inner bindings fragile;
        either use MonoLocalBinds, or simplify it using the instance
    • In the type signature: f :: (C bool, IsBool bool) => ()
   |
11 | f :: (C bool, IsBool bool) => ()
   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^

Good. The warning fires.

My conclusions:

  1. My first program really ought to be accepted. The type is not ambiguous. I'm willing to concede this point to "disgustingly delicate", though, if we don't see an easy way to fix.
  2. It looks the warning should fire even when -XMonoLocalBinds is in effect. My program has no local generalization involved. How would users disable the warnings? By not writing a simplifiable Given.
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking