achirkin / easytensor

Many-dimensional type-safe numeric ops
https://hackage.haskell.org/package/easytensor
BSD 3-Clause "New" or "Revised" License
46 stars 2 forks source link

Fixed PrimBytes for GHC 8.10 #28

Closed cjay closed 3 years ago

cjay commented 3 years ago

This fixes the following:

src/Numeric/PrimBytes.hs:311:55: error:
    • Cannot apply expression of type ‘Proxy# Symbol’
      to a visible type argument ‘name’
    • In the first argument of ‘byteFieldOffset’, namely
        ‘(proxy# @Symbol @name)’
      In the first argument of ‘I#’, namely
        ‘(byteFieldOffset (proxy# @Symbol @name) a)’
      In the first argument of ‘fromIntegral’, namely
        ‘(I# (byteFieldOffset (proxy# @Symbol @name) a))’
    |
311 | bFieldOffsetOf a = fromIntegral (I# (byteFieldOffset (proxy# @Symbol @name) a))
    |                                                       ^^^^^^^^^^^^^^^^^^^^

src/Numeric/PrimBytes.hs:501:34: error:
    • Could not deduce (KnownSymbol name0)
        arising from a use of ‘gbyteFieldOffset’
      from the context: GPrimBytes f
        bound by the instance declaration
        at src/Numeric/PrimBytes.hs:493:10-46
      or from: KnownSymbol name
        bound by the type signature for:
                   gbyteFieldOffset :: forall (name :: Symbol) (p :: k).
                                       KnownSymbol name =>
                                       Proxy# p
                                       -> Word# -> Int# -> Proxy# name -> M1 i c f p -> Int#
        at src/Numeric/PrimBytes.hs:501:5-20
      The type variable ‘name0’ is ambiguous
    • In the first argument of ‘coerce’, namely
        ‘(gbyteFieldOffset @f p)’
      In the expression: coerce (gbyteFieldOffset @f p)
      In an equation for ‘gbyteFieldOffset’:
          gbyteFieldOffset p = coerce (gbyteFieldOffset @f p)
    |
501 |     gbyteFieldOffset p = coerce (gbyteFieldOffset @f p)
    |                                  ^^^^^^^^^^^^^^^^^^^^^

I have no idea how (proxy# @Symbol @name) ever worked, proxy# seems to have only one type argument even in older versions.

achirkin commented 3 years ago

proxy# : forall k (a :: k). Proxy# a has two type variables: the displayed type a :: k and it's kind k. Not sure why we don't need it anymore. Perhaps, due to some changes to the variable visibility & type applications extension in the new version of ghc.

achirkin commented 3 years ago

Ugh, it seems there are a lot of warnings and errors in all 8.x versions of ghc now due to the changes in the type inference https://travis-ci.org/github/achirkin/easytensor/builds/763366711

I'll have a closer look on the weekend. Thanks for bringing this up!

cjay commented 3 years ago

This is very weird. It seems I was looking at proxy# from GHC.Prim (I now see this module has a disclaimer not to use it directly), where it has no explicit forall. However, GHC.Exts seems to just reexport the proxy# and Proxy# from there. Now I wonder where Haddock gets the explicit forall from. Even ghci seems to agree with Haddock:

Prelude GHC.Exts> :t +v proxy#
proxy# :: forall k (a :: k). Proxy# a

The +v should add {} around inferred type variables that are not available for visible type application, if I understand the documentation correctly. However:

Prelude GHC.Exts Data.Kind> :t proxy# @Int
proxy# @Int :: Proxy# Int
Prelude GHC.Exts Data.Kind> :t proxy# @Type @Int

<interactive>:1:1: error:
    • Cannot apply expression of type ‘Proxy# Type’
      to a visible type argument ‘Int’
    • In the expression: proxy# @Type @Int

Very confused.

cjay commented 3 years ago

I was wrong about thet :type +v, its only purpose is to show the actual type of the expression, while :type only shows the type of x in let x = <expr>. It also seems to always print explicit foralls for some reason. I think the {} for inferred type variables is supposed to always show up, but it only shows up with -fprint-explicit-foralls in 8.10.4. However, they do show up without this flag in 9.0.1. I suppose that is a bug of ghci that was fixed in the latest release.

So, the kind variable is actually inferred on 8.10.4:

Prelude GHC.Exts Data.Kind> :set -fprint-explicit-foralls
Prelude GHC.Exts Data.Kind> :t +v proxy#
proxy# :: forall {k} (a :: k). Proxy# a

It is not inferred on 8.8.4:

Prelude GHC.Exts> :t +v proxy#
proxy# :: forall k (a :: k). Proxy# a

Still not sure what made it change

cjay commented 3 years ago

I think it changed in this GHC fix, which changed the type of the proxy# primitive implementation, which apparently can be different from the type specified in the source file (this is the one for 8.8.4). Anyway, it seems like another case for CPP :|

achirkin commented 3 years ago

Interesting investigation :) I guess, it's enough to just not use type applications here

  bFieldOffsetOf a = fromIntegral (I# (byteFieldOffset (proxy# :: Proxy# name) a))

Also, I'm curious if it's possible to fix the other declaration without using extra variables for better inlining.

achirkin commented 3 years ago

So, indeed this fixes GHC 8.10, but there are so many warnings to be addressed, that it will take some time before I upload it to hackage. I've commited your changes slightly modified to compile under earlier versions, so I am closing this PR. Thanks for help!