Permalink
Browse files

prohibits constructor overloading for macro bundles

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...
1 parent 3a689f5 commit e36888c3d953048483ccea9a95d5984b54ad6ebc @xeno-by xeno-by committed Jan 12, 2014
@@ -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
@@ -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 =>
@@ -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]]: _*)
}
@@ -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) =
@@ -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
@@ -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
@@ -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.