Skip to content

`TypeError` thrown in standalone `via` deriving but not attached `via` deriving

Summary

A newtype for via deriving is provided that gives a TypeError, effectively banning the instance from use, but with a nice error message. We use this at work to prevent folks from running database operations in the "main" monad, and instead guide them towards runDB which handles transactions.

Steps to reproduce

{-# language DerivingVia #-}
{-# language DataKinds #-}
{-# language UndecidableInstances #-}
{-# language StandaloneDeriving #-}

module Woops where

import GHC.TypeLits

class C a where
    f :: a -> a

newtype Can'tBeC a = Can'tBeC a

instance ( TypeError ('Text "No")) => C (Can'tBeC a) where
    f = error "unreachable"

instance C Int where f = id

data Good = Good
    deriving C via (Can'tBeC Good)

data Bad = Bad

deriving via Can'tBeC Bad instance C Bad

With GHC 9.6.1, I get the following result:

λ ~/Projects/ghc-woops/ master* cabal build
Build profile: -w ghc-9.6.1 -O1
In order, the following will be built (use -v for more details):
 - ghc-woops-0.1.0.0 (lib) (file src/Woops.hs changed)
Preprocessing library for ghc-woops-0.1.0.0..
Building library for ghc-woops-0.1.0.0..
[2 of 2] Compiling Woops            ( src/Woops.hs, /home/matt/Projects/ghc-woops/dist-newstyle/build/x86_64-linux/ghc-9.6.1/ghc-woops-0.1.0.0/build/Woops.o, /
home/matt/Projects/ghc-woops/dist-newstyle/build/x86_64-linux/ghc-9.6.1/ghc-woops-0.1.0.0/build/Woops.dyn_o ) [Source file changed]

src/Woops.hs:25:1: error: [GHC-64725]
    • No
    • In the third argument of ‘ghc-prim-0.10.0:GHC.Prim.coerce’, namely
        ‘(f @(Can'tBeC Bad))’
      In the expression:
        ghc-prim-0.10.0:GHC.Prim.coerce
          @(Can'tBeC Bad -> Can'tBeC Bad) @(Bad -> Bad) (f @(Can'tBeC Bad))
      In an equation for ‘f’:
          f = ghc-prim-0.10.0:GHC.Prim.coerce
                @(Can'tBeC Bad -> Can'tBeC Bad) @(Bad -> Bad) (f @(Can'tBeC Bad))
      When typechecking the code for ‘f’
        in a derived instance for ‘C Bad’:
        To see the code I am typechecking, use -ddump-deriv
   |
25 | deriving via Can'tBeC Bad instance C Bad
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This is consistent going back to GHC 8.10.7.

Expected behavior

I expect that the StandaloneDeriving and attached deriving have the same behavior.

But, to be totally specific, I do want both instances to be accepted. The purpose of providing the TypeError instance here is to provide helpful error messages to folks that are using these, so instead of seeing No instance for C Bad they see You need to do X if you want to use C in the Bad type or similar.

Environment

  • GHC version used: 9.6.1, 9.4.5, 9.2.7, 8.10.7

Optional:

  • Operating System: Ubuntu
  • System Architecture: x86
Edited by parsonsmatt
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information