diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2012-08-18 18:51:58 +0200 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2012-08-19 09:36:54 +0200 |
commit | a3735fdbbf93128874d93da5c69af0f777220313 (patch) | |
tree | b4f3684e98da1391c6d2ba38c308e75fad684c89 | |
parent | ac430ac8ba554d1b976d44598400d95ce5cf3816 (diff) | |
download | scala-a3735fdbbf93128874d93da5c69af0f777220313.tar.gz scala-a3735fdbbf93128874d93da5c69af0f777220313.tar.bz2 scala-a3735fdbbf93128874d93da5c69af0f777220313.zip |
pull request feedback
6 files changed, 87 insertions, 101 deletions
diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala b/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala index 2c16a754cb..4a4a900e2b 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala @@ -8,6 +8,7 @@ package interpreter import scala.reflect.internal.util.Position import scala.util.control.Exception.ignoring +import scala.tools.nsc.util.stackTraceString /** * Machinery for the asynchronous initialization of the repl. @@ -94,9 +95,7 @@ trait ILoopInit { runThunks() } catch { case ex: Throwable => - val message = new java.io.StringWriter() - ex.printStackTrace(new java.io.PrintWriter(message)) - initError = message.toString + initError = stackTraceString(ex) throw ex } finally { initIsComplete = true diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 99ce22ddb9..773d9a6f50 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -12,6 +12,8 @@ import symtab.Flags.{ PRIVATE, PROTECTED, IS_ERROR } import scala.compat.Platform.EOL import scala.reflect.runtime.ReflectionUtils import scala.reflect.macros.runtime.AbortMacroException +import scala.util.control.NonFatal +import scala.tools.nsc.util.stackTraceString trait ContextErrors { self: Analyzer => @@ -687,13 +689,14 @@ trait ContextErrors { relevantElements = relevantElements dropRight threshold realex.setStackTrace(relevantElements) - val message = new java.io.StringWriter() - realex.printStackTrace(new java.io.PrintWriter(message)) - Some(EOL + message) + Some(EOL + stackTraceString(realex)) } } catch { // if the magic above goes boom, just fall back to uninformative, but better than nothing, getMessage - case ex: Throwable => + case NonFatal(ex) => + macroLogVerbose("got an exception when processing a macro generated exception\n" + + "offender = " + stackTraceString(realex) + "\n" + + "error = " + stackTraceString(ex)) None } } getOrElse { diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index ed38c1750b..abfefcd31e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -398,7 +398,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { macroLogVerbose("typechecked1:%n%s%n%s".format(typechecked, showRaw(typechecked))) typechecked } finally { - openMacros = openMacros.tail + popMacroContext() } case Fallback(fallback) => typer.typed1(fallback, EXPRmode, WildcardType) @@ -461,7 +461,11 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { map2(aparamss.flatten, rparamss.flatten)((aparam, rparam) => { if (aparam.name != rparam.name && !rparam.isSynthetic) MacroImplParamNameMismatchError(aparam, rparam) if (isRepeated(aparam) ^ isRepeated(rparam)) MacroImplVarargMismatchError(aparam, rparam) - checkMacroImplParamTypeMismatch(stripOffPrefixTypeRefinement(atpeToRtpe(aparam.tpe)), rparam) + val aparamtpe = aparam.tpe.dealias match { + case RefinedType(List(tpe), Scope(sym)) if tpe == MacroContextClass.tpe && sym.allOverriddenSymbols.contains(MacroContextPrefixType) => tpe + case tpe => tpe + } + checkMacroImplParamTypeMismatch(atpeToRtpe(aparamtpe), rparam) }) checkMacroImplResultTypeMismatch(atpeToRtpe(aret), rret) @@ -510,7 +514,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { * @return Requested runtime if macro implementation can be loaded successfully from either of the mirrors, * `null` otherwise. */ - type MacroRuntime = List[Any] => Any + type MacroRuntime = MacroArgs => Any private val macroRuntimesCache = perRunCaches.newWeakMap[Symbol, MacroRuntime] private def macroRuntime(macroDef: Symbol): MacroRuntime = { macroTraceVerbose("looking for macro implementation: ")(macroDef) @@ -538,7 +542,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { val implMeths = implObj.getClass.getDeclaredMethods.find(_.getName == methName) val implMeth = implMeths getOrElse { throw new NoSuchMethodException(s"$className.$methName") } macroLogVerbose("successfully loaded macro impl as (%s, %s)".format(implObj, implMeth)) - (args: List[Any]) => implMeth.invoke(implObj, (args map (_.asInstanceOf[AnyRef])): _*) + args => implMeth.invoke(implObj, ((args.c +: args.others) map (_.asInstanceOf[AnyRef])): _*) } catch { case ex: Exception => macroTraceVerbose(s"macro runtime failed to load: ")(ex.toString) @@ -561,7 +565,8 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { /** Calculate the arguments to pass to a macro implementation when expanding the provided tree. */ - private def macroArgs(typer: Typer, expandee: Tree): List[Any] = { + case class MacroArgs(c: MacroContext, others: List[Any]) + private def macroArgs(typer: Typer, expandee: Tree): MacroArgs = { val macroDef = expandee.symbol val prefixTree = expandee.collect{ case Select(qual, name) => qual }.headOption.getOrElse(EmptyTree) val context = expandee.attachments.get[MacroRuntimeAttachment].flatMap(_.macroContext).getOrElse(macroContext(typer, prefixTree, expandee)) @@ -583,12 +588,13 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { val nullaryArgsEmptyParams = exprArgs.isEmpty && macroDef.paramss == ListOfNil if (argcDoesntMatch && !nullaryArgsEmptyParams) { typer.TyperErrorGen.MacroPartialApplicationError(expandee) } - var argss: List[List[Any]] = List(context) :: exprArgs.toList + var argss: List[List[Any]] = exprArgs.toList + macroTraceVerbose("context: ")(context) macroTraceVerbose("argss: ")(argss) - val rawArgss = + val preparedArgss: List[List[Any]] = if (fastTrack contains macroDef) { - if (fastTrack(macroDef) validate argss) argss + if (fastTrack(macroDef) validate context) argss else typer.TyperErrorGen.MacroPartialApplicationError(expandee) } else { val binding = loadMacroImplBinding(macroDef) @@ -631,28 +637,31 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { argss = if (hasImplicitParams) argss.dropRight(1) :+ (tags ++ argss.last) else argss :+ tags // transforms argss taking into account varargness of paramss - // not all argument lists in argss map to macroDef.paramss, so we need to apply extra care - // namely: - // 1) the first argument list represents (c: Context) in macroImpl, so it doesn't have correspondence in macroDef - // 2) typetag context bounds are only declared on macroImpls, so this optional arglist also doesn't match macroDef + // note that typetag context bounds are only declared on macroImpls + // so this optional arglist might not match macroDef's paramlist // nb! varargs can apply to any parameter section, not necessarily to the last one - mapWithIndex(argss)((as, i_argss) => { - val i_paramss = i_argss - 1 - val mapsToParamss = 0 <= i_paramss && i_paramss < macroDef.paramss.length + mapWithIndex(argss)((as, i) => { + val mapsToParamss = macroDef.paramss.indices contains i if (mapsToParamss) { - val ps = macroDef.paramss(i_paramss) - if (isVarArgsList(ps)) as.take(ps.length - 1) :+ as.drop(ps.length - 1) - else as + val ps = macroDef.paramss(i) + if (isVarArgsList(ps)) { + val (normal, varargs) = as splitAt (ps.length - 1) + normal :+ varargs // pack all varargs into a single List argument + } else as } else as }) } - macroTraceVerbose("rawArgs: ")(rawArgss.flatten) + macroTraceVerbose("preparedArgss: ")(preparedArgss) + MacroArgs(context, preparedArgss.flatten) } /** Keeps track of macros in-flight. * See more informations in comments to `openMacros` in `scala.reflect.macros.Context`. */ - var openMacros = List[MacroContext]() + private var _openMacros = List[MacroContext]() + def openMacros = _openMacros + private def pushMacroContext(c: MacroContext) = _openMacros ::= c + private def popMacroContext() = _openMacros = _openMacros.tail def enclosingMacroPosition = openMacros map (_.macroApplication.pos) find (_ ne NoPosition) getOrElse NoPosition private sealed abstract class MacroExpansionResult @@ -708,7 +717,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { typechecked = typecheck("expected type", typechecked, pt) typechecked addAttachment MacroExpansionAttachment(expandee) } finally { - openMacros = openMacros.tail + popMacroContext() } case Fallback(fallback) => typer.context.withImplicitsEnabled(typer.typed(fallback, EXPRmode, pt)) @@ -745,63 +754,49 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { * Meant for internal use within the macro infrastructure, don't use it elsewhere. */ private def macroExpandWithRuntime(typer: Typer, expandee: Tree, runtime: MacroRuntime): MacroExpansionResult = { - import typer.TyperErrorGen._ - try { - def performExpansion(args: List[Any]): MacroExpansionResult = { - val numErrors = reporter.ERROR.count - def hasNewErrors = reporter.ERROR.count > numErrors - val expanded = runtime(args) - if (hasNewErrors) MacroGeneratedTypeError(expandee) - - expanded match { - case expanded: Expr[_] => - macroLogVerbose("original:") - macroLogLite("" + expanded.tree + "\n" + showRaw(expanded.tree)) - val freeSyms = expanded.tree.freeTerms ++ expanded.tree.freeTypes - freeSyms foreach (sym => MacroFreeSymbolError(expandee, sym)) - Success(atPos(enclosingMacroPosition.focus)(expanded.tree)) - case _ => - MacroExpansionIsNotExprError(expandee, expanded) - } - } - - val wasDelayed = isDelayed(expandee) - val undetparams = calculateUndetparams(expandee) - val nowDelayed = !typer.context.macrosEnabled || undetparams.nonEmpty - - if (wasDelayed || nowDelayed) { - if (!wasDelayed && nowDelayed) { - macroLogLite("macro expansion is delayed: %s".format(expandee)) - delayed += expandee -> undetparams - val macroContext = macroArgs(typer, expandee).head.asInstanceOf[MacroContext] - expandee addAttachment MacroRuntimeAttachment(delayed = true, typerContext = typer.context, macroContext = Some(macroContext)) - Delay(expandee) - } else if (wasDelayed && nowDelayed) { - Delay(expandee) - } else /* if (wasDelayed && !nowDelayed) */ { - Skip(macroExpandAll(typer, expandee)) - } - } else { + val wasDelayed = isDelayed(expandee) + val undetparams = calculateUndetparams(expandee) + val nowDelayed = !typer.context.macrosEnabled || undetparams.nonEmpty + + (wasDelayed, nowDelayed) match { + case (true, true) => Delay(expandee) + case (true, false) => Skip(macroExpandAll(typer, expandee)) + case (false, true) => + macroLogLite("macro expansion is delayed: %s".format(expandee)) + delayed += expandee -> undetparams + expandee addAttachment MacroRuntimeAttachment(delayed = true, typerContext = typer.context, macroContext = Some(macroArgs(typer, expandee).c)) + Delay(expandee) + case (false, false) => + import typer.TyperErrorGen._ macroLogLite("performing macro expansion %s at %s".format(expandee, expandee.pos)) val args = macroArgs(typer, expandee) - openMacros ::= args.head.asInstanceOf[MacroContext] - var isSuccess = false - try performExpansion(args) match { - case x: Success => isSuccess = true ; x - case x => x + try { + val numErrors = reporter.ERROR.count + def hasNewErrors = reporter.ERROR.count > numErrors + val expanded = { pushMacroContext(args.c); runtime(args) } + if (hasNewErrors) MacroGeneratedTypeError(expandee) + expanded match { + case expanded: Expr[_] => + macroLogVerbose("original:") + macroLogLite("" + expanded.tree + "\n" + showRaw(expanded.tree)) + val freeSyms = expanded.tree.freeTerms ++ expanded.tree.freeTypes + freeSyms foreach (sym => MacroFreeSymbolError(expandee, sym)) + Success(atPos(enclosingMacroPosition.focus)(expanded.tree)) + case _ => + MacroExpansionIsNotExprError(expandee, expanded) + } + } catch { + case ex: Throwable => + popMacroContext() + val realex = ReflectionUtils.unwrapThrowable(ex) + realex match { + case ex: AbortMacroException => MacroGeneratedAbort(expandee, ex) + case ex: ControlThrowable => throw ex + case ex: TypeError => MacroGeneratedTypeError(expandee, ex) + case _ => MacroGeneratedException(expandee, realex) + } } finally { expandee.removeAttachment[MacroRuntimeAttachment] - if (!isSuccess) openMacros = openMacros.tail - } - } - } catch { - case ex: Throwable => - val realex = ReflectionUtils.unwrapThrowable(ex) - realex match { - case ex: AbortMacroException => MacroGeneratedAbort(expandee, ex) - case ex: ControlThrowable => throw ex - case ex: TypeError => MacroGeneratedTypeError(expandee, ex) - case _ => MacroGeneratedException(expandee, realex) } } } @@ -810,8 +805,8 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { * Meant for internal use within the macro infrastructure, don't use it elsewhere. */ private def macroExpandWithoutRuntime(typer: Typer, expandee: Tree): MacroExpansionResult = { - val fallbackSym = expandee.symbol.allOverriddenSymbols.headOption.getOrElse(NoSymbol) - if (fallbackSym == NoSymbol) typer.TyperErrorGen.MacroImplementationNotFoundError(expandee) + import typer.TyperErrorGen._ + val fallbackSym = expandee.symbol.nextOverriddenSymbol orElse MacroImplementationNotFoundError(expandee) macroTraceLite("falling back to: ")(fallbackSym) def mkFallbackTree(tree: Tree): Tree = { diff --git a/src/compiler/scala/tools/reflect/FastTrack.scala b/src/compiler/scala/tools/reflect/FastTrack.scala index f84877cccb..07c972899e 100644 --- a/src/compiler/scala/tools/reflect/FastTrack.scala +++ b/src/compiler/scala/tools/reflect/FastTrack.scala @@ -17,16 +17,11 @@ trait FastTrack { private implicit def context2taggers(c0: MacroContext): Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers private implicit def context2macroimplementations(c0: MacroContext): MacroImplementations { val c: c0.type } = new { val c: c0.type = c0 } with MacroImplementations - implicit def fastTrackEntry2MacroRuntime(entry: FastTrackEntry): MacroRuntime = args => entry.run(args) + implicit def fastTrackEntry2MacroRuntime(entry: FastTrackEntry): MacroRuntime = args => entry.run(args.c) type FastTrackExpander = PartialFunction[(MacroContext, Tree), Tree] case class FastTrackEntry(sym: Symbol, expander: FastTrackExpander) { - def validate(argss: List[List[Any]]): Boolean = { - val c = argss.flatten.apply(0).asInstanceOf[MacroContext] - val isValid = expander isDefinedAt (c, c.expandee) - isValid - } - def run(args: List[Any]): Any = { - val c = args(0).asInstanceOf[MacroContext] + def validate(c: MacroContext): Boolean = expander.isDefinedAt((c, c.expandee)) + def run(c: MacroContext): Any = { val result = expander((c, c.expandee)) c.Expr[Nothing](result)(c.AbsTypeTag.Nothing) } diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index a1f44ace6e..98d42b724c 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -462,7 +462,7 @@ trait Definitions extends api.StandardDefinitions { def ReflectRuntimeUniverse = if (ReflectRuntimePackage != NoSymbol) getMemberValue(ReflectRuntimePackage, nme.universe) else NoSymbol def ReflectRuntimeCurrentMirror = if (ReflectRuntimePackage != NoSymbol) getMemberMethod(ReflectRuntimePackage, nme.currentMirror) else NoSymbol - lazy val PartialManifestClass = getMemberType(ReflectPackage, tpnme.ClassManifest) + lazy val PartialManifestClass = getTypeMember(ReflectPackage, tpnme.ClassManifest) lazy val PartialManifestModule = requiredModule[scala.reflect.ClassManifestFactory.type] lazy val FullManifestClass = requiredClass[scala.reflect.Manifest[_]] lazy val FullManifestModule = requiredModule[scala.reflect.ManifestFactory.type] @@ -494,7 +494,7 @@ trait Definitions extends api.StandardDefinitions { lazy val MacroContextClass = getClassIfDefined("scala.reflect.macros.Context") // defined in scala-reflect.jar, so we need to be careful def MacroContextPrefix = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.prefix) else NoSymbol - def MacroContextPrefixType = if (MacroContextClass != NoSymbol) getMemberType(MacroContextClass, tpnme.PrefixType) else NoSymbol + def MacroContextPrefixType = if (MacroContextClass != NoSymbol) getTypeMember(MacroContextClass, tpnme.PrefixType) else NoSymbol def MacroContextUniverse = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.universe) else NoSymbol def MacroContextMirror = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.mirror) else NoSymbol lazy val MacroImplAnnotation = requiredClass[scala.reflect.macros.internal.macroImpl] @@ -1012,10 +1012,10 @@ trait Definitions extends api.StandardDefinitions { case _ => fatalMissingSymbol(owner, name, "member object") } } - def getMemberType(owner: Symbol, name: Name): TypeSymbol = { + def getTypeMember(owner: Symbol, name: Name): TypeSymbol = { getMember(owner, name.toTypeName) match { case x: TypeSymbol => x - case _ => fatalMissingSymbol(owner, name, "member type") + case _ => fatalMissingSymbol(owner, name, "type member") } } def getMemberClass(owner: Symbol, name: Name): ClassSymbol = { diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 52dd4a55cf..9514898ce5 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -6939,12 +6939,6 @@ trait Types extends api.Types { self: SymbolTable => else (ps :+ SerializableClass.tpe).toList ) - def stripOffPrefixTypeRefinement(tpe: Type): Type = - tpe.dealias match { - case RefinedType(List(tpe), Scope(sym)) if tpe == MacroContextClass.tpe && sym.allOverriddenSymbols.contains(MacroContextPrefixType) => tpe - case _ => tpe - } - def objToAny(tp: Type): Type = if (!phase.erasedTypes && tp.typeSymbol == ObjectClass) AnyClass.tpe else tp |