Skip to content

Commit

Permalink
prohibits constructor overloading for macro bundles
Browse files Browse the repository at this point in the history
As per Jason’s feedback, this commit handles overloaded constructors
in macro bundles. The backend now checks that we have a constructor of
a correct type. The frontend now prohibits multiple constructors altogether.
  • Loading branch information
xeno-by committed Jan 12, 2014
1 parent 3a689f5 commit e36888c
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 6 deletions.
2 changes: 1 addition & 1 deletion src/compiler/scala/reflect/macros/compiler/Errors.scala
Expand Up @@ -51,7 +51,7 @@ trait Errors extends Traces {

def MacroBundleNonStaticError() = bundleRefError("macro bundles must be static")

def MacroBundleWrongShapeError() = bundleRefError("macro bundles must be concrete classes having a single `val c: Context` parameter")
def MacroBundleWrongShapeError() = bundleRefError("macro bundles must be concrete classes having a single constructor with a `val c: Context` parameter")

// compatibility errors

Expand Down
Expand Up @@ -2,7 +2,9 @@ package scala.reflect.macros
package runtime

import scala.reflect.runtime.ReflectionUtils
import scala.reflect.macros.blackbox.{Context => ApiContext}
import scala.reflect.macros.blackbox.{Context => BlackboxContext}
import scala.reflect.macros.whitebox.{Context => WhiteboxContext}
import java.lang.reflect.{Constructor => jConstructor}

trait JavaReflectionRuntimes {
self: scala.tools.nsc.typechecker.Analyzer =>
Expand All @@ -19,8 +21,15 @@ trait JavaReflectionRuntimes {
macroLogVerbose(s"successfully loaded macro impl as ($implClass, $implMeth)")
args => {
val implObj =
if (isBundle) implClass.getConstructors().head.newInstance(args.c)
else ReflectionUtils.staticSingletonInstance(implClass)
if (isBundle) {
def isMacroContext(clazz: Class[_]) = clazz == classOf[BlackboxContext] || clazz == classOf[WhiteboxContext]
def isBundleCtor(ctor: jConstructor[_]) = ctor.getParameterTypes match {
case Array(param) if isMacroContext(param) => true
case _ => false
}
val Array(bundleCtor) = implClass.getConstructors.filter(isBundleCtor)
bundleCtor.newInstance(args.c)
} else ReflectionUtils.staticSingletonInstance(implClass)
val implArgs = if (isBundle) args.others else args.c +: args.others
implMeth.invoke(implObj, implArgs.asInstanceOf[Seq[AnyRef]]: _*)
}
Expand Down
3 changes: 2 additions & 1 deletion src/reflect/scala/reflect/internal/Definitions.scala
Expand Up @@ -616,8 +616,9 @@ trait Definitions extends api.StandardDefinitions {

def isMacroBundleType(tp: Type) = {
val isContextCompatible = macroBundleParamInfo(tp) != NoType
val hasSingleConstructor = !tp.declaration(nme.CONSTRUCTOR).isOverloaded
val nonAbstract = !tp.erasure.typeSymbol.isAbstractClass
isContextCompatible && nonAbstract
isContextCompatible && hasSingleConstructor && nonAbstract
}

def isBlackboxMacroBundleType(tp: Type) =
Expand Down
2 changes: 1 addition & 1 deletion test/files/neg/macro-bundle-abstract.check
@@ -1,4 +1,4 @@
macro-bundle-abstract.scala:10: error: macro bundles must be concrete classes having a single `val c: Context` parameter
macro-bundle-abstract.scala:10: error: macro bundles must be concrete classes having a single constructor with a `val c: Context` parameter
def foo = macro Bundle.impl
^
one error found
4 changes: 4 additions & 0 deletions test/files/neg/macro-bundle-overloaded.check
@@ -0,0 +1,4 @@
macro-bundle-overloaded.scala:11: error: macro bundles must be concrete classes having a single constructor with a `val c: Context` parameter
def foo = macro Bundle.impl
^
one error found
12 changes: 12 additions & 0 deletions test/files/neg/macro-bundle-overloaded.scala
@@ -0,0 +1,12 @@
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.{Context => BlackboxContext}
import scala.reflect.macros.whitebox.{Context => WhiteboxContext}

class Bundle(val c: BlackboxContext) {
def this(c: WhiteboxContext) = this(c: BlackboxContext)
def impl = ???
}

object Macros {
def foo = macro Bundle.impl
}

0 comments on commit e36888c

Please sign in to comment.