#2222: Template Haskell: reify returns incorrect types when ommiting type
signatures
------------------------------+---------------------------------------------
 Reporter:  fons              |          Owner:         
     Type:  bug               |         Status:  new    
 Priority:  normal            |      Milestone:         
Component:  Template Haskell  |        Version:  6.8.2  
 Severity:  major             |     Resolution:         
 Keywords:                    |     Difficulty:  Unknown
 Testcase:                    |   Architecture:  Unknown
       Os:  Multiple          |  
------------------------------+---------------------------------------------
Changes (by simonpj):

  * difficulty:  => Unknown

Comment:

 OK, so there are several things going on here.

 1.  For `a`, you are hitting the Monomorphism Restriction.  Since `a` is
 monomorphic, it gets type `t0`, where `t0` is a unification variable.
 Right at the very end of the module we might see `(f a)` where `f :: Int
 -> Int`, and then (but only then) we'd discover that `t0` is really `Int`.
 The difficulty is that reification (for local variables) can ask for the
 type of a variable before all the evidence is in. A much more direct
 examples would be
 {{{
   \x. ... $( ...reify 'x'... ) ...
 }}}
 The type of `x` may not be determined by the time the splice runs.  I
 can't see a way round this, except by making reification illegal for local
 variables, or perhaps for non-rigid ones, or something.

 2.  Although you wrote your definitions in order `b,c,d`, and they are not
 recursive, GHC is treating them as a mutually recursive group, and, as
 luck would have it, checks `d` first.  So the reification inside `d` see's
 `c`'s type before `c`'s right hand side has been examined, and we are back
 in situation (1).

 Why are they treated as mutually recursive?  Here's the comment from
 `RnSource`:
 {{{
 Note [Splices]
 ~~~~~~~~~~~~~~
 Consider
         f = ...
         h = ...$(thing "f")...

 The splice can expand into literally anything, so when we do dependency
 analysis we must assume that it might mention 'f'.  So we simply treat
 all locally-defined names as mentioned by any splice.  This is terribly
 brutal, but I don't see what else to do.  For example, it'll mean
 that every locally-defined thing will appear to be used, so no unused-
 binding
 warnings.  But if we miss the dependency, then we might typecheck
 'h' before 'f', and that will crash the type checker because 'f' isn't
 in scope.

 Currently, I'm not treating a splice as also mentioning every import,
 which is a bit inconsistent -- but there are a lot of them.  We might
 thereby get some bogus unused-import warnings, but we won't crash the
 type checker.  Not very satisfactory really.
 }}}
 Remember that TH allows dynamic binding!

 Again, I don't see a good way around this either.

 You might say that you expect TH splices to be run top-to-bottom, but what
 if one at the bottom is used further up:
 {{{
   f = ...g...
   ...
   h = $(bar 4)
   g = $(foo 3)
 }}}
 Now we have to run the splice for `g` before we can get a type for `g`;
 and we need a type for `g` before we can typecheck `f`.


 Anyway I hope that explains some of what is going on.  The real issues
 here are ones of design, rather than bugs of implementation.  Good design
 ideas would be very welcome -- the TH design is clearly warty in places.

 Simon

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/2222#comment:1>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
_______________________________________________
Glasgow-haskell-bugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to