Skip to content

Inaccessible code might be accessible with newtypes and Coercible

If I say

module A (Age, ageCo) where

import Data.Type.Coercion

newtype Age = MkAge Int

ageCo :: Coercion Age Int
ageCo = Coercion
{-# LANGUAGE FlexibleContexts #-}

module B where

import Data.Coerce
import A

foo :: Coercible Age Int => ()
foo = ()

I get

B.hs:8:8: error:
    Couldn't match representation of type ‘Age’ with that of ‘Int’
    Inaccessible code in
      the type signature for: foo :: Coercible Age Int => ()
    In the ambiguity check for the type signature for ‘foo’:
      foo :: Coercible Age Int => ()
    To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
    In the type signature for ‘foo’: foo :: Coercible Age Int => ()

I agree that module B can't directly prove Coercible Age Int. But ageCo is in scope which proves exactly this! So it is provable, albeit indirectly. GHC should not claim that the code is inaccessible.

Proposed fix: in canDecomposableTyConApp, only call canEqHardFailure for a representational equality when both tycons involved say True to isDistinctTyCon.

I'm happy to put the fix in, once someone seconds this idea. Getting this right has proved harder than I thought!

Edited by Richard Eisenberg
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information