Failed OccName lookup in RnEnv with Template Haskell Hack

I have written a set of function that generates hsSyn data structures,
in particular HsExpr. I want run these functions at compile time, so
it can generate user code. I do this via Template Haskell and an ugly
hack in TH.
TcSplice.lhs expects an ExpQ monad as result for splice expressions.
I hesitate to rewrite my functions to generate a TH.Exp hierarchy
instead of a (HsExpr RdrName) hierarchy. The hack is to extend TH.Exp
with a new constructor InternalE (HsExpr RdrName) and to add a pattern
to hsSyn/Convert.lhs in
ctvl :: TH.Exp -> CvtM (LHsExpr RdrName)
cvt (InternalE expr) = return expr
This effectively percises the whole TH.Exp -> HsExpr conversion by
providing a Exp constructor with a HsExpr payload, and extending the
conversion to just unwrap this payload.
This enables me to hand HsExpr to the compiler via Template Haskell
via this elegant ugly hack:
foobar =
$(return (InternalE

| The problem is that the RdrNames carried in the HsExpr are not found | in the Renamer environment. To give you an example | | foobar = | $(return (InternalE (HsVar (mkUnqual varName | (mkFastString "myfoo"))))) | | which should in the overall result "foobar = myfoo" | | Running this gives me a "Not in scope" error but the myfoo variable is | obviously in the global environment as running this with | -ddump-rn-trace shows: Well that is indeed puzzling, but you are doing something quite tricky here. In TH, a TH splice uses only data types and functions declared in the TH library. But your splices use data types declared in GHC itself. I'm not quite sure how you make the compilation and linking stuff work out, but you certainly need to take great care that the TH splice code is uses the same data types, compiled in the same way, as the compiler it's linked with. Yes, it's hard to think about; I don't have it fully paged in myself. So the ice is thin. I can't account for the behaviour you are seeing -- but I can't see how to help you more. Perhaps do the HsVar and VarE thing in the *same* expression (in a pair, say), and confirm that they do generate the same HsExpr. Then start tracing the global envt lookup and its results. Simon | | test.hs:49:7: | Not in scope: `myfoo{v}' | Global envt is: | [cut] | myfoo{v}: main:MyAdd.myfoo{v rI9} imported from MyAdd at test.hs:13:20-24 | [cut] | | In contrast, the TH variant works without any flaws: | | $(return (VarE (mkName "myfoo"))) | | I assert that the VarE variant and the InternalE variant are converted | to exactly the same HsExpr by hsSyn/Convert.lhs. Using -ddump-slices | -dppr-debug shows that both splices generate "myfoo{v}". | | Using a few more hacks, I even made sure that the printed FastStrings | "myfoo" are equal in terms of "getKey# (getUnique str)", this pretty | much rules out a bug in UniqFM.hs. | | Does anyone (especially the developers that are intimate with TH and | HsSyn) know what could be the cause? I spent twelve fruitless hours | searching for the cause. | | Many thanks in advance, | --- | Fruhwirth Clemens - http://clemens.endorphin.org | for robots: sp4mtrap@endorphin.org | | | | _______________________________________________ | Glasgow-haskell-users mailing list | Glasgow-haskell-users@haskell.org | http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

At Fri, 3 Nov 2006 09:51:50 -0000,
"Simon Peyton-Jones"
| The problem is that the RdrNames carried in the HsExpr are not found | in the Renamer environment. To give you an example | | foobar = | $(return (InternalE (HsVar (mkUnqual varName | (mkFastString "myfoo"))))) | | which should in the overall result "foobar = myfoo" | | Running this gives me a "Not in scope" error but the myfoo variable is | obviously in the global environment as running this with | -ddump-rn-trace shows:
Well that is indeed puzzling, but you are doing something quite tricky here. In TH, a TH splice uses only data types and functions declared in the TH library. But your splices use data types declared in GHC itself. I'm not quite sure how you make the compilation and linking stuff work out, but you certainly need to take great care that the TH splice code is uses the same data types, compiled in the same way, as the compiler it's linked with. Yes, it's hard to think about; I don't have it fully paged in myself.
So the ice is thin. I can't account for the behaviour you are seeing -- but I can't see how to help you more. Perhaps do the HsVar and VarE thing in the *same* expression (in a pair, say), and confirm that they do generate the same HsExpr. Then start tracing the global envt lookup and its results.
Nothing is more effective in blocking you to find a solution than broken a test case. I was creating thousands of FastStrings in the template haskell splice, I was even abusing conversion routings of the TH->HsSyn converted to create fast strings for me, but all fast strings I could ever possible create in a splice, (even with the help of the TH converter) would have been interned in linker environment of the splice! This is different from the compiler's linker environment. The data structures created by the splice are relinked into the compiler environment, but the FastStrings are incorrectly relinked. That is, they are not interned in the compilers FastString symbol table. That's not the linkers fault of course, as it can not know that creating a FastString has a side effect that must be redone in the environment it's linking to. I solved this problem partially for HsVar by recreating the FastStrings it contains via back-and-forth conversion to String. Of course, this is very cumbersome if I would have to do this for every FastString/OccName/RdrName that is contained in an HsExpr tree. Writting the tree traversal code is the exhausting part in this case, but maybe generics will save us one day. However, the best fix in my case is to lift the HsExpr generating function into the compiler. All FastStrings are now created in the proper environment. Thanks for your suggestions, Simon. -- Fruhwirth Clemens - http://clemens.endorphin.org for robots: sp4mtrap@endorphin.org
participants (2)
-
Clemens Fruhwirth
-
Simon Peyton-Jones