Skip to content

addTopDecls fails with typed Template Haskell

The following untyped Template Haskell works as expected:

--- AddTopDecls.hs ---
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes     #-}

module AddTopDecls where

import Language.Haskell.TH
import Language.Haskell.TH.Syntax

importDoubleToDouble :: String -> ExpQ
importDoubleToDouble fname = do
    n <- newName fname
    d <- forImpD CCall unsafe fname n [t|Double -> Double|]
    addTopDecls [d]
    varE n

--- Main.hs ---
{-# LANGUAGE TemplateHaskell #-}

module Main where

import AddTopDecls

main :: IO ()
main = do
    let sin' = $(importDoubleToDouble "sin")
        cos' = $(importDoubleToDouble "cos")
    --
    print (sin' 0)
    print (cos' pi)

However it fails if I convert to the equivalent typed version:

--- AddTopDecls.hs ---
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes     #-}

module AddTopDecls where

import Language.Haskell.TH
import Language.Haskell.TH.Syntax

importDoubleToDouble :: String -> Q (TExp (Double -> Double))
importDoubleToDouble fname = do
    n <- newName fname
    d <- forImpD CCall unsafe fname n [t|Double -> Double|]
    addTopDecls [d]
    unsafeTExpCoerce (varE n)

--- Main.hs ---
{-# LANGUAGE TemplateHaskell #-}

module Main where

import AddTopDecls

main :: IO ()
main = do
    let sin' = $$(importDoubleToDouble "sin")
        cos' = $$(importDoubleToDouble "cos")
    --
    print (sin' 0)
    print (cos' pi)

With the error:

> ghci Main.hs -ddump-splices
GHCi, version 8.2.0.20170404: http://www.haskell.org/ghc/  :? for help
[1 of 2] Compiling AddTopDecls      ( AddTopDecls.hs, interpreted )
[2 of 2] Compiling Main             ( Main.hs, interpreted )
Main.hs:9:19-44: Splicing expression
    importDoubleToDouble "sin" ======> sin_a4s2
Main.hs:1:1: Splicing top-level declarations added with addTopDecls
  ======>
    foreign import ccall unsafe "sin" Main.sin :: Double -> Double

Main.hs:9:19: error:
    • GHC internal error: ‘sin_a4s2’ is not in scope during type checking, but it passed the renamer
      tcl_env of environment: [a4dl :-> Identifier[sin'::t1, TopLevelLet [] False],
                               a4dm :-> Identifier[cos'::t1, TopLevelLet [] False],
                               r4cW :-> Identifier[main::IO (), TopLevelLet]]
    • In the expression: sin_a4s2
      In the result of the splice:
        $importDoubleToDouble "sin"
      To see what the splice expanded to, use -ddump-splices
      In the Template Haskell splice $$(importDoubleToDouble "sin")
  |
9 |     let sin' = $$(importDoubleToDouble "sin")
  |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^

Tested with 7.10.3, 8.0.2, and 8.2.0-rc1.

Unfortunately I can't use untyped TH in my real use case, so if you have any suggestions for a workaround that would also be great.

Trac metadata
Trac field Value
Version 8.2.1-rc1
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Template Haskell
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information