Harrumph. In that second case, [d| infix 5 Foo |] produces an ExactRdrName for Foo that names a data constructor, not a type constructor, even when only the type constructor is in scope. Then, according to Note [dataTcOccs and Exact Names] in !RnEnv, the ExactRdrNames are trusted to have the right namespace and, so a naive fix for this bug fails the Foo case.
There are two possible ways forward that I see:
Don't trust ExactRdrNames in dataTcOccs. That is, when we have an Exact constructor name, also look for the type with same spelling.
Duplicate the dataTcOccs logic in !DsMeta.
I favor (2), because code that consumes the TH AST will want the TH.Names to have the right namespaces. It's really a bug that the fixity declaration above refers to a data constructor Foo.
Well, option (2) is infeasible. This is because desugaring a quoted fixity declaration produces TH.Names that do not have namespace information attached. This is a consequence of the fact that namespace information is available only with TH.Name's NameG constructor, which also has package and module information. Of course, when processing a quote, we have no idea what package/module the declaration will eventually end up in, so NameG is a non-starter. Thus, we have no namespace information here, and instead must be liberal when processing ExactRdrNames.
I suppose the Right Way to fix this is to add namespace information to TH's NameU and NameL constructors, but that probably has farther-reaching implications than need to be dealt with at this moment.
My solution (2) above is already somewhat implemented. Note that the quote has only 1 fixity declaration, but the desugared TH AST has 2! This was the essence of my idea (2) above.
GHC correctly notices the difference between the type Foo and the data constructor Foo in a quote.
All of the local names are NameUs.
These NameUs indeed become Exacts during splicing. But, the round trip from quote to TH AST to splice loses the namespace information, because NameUs do not carry namespace info. So, we either add namespace information to NameU or implement (1), above. Adding namespace info to NameU is slightly annoying, because fixity declarations are the only place that the namespace isn't apparent from a usage site.
Another possible solution is to add namespace info to the InfixD TH constructor. This is dissatisfactory because TH should model concrete syntax, and concrete syntax doesn't have a namespace marker there.
I'm happy to take suggestions, but my tendency is toward (1).
I don't think this was every really fixed properly and the wrinkle still exists in RnEnv. It seems that requiring namespace information on the InfixD constructor is the best way forward.