From bc1071580203eda3f90433d930739f55a696a131 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sun, 5 May 2013 15:51:56 +0200 Subject: easy way of writing not implemented macros Even though it's easy to mark regular method bodies as stubs (using ???), there's no simple way of doing the same for macro methods. This patch fixes the inconvenience. --- .../tools/nsc/typechecker/ContextErrors.scala | 5 +++ .../scala/tools/nsc/typechecker/Macros.scala | 47 +++++++++++++--------- .../scala/tools/nsc/typechecker/Typers.scala | 2 +- 3 files changed, 33 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index e0dbe98780..b9cff5b2d3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -1307,6 +1307,11 @@ trait ContextErrors { throw MacroBodyTypecheckException // don't call fail, because we don't need IS_ERROR } + def MacroDefIsQmarkQmarkQmark() = { + macroLogVerbose("typecheck terminated unexpectedly: macro is ???") + throw MacroBodyTypecheckException + } + def MacroFeatureNotEnabled() = { macroLogVerbose("typecheck terminated unexpectedly: language.experimental.macros feature is not enabled") fail() diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 5ad568b1e6..816f977890 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -412,6 +412,9 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { // Phase II: typecheck the right-hand side of the macro def val typed = typecheckRhs(macroDdef.rhs) typed match { + case MacroImplReference(_, meth, _) if meth == Predef_??? => + bindMacroImpl(macroDef, typed) + MacroDefIsQmarkQmarkQmark() case MacroImplReference(owner, meth, targs) => if (!meth.isMethod) MacroDefInvalidBodyError() if (!meth.isPublic) MacroImplNotPublicError() @@ -521,26 +524,30 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { val methName = binding.methName macroLogVerbose(s"resolved implementation as $className.$methName") - // I don't use Scala reflection here, because it seems to interfere with JIT magic - // whenever you instantiate a mirror (and not do anything with in, just instantiate), performance drops by 15-20% - // I'm not sure what's the reason - for me it's pure voodoo - // upd. my latest experiments show that everything's okay - // it seems that in 2.10.1 we can easily switch to Scala reflection - try { - macroLogVerbose(s"loading implementation class: $className") - macroLogVerbose(s"classloader is: ${ReflectionUtils.show(macroClassloader)}") - val implObj = ReflectionUtils.staticSingletonInstance(macroClassloader, className) - // relies on the fact that macro impls cannot be overloaded - // so every methName can resolve to at maximum one method - val implMeths = implObj.getClass.getDeclaredMethods.find(_.getName == methName) - val implMeth = implMeths getOrElse { throw new NoSuchMethodException(s"$className.$methName") } - macroLogVerbose(s"successfully loaded macro impl as ($implObj, $implMeth)") - args => implMeth.invoke(implObj, ((args.c +: args.others) map (_.asInstanceOf[AnyRef])): _*) - } catch { - case ex: Exception => - macroLogVerbose(s"macro runtime failed to load: ${ex.toString}") - macroDef setFlag IS_ERROR - null + if (binding.className == Predef_???.owner.fullName.toString && binding.methName == Predef_???.name.encoded) { + args => throw new AbortMacroException(args.c.enclosingPosition, "macro implementation is missing") + } else { + // I don't use Scala reflection here, because it seems to interfere with JIT magic + // whenever you instantiate a mirror (and not do anything with in, just instantiate), performance drops by 15-20% + // I'm not sure what's the reason - for me it's pure voodoo + // upd. my latest experiments show that everything's okay + // it seems that in 2.10.1 we can easily switch to Scala reflection + try { + macroLogVerbose(s"loading implementation class: $className") + macroLogVerbose(s"classloader is: ${ReflectionUtils.show(macroClassloader)}") + val implObj = ReflectionUtils.staticSingletonInstance(macroClassloader, className) + // relies on the fact that macro impls cannot be overloaded + // so every methName can resolve to at maximum one method + val implMeths = implObj.getClass.getDeclaredMethods.find(_.getName == methName) + val implMeth = implMeths getOrElse { throw new NoSuchMethodException(s"$className.$methName") } + macroLogVerbose(s"successfully loaded macro impl as ($implObj, $implMeth)") + args => implMeth.invoke(implObj, ((args.c +: args.others) map (_.asInstanceOf[AnyRef])): _*) + } catch { + case ex: Exception => + macroLogVerbose(s"macro runtime failed to load: ${ex.toString}") + macroDef setFlag IS_ERROR + null + } } }) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index b89b570cd8..c59ef4ebda 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -5792,7 +5792,7 @@ trait Typers extends Modes with Adaptations with Tags { tree1 } - val isMacroBodyOkay = !tree.symbol.isErroneous && !(tree1 exists (_.isErroneous)) + val isMacroBodyOkay = !tree.symbol.isErroneous && !(tree1 exists (_.isErroneous)) && tree1 != EmptyTree val shouldInheritMacroImplReturnType = ddef.tpt.isEmpty if (isMacroBodyOkay && shouldInheritMacroImplReturnType) computeMacroDefTypeFromMacroImpl(ddef, tree1.symbol) else AnyClass.tpe } -- cgit v1.2.3