summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2013-10-02 16:34:59 +0200
committerEugene Burmako <xeno.by@gmail.com>2013-10-02 22:45:58 +0200
commitd627672ec4a10861a659bfaacfaf86aa4b5b4e6e (patch)
treefd8e9af80295bac892e9e684ef4945d9761a3352 /src/compiler
parent8aae23ed47c4e38a465ff3373392484ca82473d1 (diff)
downloadscala-d627672ec4a10861a659bfaacfaf86aa4b5b4e6e.tar.gz
scala-d627672ec4a10861a659bfaacfaf86aa4b5b4e6e.tar.bz2
scala-d627672ec4a10861a659bfaacfaf86aa4b5b4e6e.zip
clearly establishes what macro bundles are
Previously it was enough to just extend scala.reflect.macros.Macro, which created some loopholes, but now scalac enforces that bundles: 1) Are static (not necessarily top-level, but just static) 2) Are traits (objects shouldn't be bundles anyway, and classes bring complications with their ctors which require special treatment in generated classes, so why support them if they don't bring anything new to the table?) 3) Are monomorphic (again, this brings unnecessary complications wrt auxiliary code generation, so I don't see merit in supporting polymorphic bundles, whatever that a polymorphic bundle could mean) 4) Don't provide concrete implementation for Macro.c (if they do then what is the point?)
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/reflect/macros/compiler/Errors.scala4
-rw-r--r--src/compiler/scala/reflect/macros/compiler/Resolvers.scala44
2 files changed, 29 insertions, 19 deletions
diff --git a/src/compiler/scala/reflect/macros/compiler/Errors.scala b/src/compiler/scala/reflect/macros/compiler/Errors.scala
index 6ec111cf7c..9b56e417e2 100644
--- a/src/compiler/scala/reflect/macros/compiler/Errors.scala
+++ b/src/compiler/scala/reflect/macros/compiler/Errors.scala
@@ -29,6 +29,10 @@ trait Errors extends Traces {
def MacroImplWrongNumberOfTypeArgumentsError() = implRefError(TypedApplyWrongNumberOfTpeParametersErrorMessage(macroImplRef))
+ def MacroBundleNonStaticError() = implRefError("macro bundles must be static")
+
+ def MacroBundleWrongShapeError() = implRefError("macro bundles must be monomorphic traits extending scala.reflect.macros.Macro and not implementing its `val c: Context` member")
+
// compatibility errors
// helpers
diff --git a/src/compiler/scala/reflect/macros/compiler/Resolvers.scala b/src/compiler/scala/reflect/macros/compiler/Resolvers.scala
index 46c4e24817..f950059be4 100644
--- a/src/compiler/scala/reflect/macros/compiler/Resolvers.scala
+++ b/src/compiler/scala/reflect/macros/compiler/Resolvers.scala
@@ -9,7 +9,7 @@ trait Resolvers {
import global._
import analyzer._
- import definitions._
+ import definitions.{EmptyPackageClass => _, _}
import treeInfo._
import gen._
@@ -33,7 +33,7 @@ trait Resolvers {
*/
lazy val macroImplRef: Tree = {
val (maybeBundleRef, methName, targs) = macroDdef.rhs match {
- case Applied(methRef @ Select(bundleRef @ RefTree(qual, bundleName), methName), targs, Nil) =>
+ case Applied(Select(Applied(RefTree(qual, bundleName), _, Nil), methName), targs, Nil) =>
(RefTree(qual, bundleName.toTypeName), methName, targs)
case Applied(Ident(methName), targs, Nil) =>
(Ident(context.owner.enclClass), methName, targs)
@@ -41,30 +41,36 @@ trait Resolvers {
(EmptyTree, TermName(""), Nil)
}
- val untypedImplRef = typer.silent(_.typedType(maybeBundleRef)) match {
- case SilentResultValue(result) if isMacroBundleType(result.tpe) =>
- val bundleClass = result.tpe.typeSymbol
- if (!bundleClass.owner.isPackageClass) abort(macroDef.pos, "macro bundles can only be defined as top-level classes or traits")
+ val untypedImplRef = typer.silent(_.typedTypeConstructor(maybeBundleRef)) match {
+ case SilentResultValue(result) if result.tpe.baseClasses.contains(MacroClass) =>
+ val bundleProto = result.tpe.typeSymbol
+ val bundlePkg = bundleProto.enclosingPackageClass
+ if (!isMacroBundleProtoType(bundleProto.tpe)) MacroBundleWrongShapeError()
+ if (!bundleProto.owner.isStaticOwner) MacroBundleNonStaticError()
- // synthesize the invoker, i.e. given a top-level `trait Foo extends Macro { def expand = ... } `
- // create a top-level definition `class FooInvoker(val c: Context) extends Foo` in MACRO_INVOKER_PACKAGE
- val invokerPid = gen.mkUnattributedRef(nme.MACRO_INVOKER_PACKAGE)
- val invokerName = TypeName(bundleClass.fullName.split('.').map(_.capitalize).mkString("") + nme.MACRO_INVOKER_SUFFIX)
- val invokerFullName = TypeName(s"$invokerPid.$invokerName")
- val existingInvoker = rootMirror.getClassIfDefined(invokerFullName)
- if (!currentRun.compiles(existingInvoker)) {
+ // synthesize the bundle, i.e. given a static `trait Foo extends Macro { def expand = ... } `
+ // create a top-level definition `class Foo$Bundle(val c: Context) extends Foo` in a package next to `Foo`
+ val bundlePid = gen.mkUnattributedRef(bundlePkg)
+ val bundlePrefix =
+ if (bundlePkg == EmptyPackageClass) bundleProto.fullName('$')
+ else bundleProto.fullName('$').substring(bundlePkg.fullName('$').length + 1)
+ val bundleName = TypeName(bundlePrefix + tpnme.MACRO_BUNDLE_SUFFIX)
+ val existingBundle = bundleProto.enclosingPackageClass.info.decl(bundleName)
+ if (!currentRun.compiles(existingBundle)) {
def mkContextValDef(flags: Long) = ValDef(Modifiers(flags), nme.c, TypeTree(ctxTpe), EmptyTree)
val contextField = mkContextValDef(PARAMACCESSOR)
val contextParam = mkContextValDef(PARAM | PARAMACCESSOR)
- val invokerCtor = DefDef(Modifiers(), nme.CONSTRUCTOR, Nil, List(List(contextParam)), TypeTree(), Block(List(pendingSuperCall), Literal(Constant(()))))
- val invoker = atPos(bundleClass.pos)(ClassDef(NoMods, invokerName, Nil, Template(List(Ident(bundleClass)), noSelfType, List(contextField, invokerCtor))))
- currentRun.compileLate(PackageDef(invokerPid, List(invoker)))
+ val bundleCtor = DefDef(Modifiers(), nme.CONSTRUCTOR, Nil, List(List(contextParam)), TypeTree(), Block(List(pendingSuperCall), Literal(Constant(()))))
+ val bundleParent = gen.mkAppliedTypeTree(Ident(bundleProto), bundleProto.typeParams.map(sym => Ident(sym.name)))
+ val bundleTemplate = Template(List(bundleParent), noSelfType, List(contextField, bundleCtor))
+ val bundle = atPos(bundleProto.pos)(ClassDef(NoMods, bundleName, bundleProto.typeParams.map(TypeDef(_)), bundleTemplate))
+ currentRun.compileLate(PackageDef(bundlePid, List(bundle)))
}
// synthesize the macro impl reference, which is going to look like:
- // `new Foo$invoker(???).expand` plus the optional type arguments
- val instanceOfInvoker = New(Select(invokerPid, invokerName), List(List(Select(scalaDot(nme.Predef), nme.???))))
- gen.mkTypeApply(Select(instanceOfInvoker, methName), targs)
+ // `new FooBundle(???).macroName` plus the optional type arguments
+ val bundleInstance = New(Select(bundlePid, bundleName), List(List(Ident(Predef_???))))
+ atPos(macroDdef.rhs.pos)(gen.mkTypeApply(Select(bundleInstance, methName), targs))
case _ =>
macroDdef.rhs
}