scala/scala — pull request #3570 by soc (2014-02-21 20:29:08+00:00)
Title: Support def macros for constructors

Fixes an oversight that lasted from the times of 2.10.0-M3. Back then we
allowed defs to be a macro, but didn't think of constructors. Of course,
primary constructors can't be macros, because a class ought to have at
least one JVM-compatible ctor, but secondary constructors - why not?!

You might ask what's the point of turning constructors into macros.
After all, constructors have to expand into something that calls into
other constructors. Therefore even if one wants to hide a certain
constructor from the user by making that constructor private or protected,
it won't help because a public macro constructor would eventually have
to call that hidden constructor, producing a compilation error.

So we're stuck, right? Not really! Indeed, we can't expand into
a direct call to the hidden ctor, but what we can do is call a companion's
method and companions can see private constructors:

class C private (x: Int) {
def this(x: Int) = macro ??? // expands into `C(x)`
}

object C {
def apply(x: Int) = new C(x)
}

Now, you might point out that the signatures of the hidden ctor
and of the macro ctor are the same. So how do we disambiguate? Easy!
Let's wrap our state in a zero-overhead value class!

class CState(val x: Int) extends AnyVal

class C private (x: CState) {
def this(x: Int) = macro ??? // expands into `C(x)`
}

object C {
def apply(x: Int) = new C(new CState(x))
}