diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2012-01-20 01:52:40 +0100 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2012-01-20 06:54:20 +0100 |
commit | 35e676ded0f9bfd006a5f090841abdea3ff1759c (patch) | |
tree | ade8247e0ebc66964189875194f78b85c6596d27 /src | |
parent | 58cb15c40dc431e45eaa0a5278874d9996e42104 (diff) | |
download | scala-35e676ded0f9bfd006a5f090841abdea3ff1759c.tar.gz scala-35e676ded0f9bfd006a5f090841abdea3ff1759c.tar.bz2 scala-35e676ded0f9bfd006a5f090841abdea3ff1759c.zip |
Progress with macros
A short recap:
* Macro expansion now works finely for instance macro invocations
* Macros are now hidden behind -Xmacros
* Bodies of macros now have "import _context._" in their preamble
* Macros are now loaded from classpath, much like regular libraries
* Macros can now override methods (in that case macro expansion
does not crash if macro is not found, it just falls back to super)
Review by @odersky.
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/reflect/internal/Definitions.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/reflect/internal/StdNames.scala | 29 | ||||
-rw-r--r-- | src/compiler/scala/reflect/runtime/JavaToScala.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/reflect/runtime/Mirror.scala | 15 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/MacroContext.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 7 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/settings/ScalaSettings.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Macros.scala | 136 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Namers.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 20 | ||||
-rw-r--r-- | src/library/scala/reflect/ReflectionUtils.scala | 12 | ||||
-rw-r--r-- | src/library/scala/reflect/api/Mirror.scala | 6 | ||||
-rw-r--r-- | src/library/scala/reflect/macro/Context.scala (renamed from src/library/scala/reflect/api/MacroContext.scala) | 6 | ||||
-rw-r--r-- | src/library/scala/reflect/package.scala | 2 |
15 files changed, 200 insertions, 49 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 884ad7af3d..5aaad9da2f 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) @@ -4430,6 +4431,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)) diff --git a/src/library/scala/reflect/ReflectionUtils.scala b/src/library/scala/reflect/ReflectionUtils.scala index b63a8645de..dfadfb4976 100644 --- a/src/library/scala/reflect/ReflectionUtils.scala +++ b/src/library/scala/reflect/ReflectionUtils.scala @@ -27,11 +27,15 @@ object ReflectionUtils { case ex if pf isDefinedAt unwrapThrowable(ex) => pf(unwrapThrowable(ex)) } - // Retrieves the MODULE$ field for the given class name. - def singletonInstance(className: String, cl: ClassLoader = getClass.getClassLoader): Option[AnyRef] = { + def singletonInstance(className: String, cl: ClassLoader = getClass.getClassLoader): AnyRef = { val name = if (className endsWith "$") className else className + "$" + val clazz = java.lang.Class.forName(name, true, cl) + val singleton = clazz getField "MODULE$" get null + singleton + } - try Some(java.lang.Class.forName(name, true, cl) getField "MODULE$" get null) + // Retrieves the MODULE$ field for the given class name. + def singletonInstanceOpt(className: String, cl: ClassLoader = getClass.getClassLoader): Option[AnyRef] = + try Some(singletonInstance(className, cl)) catch { case _: ClassNotFoundException => None } - } } diff --git a/src/library/scala/reflect/api/Mirror.scala b/src/library/scala/reflect/api/Mirror.scala index 53ac84f8cb..136f52b05f 100644 --- a/src/library/scala/reflect/api/Mirror.scala +++ b/src/library/scala/reflect/api/Mirror.scala @@ -13,7 +13,11 @@ trait Mirror extends Universe with RuntimeTypes with TreeBuildUtil { * to do: throws anything else? */ def classWithName(name: String): Symbol - + + /** Return a reference to the companion object of this class symbol + */ + def getCompanionObject(clazz: Symbol): AnyRef + /** The Scala class symbol corresponding to the runtime class of given object * @param The object from which the class is returned * @throws ? diff --git a/src/library/scala/reflect/api/MacroContext.scala b/src/library/scala/reflect/macro/Context.scala index e23357d26e..d0a2787fdf 100644 --- a/src/library/scala/reflect/api/MacroContext.scala +++ b/src/library/scala/reflect/macro/Context.scala @@ -1,7 +1,7 @@ package scala.reflect -package api +package macro -trait MacroContext extends Universe { +trait Context extends api.Universe { /** Mark a variable as captured; i.e. force boxing in a *Ref type. */ @@ -12,4 +12,4 @@ trait MacroContext extends Universe { */ def referenceCapturedVariable(id: Ident): Tree -}
\ No newline at end of file +} diff --git a/src/library/scala/reflect/package.scala b/src/library/scala/reflect/package.scala index 62592baa27..1c3e618520 100644 --- a/src/library/scala/reflect/package.scala +++ b/src/library/scala/reflect/package.scala @@ -8,7 +8,7 @@ package object reflect { // initialization, but in response to a doomed attempt to utilize it. lazy val mirror: api.Mirror = { // we use (Java) reflection here so that we can keep reflect.runtime and reflect.internals in a seperate jar - ReflectionUtils.singletonInstance("scala.reflect.runtime.Mirror") collect { case x: api.Mirror => x } getOrElse { + ReflectionUtils.singletonInstanceOpt("scala.reflect.runtime.Mirror") collect { case x: api.Mirror => x } getOrElse { throw new UnsupportedOperationException("Scala reflection not available on this platform") } } |