summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-01-19 22:08:11 -0800
committerPaul Phillips <paulp@improving.org>2012-01-19 22:08:11 -0800
commit7a7e049c205a0dda6666f158b1b37558bf214e90 (patch)
treeeab288d9916db45832b66de1e15a1fe774f316ce /src/compiler
parent14ef1090325c3b85aa8c2dd7911445ec7e934743 (diff)
parent35e676ded0f9bfd006a5f090841abdea3ff1759c (diff)
downloadscala-7a7e049c205a0dda6666f158b1b37558bf214e90.tar.gz
scala-7a7e049c205a0dda6666f158b1b37558bf214e90.tar.bz2
scala-7a7e049c205a0dda6666f158b1b37558bf214e90.zip
Merge remote-tracking branch 'kepler/topic/macros' into develop
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala1
-rw-r--r--src/compiler/scala/reflect/internal/StdNames.scala29
-rw-r--r--src/compiler/scala/reflect/runtime/JavaToScala.scala2
-rw-r--r--src/compiler/scala/reflect/runtime/Mirror.scala15
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala6
-rw-r--r--src/compiler/scala/tools/nsc/MacroContext.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala7
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala136
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala20
11 files changed, 183 insertions, 40 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala
index d38b62cbb4..f7e276fdab 100644
--- a/src/compiler/scala/reflect/internal/Definitions.scala
+++ b/src/compiler/scala/reflect/internal/Definitions.scala
@@ -393,6 +393,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
// scala.reflect
lazy val ReflectApiUniverse = getRequiredClass("scala.reflect.api.Universe")
+ lazy val ReflectMacroContext = getRequiredClass("scala.reflect.macro.Context")
lazy val ReflectRuntimeMirror = getRequiredModule("scala.reflect.runtime.Mirror")
def freeValueMethod = getMember(ReflectRuntimeMirror, nme.freeValue)
lazy val ReflectPackage = getPackageObject("scala.reflect")
diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala
index 507621ea42..aba00088f9 100644
--- a/src/compiler/scala/reflect/internal/StdNames.scala
+++ b/src/compiler/scala/reflect/internal/StdNames.scala
@@ -13,7 +13,7 @@ import annotation.switch
trait StdNames extends NameManglers { self: SymbolTable =>
def encode(str: String): TermName = newTermNameCached(NameTransformer.encode(str))
-
+
implicit def lowerTermNames(n: TermName): String = "" + n
// implicit def stringToTermName(s: String): TermName = newTermName(s)
@@ -182,7 +182,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
trait TermNames extends Keywords with CommonNames {
// Compiler internal names
val EXPAND_SEPARATOR_STRING = "$$"
-
+
val ANYNAME: NameType = "<anyname>"
val CONSTRUCTOR: NameType = "<init>"
val FAKE_LOCAL_THIS: NameType = "this$"
@@ -207,7 +207,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
final val Predef: NameType = "Predef"
final val ScalaRunTime: NameType = "ScalaRunTime"
final val Some: NameType = "Some"
-
+
val _1 : NameType = "_1"
val _2 : NameType = "_2"
val _3 : NameType = "_3"
@@ -301,6 +301,8 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val classOf: NameType = "classOf"
val clone_ : NameType = if (forMSIL) "MemberwiseClone" else "clone" // sn.OClone causes checkinit failure
val conforms: NameType = "conforms"
+ val context : NameType = "_context"
+ val contextImplicit : NameType = "$context"
val copy: NameType = "copy"
val delayedInit: NameType = "delayedInit"
val delayedInitArg: NameType = "delayedInit$body"
@@ -324,7 +326,6 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val freeValue : NameType = "freeValue"
val genericArrayOps: NameType = "genericArrayOps"
val get: NameType = "get"
- val glob : NameType = "glob"
val hasNext: NameType = "hasNext"
val hashCode_ : NameType = if (forMSIL) "GetHashCode" else "hashCode"
val hash_ : NameType = "hash"
@@ -430,7 +431,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val REFINE_CLASS_NAME: NameType = "<refinement>"
val ANON_CLASS_NAME: NameType = "$anon"
}
-
+
/** For fully qualified type names.
*/
object fulltpnme extends TypeNames {
@@ -450,11 +451,11 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val RuntimeNothing = toBinary(fulltpnme.RuntimeNothing).toTypeName
val RuntimeNull = toBinary(fulltpnme.RuntimeNull).toTypeName
}
-
+
object fullnme extends TermNames {
type NameType = TermName
protected implicit def createNameType(name: String): TermName = newTermNameCached(name)
-
+
val MirrorPackage: NameType = "scala.reflect.mirror"
}
@@ -516,7 +517,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
def moduleVarName(name: TermName): TermName =
newTermNameCached("" + name + MODULE_VAR_SUFFIX)
-
+
val ROOTPKG: TermName = "_root_"
/** Base strings from which synthetic names are derived. */
@@ -531,7 +532,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val INTERPRETER_VAR_PREFIX = "res"
val INTERPRETER_WRAPPER_SUFFIX = "$object"
val WHILE_PREFIX = "while$"
-
+
val EQEQ_LOCAL_VAR: TermName = newTermName(EQEQ_LOCAL_VAR_STRING)
def getCause = sn.GetCause
@@ -568,18 +569,18 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val UNARY_+ = encode("unary_+")
val UNARY_- = encode("unary_-")
val UNARY_! = encode("unary_!")
-
+
// Grouped here so Cleanup knows what tests to perform.
val CommonOpNames = Set[Name](OR, XOR, AND, EQ, NE)
val ConversionNames = Set[Name](toByte, toChar, toDouble, toFloat, toInt, toLong, toShort)
val BooleanOpNames = Set[Name](ZOR, ZAND, UNARY_!) ++ CommonOpNames
val NumberOpNames = (
- Set[Name](ADD, SUB, MUL, DIV, MOD, LSL, LSR, ASR, LT, LE, GE, GT)
- ++ Set(UNARY_+, UNARY_-, UNARY_!)
+ Set[Name](ADD, SUB, MUL, DIV, MOD, LSL, LSR, ASR, LT, LE, GE, GT)
+ ++ Set(UNARY_+, UNARY_-, UNARY_!)
++ ConversionNames
++ CommonOpNames
)
-
+
val add: NameType = "add"
val complement: NameType = "complement"
val divide: NameType = "divide"
@@ -670,7 +671,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
reflMethodName
)
def isReflectionCacheName(name: Name) = reflectionCacheNames exists (name startsWith _)
-
+
@switch def productAccessorName(j: Int): TermName = j match {
case 1 => nme._1
case 2 => nme._2
diff --git a/src/compiler/scala/reflect/runtime/JavaToScala.scala b/src/compiler/scala/reflect/runtime/JavaToScala.scala
index 61b03a9a29..bc5d616ae3 100644
--- a/src/compiler/scala/reflect/runtime/JavaToScala.scala
+++ b/src/compiler/scala/reflect/runtime/JavaToScala.scala
@@ -45,7 +45,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
def javaClass(path: String): jClass[_] =
javaClass(path, defaultReflectiveClassLoader())
def javaClass(path: String, classLoader: JClassLoader): jClass[_] =
- classLoader.loadClass(path)
+ Class.forName(path, true, classLoader)
/** Does `path` correspond to a Java class with that fully qualified name? */
def isJavaClass(path: String): Boolean =
diff --git a/src/compiler/scala/reflect/runtime/Mirror.scala b/src/compiler/scala/reflect/runtime/Mirror.scala
index 9490dc4ad7..09a4bbe198 100644
--- a/src/compiler/scala/reflect/runtime/Mirror.scala
+++ b/src/compiler/scala/reflect/runtime/Mirror.scala
@@ -12,7 +12,16 @@ class Mirror extends Universe with RuntimeTypes with TreeBuildUtil with ToolBoxe
import definitions._
- def classWithName(name: String): Symbol = classToScala(javaClass(name))
+ def classWithName(name: String): Symbol = {
+ val clazz = javaClass(name, defaultReflectiveClassLoader())
+ classToScala(clazz)
+ }
+
+ def getCompanionObject(clazz: Symbol): AnyRef = {
+ val singleton = ReflectionUtils.singletonInstance(clazz.fullName, defaultReflectiveClassLoader())
+ singleton
+ }
+
def getClass(obj: AnyRef): Symbol = classToScala(obj.getClass)
def getType(obj: AnyRef): Type = typeToScala(obj.getClass)
// to do add getClass/getType for instances of primitive types, probably like this:
@@ -32,7 +41,9 @@ class Mirror extends Universe with RuntimeTypes with TreeBuildUtil with ToolBoxe
case nme.update => return Array.set(receiver, args(0).asInstanceOf[Int], args(1))
}
}
- methodToJava(meth).invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*)
+
+ val jmeth = methodToJava(meth)
+ jmeth.invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*)
}
override def classToType(jclazz: java.lang.Class[_]): Type = typeToScala(jclazz)
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index c8db996de2..e805b4e75e 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -901,6 +901,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
/** Counts for certain classes of warnings during this run. */
var deprecationWarnings: List[(Position, String)] = Nil
var uncheckedWarnings: List[(Position, String)] = Nil
+
+ /** A flag whether macro expansions failed */
+ var macroExpansionFailed = false
/** Progress tracking. Measured in "progress units" which are 1 per
* compilation unit per phase completed.
@@ -1083,6 +1086,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
)
warn(deprecationWarnings.size, "deprecation", settings.deprecation)
warn(uncheckedWarnings.size, "unchecked", settings.unchecked)
+ if (macroExpansionFailed)
+ warning("some macros could not be expanded and code fell back to overridden methods;"+
+ "\nrecompiling with generated classfiles on the classpath might help.")
// todo: migrationWarnings
}
}
diff --git a/src/compiler/scala/tools/nsc/MacroContext.scala b/src/compiler/scala/tools/nsc/MacroContext.scala
index e739eade3a..72662291f8 100644
--- a/src/compiler/scala/tools/nsc/MacroContext.scala
+++ b/src/compiler/scala/tools/nsc/MacroContext.scala
@@ -2,7 +2,7 @@ package scala.tools.nsc
import symtab.Flags._
-trait MacroContext extends reflect.api.MacroContext { self: Global =>
+trait MacroContext extends reflect.macro.Context { self: Global =>
def captureVariable(vble: Symbol): Unit = vble setFlag CAPTURED
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index ce41bc456e..fe6dcc9138 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -2449,7 +2449,7 @@ self =>
else {
val nameOffset = in.offset
val name = ident()
- if (name == nme.macro_ && isIdent && settings.Xexperimental.value)
+ if (name == nme.macro_ && isIdent && settings.Xmacros.value)
funDefRest(start, in.offset, mods | Flags.MACRO, ident())
else
funDefRest(start, nameOffset, mods, name)
@@ -2480,6 +2480,9 @@ self =>
restype = scalaUnitConstr
blockExpr()
} else {
+ if (name == nme.macro_ && isIdent && in.token != EQUALS) {
+ warning("this syntactically invalid code resembles a macro definition. have you forgotten to enable -Xmacros?")
+ }
equalsExpr()
}
DefDef(newmods, name, tparams, vparamss, restype, rhs)
@@ -2539,7 +2542,7 @@ self =>
newLinesOpt()
atPos(start, in.offset) {
val name = identForType()
- if (name == nme.macro_.toTypeName && isIdent && settings.Xexperimental.value) {
+ if (name == nme.macro_.toTypeName && isIdent && settings.Xmacros.value) {
funDefRest(start, in.offset, mods | Flags.MACRO, identForType())
} else {
// @M! a type alias as well as an abstract type may declare type parameters
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index efd5323ce2..6806ca03ba 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -96,6 +96,7 @@ trait ScalaSettings extends AbsScalaSettings
val Xexperimental = BooleanSetting ("-Xexperimental", "Enable experimental extensions.") .
withPostSetHook(set => List(YmethodInfer, overrideObjects) foreach (_.value = set.value))
// YdepMethTpes, YvirtClasses,
+ val Xmacros = BooleanSetting ("-Xmacros", "Enable macros.")
/** Compatibility stubs for options whose value name did
* not previously match the option name.
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index b9264aae55..7f9e56a926 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -2,6 +2,8 @@ package scala.tools.nsc
package typechecker
import symtab.Flags._
+import scala.tools.nsc.util._
+import scala.reflect.ReflectionUtils
trait Macros { self: Analyzer =>
import global._
@@ -13,6 +15,20 @@ trait Macros { self: Analyzer =>
owner.info.decl(nme.macroMethodName(mac.name))
}
+ def macroArgs(tree: Tree): (List[List[Tree]]) = tree match {
+ case Apply(fn, args) =>
+ macroArgs(fn) :+ args
+ case TypeApply(fn, args) =>
+ macroArgs(fn) :+ args
+ case Select(qual, name) if !isStaticMacro(tree.symbol) =>
+ List(List(qual))
+ case _ =>
+ List(List())
+ }
+
+ private def isStaticMacro(mac: Symbol): Boolean =
+ mac.owner.isModuleClass
+
/**
* The definition of the method implementing a macro. Example:
* Say we have in a class C
@@ -33,25 +49,32 @@ trait Macros { self: Analyzer =>
*/
def macroMethDef(mdef: DefDef): Tree = {
def paramDef(name: Name, tpt: Tree) = ValDef(Modifiers(PARAM), name, tpt, EmptyTree)
- val universeType = TypeTree(ReflectApiUniverse.tpe)
- val globParamSec = List(paramDef(nme.glob, universeType))
- def globSelect(name: Name) = Select(Ident(nme.glob), name)
+ val contextType = TypeTree(ReflectMacroContext.tpe)
+ val globParamSec = List(paramDef(nme.context, contextType))
+ def globSelect(name: Name) = Select(Ident(nme.context), name)
def globTree = globSelect(newTypeName("Tree"))
def globType = globSelect(newTypeName("Type"))
- val thisParamSec = if (mdef.symbol.owner.isModuleClass) List() else List(paramDef(newTermName("_this"), globTree))
+ val thisParamSec = if (isStaticMacro(mdef.symbol)) List() else List(paramDef(newTermName("_this"), globTree))
def tparamInMacro(tdef: TypeDef) = paramDef(tdef.name.toTermName, globType)
- def vparamInMacro(vdef: ValDef): ValDef = paramDef(vdef.name, globTree)
+ def vparamInMacro(vdef: ValDef): ValDef = paramDef(vdef.name, vdef.tpt match {
+ case tpt @ AppliedTypeTree(hk, _) if treeInfo.isRepeatedParamType(tpt) => AppliedTypeTree(hk, List(globTree))
+ case _ => globTree
+ })
def wrapImplicit(tree: Tree) = atPos(tree.pos) {
- Block(List(ValDef(Modifiers(IMPLICIT), newTermName("$" + nme.glob), universeType, Ident(nme.glob))), tree)
+ // implicit hasn't proven useful so far, so I'm disabling it
+ //val implicitDecl = ValDef(Modifiers(IMPLICIT), nme.contextImplicit, SingletonTypeTree(Ident(nme.context)), Ident(nme.context))
+ val importGlob = Import(Ident(nme.context), List(ImportSelector(nme.WILDCARD, -1, null, -1)))
+ Block(List(importGlob), tree)
}
+ var formals = (mdef.vparamss map (_ map vparamInMacro))
+ if (mdef.tparams.nonEmpty) formals = (mdef.tparams map tparamInMacro) :: formals
atPos(mdef.pos) {
new DefDef( // can't call DefDef here; need to find out why
- mods = mdef.mods &~ MACRO,
+ mods = mdef.mods &~ MACRO &~ OVERRIDE,
name = nme.macroMethodName(mdef.name),
tparams = List(),
- vparamss = globParamSec :: thisParamSec :: (mdef.tparams map tparamInMacro) ::
- (mdef.vparamss map (_ map vparamInMacro)),
+ vparamss = globParamSec :: thisParamSec :: formals,
tpt = globTree,
wrapImplicit(mdef.rhs))
}
@@ -59,11 +82,98 @@ trait Macros { self: Analyzer =>
def addMacroMethods(templ: Template, namer: Namer): Unit = {
for (ddef @ DefDef(mods, _, _, _, _, _) <- templ.body if mods hasFlag MACRO) {
- val sym = namer.enterSyntheticSym(util.trace("macro def: ")(macroMethDef(ddef)))
- println("added to "+namer.context.owner.enclClass+": "+sym)
+ val trace = scala.tools.nsc.util.trace when settings.debug.value
+ val sym = namer.enterSyntheticSym(trace("macro def: ")(macroMethDef(ddef)))
+ trace("added to "+namer.context.owner.enclClass+": ")(sym)
}
}
- def macroExpand(tree: Tree): Tree = ???
+ lazy val mirror = new scala.reflect.runtime.Mirror {
+ lazy val libraryClassLoader = {
+ val classpath = global.classPath.asURLs
+ ScalaClassLoader.fromURLs(classpath, self.getClass.getClassLoader)
+ }
+
+ override def defaultReflectiveClassLoader() = libraryClassLoader
+ }
+
+ class MacroExpandError(val msg: String) extends Exception(msg)
-} \ No newline at end of file
+ /** Return optionally address of companion object and implementation method symbol
+ * of given macro; or None if implementation classfile cannot be loaded or does
+ * not contain the macro implementation.
+ */
+ def macroImpl(mac: Symbol): Option[(AnyRef, mirror.Symbol)] = {
+ try {
+ val mmeth = macroMeth(mac)
+ if (mmeth == NoSymbol) None
+ else {
+ val receiverClass: mirror.Symbol = mirror.classWithName(mmeth.owner.fullName)
+ val receiverObj = receiverClass.companionModule
+ if (receiverObj == NoSymbol) None
+ else {
+ val receiver = mirror.getCompanionObject(receiverClass)
+ val rmeth = receiverObj.info.member(mirror.newTermName(mmeth.name.toString))
+ Some((receiver, rmeth))
+ }
+ }
+ } catch {
+ case ex: ClassNotFoundException =>
+ None
+ }
+ }
+
+ /** Return result of macro expansion.
+ * Or, if that fails, and the macro overrides a method return
+ * tree that calls this method instead of the macro.
+ */
+ def macroExpand(tree: Tree): Any = {
+ val macroDef = tree.symbol
+ macroImpl(macroDef) match {
+ case Some((receiver, rmeth)) =>
+ val argss = List(global) :: macroArgs(tree)
+ val paramss = macroMeth(macroDef).paramss
+ val rawArgss = for ((as, ps) <- argss zip paramss) yield {
+ if (isVarArgsList(ps)) as.take(ps.length - 1) :+ as.drop(ps.length - 1)
+ else as
+ }
+ val rawArgs: Seq[Any] = rawArgss.flatten
+ try {
+ mirror.invoke(receiver, rmeth, rawArgs: _*)
+ } catch {
+ case ex =>
+ val realex = ReflectionUtils.unwrapThrowable(ex)
+ val stacktrace = new java.io.StringWriter()
+ realex.printStackTrace(new java.io.PrintWriter(stacktrace))
+ val msg = System.getProperty("line.separator") + stacktrace
+ throw new MacroExpandError("exception during macro expansion: " + msg)
+ }
+ case None =>
+ val trace = scala.tools.nsc.util.trace when settings.debug.value
+ def notFound() = throw new MacroExpandError("macro implementation not found: " + macroDef.name)
+ def fallBackToOverridden(tree: Tree): Tree = {
+ tree match {
+ case Select(qual, name) if (macroDef.isMacro) =>
+ macroDef.allOverriddenSymbols match {
+ case first :: others =>
+ return Select(qual, name) setPos tree.pos setSymbol first
+ case _ =>
+ trace("macro is not overridden: ")(tree)
+ notFound()
+ }
+ case Apply(fn, args) =>
+ Apply(fallBackToOverridden(fn), args) setPos tree.pos
+ case TypeApply(fn, args) =>
+ TypeApply(fallBackToOverridden(fn), args) setPos tree.pos
+ case _ =>
+ trace("unexpected tree in fallback: ")(tree)
+ notFound()
+ }
+ }
+ val tree1 = fallBackToOverridden(tree)
+ trace("falling back to ")(tree1)
+ currentRun.macroExpansionFailed = true
+ tree1
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 354b8caaa3..e04d89047b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -842,10 +842,10 @@ trait Namers extends MethodSynthesis {
Namers.this.classOfModuleClass get clazz foreach { cdefRef =>
val cdef = cdefRef()
if (cdef.mods.isCase) addApplyUnapply(cdef, templateNamer)
- addMacroMethods(cdef.impl, templateNamer)
+ if (settings.Xmacros.value) addMacroMethods(cdef.impl, templateNamer)
classOfModuleClass -= clazz
}
- addMacroMethods(templ, templateNamer)
+ if (settings.Xmacros.value) addMacroMethods(templ, templateNamer)
}
// add the copy method to case classes; this needs to be done here, not in SyntheticMethods, because
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index b4221365be..0fbde03e97 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -911,7 +911,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
if (tree.isType)
adaptType()
- else if ((mode & (PATTERNmode | FUNmode)) == (PATTERNmode | FUNmode))
+ else if (inExprModeButNot(mode, FUNmode) && tree.symbol != null && tree.symbol.isMacro && !tree.isDef) {
+ val tree1 = expandMacro(tree)
+ if (tree1.isErroneous) tree1 else typed(tree1, mode, pt)
+ } else if ((mode & (PATTERNmode | FUNmode)) == (PATTERNmode | FUNmode))
adaptConstrPattern()
else if (inAllModes(mode, EXPRmode | FUNmode) &&
!tree.tpe.isInstanceOf[MethodType] &&
@@ -3471,9 +3474,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// (calling typed1 more than once for the same tree)
if (checked ne res) typed { atPos(tree.pos)(checked) }
else res
- } else if ((mode & FUNmode) == 0 && fun2.hasSymbol && fun2.symbol.isMacro)
- typed1(macroExpand(res), mode, pt)
- else
+ } else
res
case ex: TypeError =>
fun match {
@@ -3483,7 +3484,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (treeInfo.isVariableOrGetter(qual1)) {
stopTimer(failedOpEqNanos, opeqStart)
convertToAssignment(fun, qual1, name, args, ex)
- }
+ }
else {
stopTimer(failedApplyNanos, appStart)
reportTypeError(fun.pos, ex)
@@ -4441,6 +4442,15 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
}
+ def expandMacro(tree: Tree): Tree = try {
+ macroExpand(tree) match {
+ case t: Tree => t
+ case t => errorTree(tree, "macros must return a compiler-specific tree; returned class is: " + t.getClass)
+ }
+ } catch {
+ case ex: MacroExpandError => errorTree(tree, ex.msg)
+ }
+
def atOwner(owner: Symbol): Typer =
newTyper(context.make(context.tree, owner))