scala/scala — pull request #3236 by xeno-by (2013-12-08 13:24:35+00:00)
Title: whitebox macros are now pretypechecked against WildcardType

Even though whitebox macros are supposed to be used to produce expansions
that refine advertised return types of their macro definitions, sometimes
those more precise types aren’t picked up by the typechecker.

It all started with Travis generating structural types with macros
and noticing that typer needs an extra nudge in order to make generated
members accessible to the outside world. I didn’t understand the mechanism
of the phenomenon back then, and after some time I just gave up.

Afterwards, when this issue had been brought up again in a different
StackOverflow question, we discussed it at reflection meeting, figured out
that typedBlock provides some special treatment to anonymous classes,
and it became clear that the first macro typecheck (the one that types
the expansion against the return type of the corresponding macro def)
is at fault here.

The thing is that if we have a block that stands for a desugard anonymous
class instantiation, and we typecheck it with expected type different from
WildcardType, then typer isn’t going to include decls of the anonymous class
in the resulting structural type: https://github.com/scala/scala/blob/master/src/compiler/scala/tools/nsc/typechecker/Typers.scala#L2350.
I tried to figure it out at https://groups.google.com/forum/#!topic/scala-internals/eXQt-BPm4i8,
but couldn’t dispel the mystery, so I let the bug lie dormant for a while.

But today I had a profound experience that finally tipped the scales
in favor of getting my hands dirty. It turns out that if we typecheck
an if, providing a suitable pt, then the resulting type of an if is going
to be that pt, even though the lub of the branch types might be more precise.
I’m sure that reasons for this behavior are also beyond my understanding,
so I decided to sidestep this problem.

Now expansions of whitebox macros are pre-typechecked against WildcardType
in order to get the most precise types possible. Then, everything goes
as usual: first we typecheck against the return type of the macro def,
and then we typecheck against the expected type of the expansion point.
Nothing is changed for blackbox macros, because they are restricted to
the return type of the macro def anyway.