I have considered how to add this capability some in the past, it's something I'd also like to have. Collecting the type info in the module finalizer is an interesting idea! This may well be the cheapest way to get the info necessary for this usecase.
As far as I understand it, currently we're in the middle of typechecking when quasiquotes get run, so we don't yet have concrete. The types of reified variables may well depend upon the type of the expression generated by the quasi-quote. There seems to be a straightforward-ish way to resolve this - run typechecking twice. The first typechecking pass uses quasi-quotes substituted with stub versions of their output. For this example, it'd be (undefined :: IO double). To support this, we'd add a (Maybe ExpQ) field to QuasiQuoter, hopefully doing this in a way that preserves backwards compatibility (via pattern syns, or adding a new constructor to QuasiQuoter).
For consistency, we would want to ensure that the stub unifies with the expression that actually gets used. To enforce this, we'd typecheck something equivalent to
case True of
True -> ... -- generated code
False -> (undefined :: IO Double) -- stub
My particular use case is similar, in that it's related to FFI. What I want to do is have quasiquoters for typescript in GHCJS code. Since GHCJS already runs TH in node, we can actually load up the typescript compiler and do the typechecking directly at the quasi-quote location. For the first-pass stubs, we pretend like all the captured variables are the "Any" type, and ask typescript what it thinks the overall type is. For the second pass, we have the types of the anti-quotes, and so can typecheck the whole expression.
It'd also be really cool if we could generated code + typecheck anti-quotes during the first pass. This would make it possible to use anti-quotes which are more complicated than just a variable.