GHC used to reject programs of this form:
newtype Age = MkAge Int
deriving Eq via Const Int a
That's because an earlier implementation of DerivingVia
would
generate the following instance:
instance Eq Age where
(==) = coerce @(Const Int a -> Const Int a -> Bool)
@(Age -> Age -> Bool)
(==)
Note that the a
in Const Int a
is not bound anywhere, which
causes all sorts of issues. I figured that no one would ever want to
write code like this anyway, so I simply banned "floating" via
type
variables like a
, checking for their presence in the aptly named
reportFloatingViaTvs
function.
reportFloatingViaTvs
ended up being implemented in a subtly
incorrect way, as #15831 (closed) demonstrates. Following counsel with the
sage of gold fire, I decided to abandon reportFloatingViaTvs
entirely and opt for a different approach that would accept
the instance above. This is because GHC now generates this instance
instead:
instance forall a. Eq Age where
(==) = coerce @(Const Int a -> Const Int a -> Bool)
@(Age -> Age -> Bool)
(==)
Notice that we now explicitly quantify the a
in
instance forall a. Eq Age
, so everything is peachy scoping-wise.
See Note [Floating `via` type variables]
in TcDeriv
for the full
scoop.
A pleasant benefit of this refactoring is that it made it much easier to catch the problem observed in #16181 (closed), so this patch fixes that issue too.
Fixes #15831 (closed). Fixes #16181 (closed).