Note [GND and ambiguity]

GHC/Tc/Deriv/Generate.hs:1936 compiler 2 tickets

We make an effort to make the code generated through GND be robust w.r.t.
ambiguous type variables. Here are a couple of examples to illustrate this:

* In this example (from #15637), the class-bound type variable `a` is ambiguous
  in the type of `f`:

    class C a where
      f :: String    -- f :: forall a. C a => String
    instance C ()
      where f = "foo"
    newtype T = T ()
      deriving C

  A naïve attempt and generating a C T instance would be:

    instance C T where
      f = coerce @String @String f

  This isn't going to typecheck, however, since GHC doesn't know what to
  instantiate the type variable `a` with in the call to `f` in the method body.
  (Note that `f :: forall a. String`!) To compensate for the possibility of
  ambiguity here, we explicitly instantiate `a` like so:

    instance C T where
      f = coerce @String @String (f @())

  All better now.

* In this example (adapted from #25148), the ambiguity arises from the `n`
  type variable bound by the type signature for `fact1`:

    class Facts a where
      fact1 :: forall n. Proxy a -> Dict (0 <= n)
    newtype T a = MkT a
      deriving newtype Facts

  When generating code for the derived `Facts` instance, we must use a type
  abstraction to bring `n` into scope over the type applications to `coerce`
  (see Note [Newtype-deriving instances] for more why this is needed). A first
  attempt at generating the instance would be:

    instance Facts a => Facts (T a) where
      fact1 @n = coerce @(Proxy    a  -> Dict (0 <= n))
                        @(Proxy (T a) -> Dict (0 <= n))
                        (fact1 @a)

  This still won't typecheck, however, as GHC doesn't know how to instantiate
  `n` in the call to `fact1 @a`. To compensate for the possibility of ambiguity
  here, we also visibly apply `n` in the call to `fact1` on the RHS:

    instance Facts a => Facts (T a) where
      fact1 @n = coerce @(Proxy    a  -> Dict (0 <= n))
                        @(Proxy (T a) -> Dict (0 <= n))
                        (fact1 @a @n) -- Note the @n here!

  This takes advantage of the fact that we *already* need to bring `n` into
  scope using a type abstraction, and so we are able to use it both for
  instantiating the call to `coerce` and instantiating the call to `fact1`.

  Note that we use this same type abstractions-based approach for resolving
  ambiguity in default methods, as described in Note [Default methods in
  instances] (Wrinkle: Ambiguous types from vanilla method type signatures) in
  GHC.Tc.TyCl.Instance.

References 1

Referenced by 4