diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2013-10-02 16:34:59 +0200 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2013-10-02 22:45:58 +0200 |
commit | d627672ec4a10861a659bfaacfaf86aa4b5b4e6e (patch) | |
tree | fd8e9af80295bac892e9e684ef4945d9761a3352 /src/compiler | |
parent | 8aae23ed47c4e38a465ff3373392484ca82473d1 (diff) | |
download | scala-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.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/reflect/macros/compiler/Resolvers.scala | 44 |
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 } |