summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/reflect/internal/JvmClassInfo.scala440
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Context.scala3
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Traces.scala8
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Typers.scala17
-rw-r--r--src/compiler/scala/reflect/makro/util/Traces.scala18
-rw-r--r--src/compiler/scala/reflect/reify/Errors.scala3
-rw-r--r--src/compiler/scala/reflect/reify/codegen/Types.scala2
-rw-r--r--src/compiler/scala/reflect/reify/codegen/Util.scala2
-rw-r--r--src/compiler/scala/reflect/reify/package.scala10
-rw-r--r--src/compiler/scala/tools/cmd/program/DumpClass.scala40
-rw-r--r--src/compiler/scala/tools/nsc/ast/NodePrinters.scala48
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala115
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala201
-rw-r--r--src/compiler/scala/tools/util/StringOps.scala10
16 files changed, 745 insertions, 180 deletions
diff --git a/src/compiler/scala/reflect/internal/JvmClassInfo.scala b/src/compiler/scala/reflect/internal/JvmClassInfo.scala
new file mode 100644
index 0000000000..d47f51e512
--- /dev/null
+++ b/src/compiler/scala/reflect/internal/JvmClassInfo.scala
@@ -0,0 +1,440 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.reflect.internal
+
+import java.io.{ DataInput, InputStream, DataInputStream, ByteArrayInputStream, BufferedInputStream, FileInputStream }
+import scala.tools.nsc.io.{ Directory }
+import scala.reflect.NameTransformer.decode
+import scala.tools.util.StringOps.trimTrailingSpace
+import ConstantPool._
+
+final case class JvmVersion(minorVersion: Int, majorVersion: Int)
+
+trait ClassfileModel {
+ type Result
+ type Entry
+ type InterfaceInfo
+ type MemberInfo
+ type AttributeInfo
+ type InnerClassInfo
+
+ protected implicit def EntryArrayTag: ArrayTag[Entry]
+ protected implicit def InterfaceInfoArrayTag: ArrayTag[InterfaceInfo]
+ protected implicit def MemberInfoArrayTag: ArrayTag[MemberInfo]
+ protected implicit def AttributeInfoArrayTag: ArrayTag[AttributeInfo]
+ protected implicit def InnerClassInfoArrayTag: ArrayTag[InnerClassInfo]
+
+ // These could be implemented to jump forward in the stream if the
+ // result is not wanted.
+ def readConstantPoolEntry(): Entry
+ def readInterface(): InterfaceInfo
+ def readMember(): MemberInfo
+ def readAttribute(): AttributeInfo
+ def readInnerClass(): InnerClassInfo
+
+ def createInfo(
+ version: JvmVersion,
+ entries: Array[Entry],
+ flags: Int,
+ name: String,
+ superName: String,
+ interfaces: Array[InterfaceInfo],
+ fields: Array[MemberInfo],
+ methods: Array[MemberInfo],
+ attributes: Array[AttributeInfo]
+ ): Result
+}
+
+abstract class StreamingClassfileModel extends ClassfileModel {
+ protected[this] val in: DataInput
+ private[this] var name: String = _
+ private[this] var entries: Array[PoolEntry] = _
+
+ type Entry = PoolEntry
+
+ // These translate null into "", it's less troublesome.
+ protected def nameAt(idx: Int) = entries(idx) match {
+ case x: Name_Info => stringAt(x.name_index).replace('/', '.')
+ case _ => ""
+ }
+ protected def stringAt(idx: Int) = entries(idx) match {
+ case x: Utf8_info => x.stringValue
+ case _ => ""
+ }
+
+ protected def u4 = in.readInt
+ protected def u2 = in.readUnsignedShort.toChar
+ protected def u1 = in.readUnsignedByte
+
+ // The constant_pool table is indexed from 1 to constant_pool_count−1.
+ protected def readConstantPool(): Array[Entry] = {
+ val count = u2
+ val entries = new Array[Entry](count)
+ var i = 1
+ while (i < count) {
+ val entry = readConstantPoolEntry()
+ entries(i) = entry
+ i += entry.width
+ }
+ entries
+ }
+ protected def readInterfaces() = {
+ val count = u2
+ val interfaces = new Array[InterfaceInfo](count)
+ var i = 0
+ while (i < count) {
+ interfaces(i) = readInterface()
+ i += 1
+ }
+ interfaces
+ }
+ protected def readMembers() = {
+ val count = u2
+ val arr = new Array[MemberInfo](count)
+ var i = 0
+ while (i < count) {
+ arr(i) = readMember()
+ i += 1
+ }
+ arr
+ }
+ protected def readAttributes(): Array[AttributeInfo] = {
+ val count = u2
+ val arr = new Array[AttributeInfo](count)
+ var i = 0
+ while (i < count) {
+ arr(i) = readAttribute()
+ i += 1
+ }
+ arr
+ }
+ protected def readInnerClasses() = {
+ val count = u2
+ val arr = new Array[InnerClassInfo](count)
+ var i = 0
+ while (i < count) {
+ arr(i) = readInnerClass()
+ i += 1
+ }
+ arr
+ }
+ protected def thisClass = name
+
+ def parse() = {
+ assert(u4 == 0xCAFEBABE, "Bad magic number")
+ val version = JvmVersion(u2, u2)
+ this.entries = readConstantPool()
+ val flags = u2.toShort
+ this.name = nameAt(u2)
+ val superName = nameAt(u2)
+ val interfaces = readInterfaces()
+ val fields = readMembers()
+ val methods = readMembers()
+ val attributes = readAttributes()
+
+ try createInfo(version, entries, flags, name, superName, interfaces, fields, methods, attributes)
+ finally entries = null
+ }
+}
+
+abstract class ScalacClassfileModel extends StreamingClassfileModel {
+ type Result = JvmClassInfo
+ type InterfaceInfo = String
+ type MemberInfo = JvmMemberInfo
+ type AttributeInfo = JvmAttributeInfo
+ type InnerClassInfo = JvmInnerClassInfo
+
+ protected implicit def EntryArrayTag = arrayTag[PoolEntry]
+ protected implicit def InterfaceInfoArrayTag = arrayTag[InterfaceInfo]
+ protected implicit def MemberInfoArrayTag = arrayTag[MemberInfo]
+ protected implicit def AttributeInfoArrayTag = arrayTag[AttributeInfo]
+ protected implicit def InnerClassInfoArrayTag = arrayTag[InnerClassInfo]
+
+ def readConstantPoolEntry(): PoolEntry
+ def readInterface(): String
+ def readMember(): JvmMemberInfo
+ def readAttribute(): JvmAttributeInfo
+ def readInnerClass(): JvmInnerClassInfo
+
+ def createInfo(
+ version: JvmVersion,
+ entries: Array[PoolEntry],
+ flags: Int,
+ name: String,
+ superName: String,
+ interfaces: Array[String],
+ fields: Array[JvmMemberInfo],
+ methods: Array[JvmMemberInfo],
+ attributes: Array[JvmAttributeInfo]
+ ): JvmClassInfo = new JvmClassInfo(name, superName, interfaces, fields, methods, attributes)
+}
+
+class JvmClassInfoBuilder(protected[this] val in: DataInput) extends ScalacClassfileModel {
+ def readInterface(): InterfaceInfo = nameAt(u2)
+ def readMember(): JvmMemberInfo = new JvmMemberInfo(u2.toShort, stringAt(u2), stringAt(u2), readAttributes())
+ def readInnerClass(): JvmInnerClassInfo = new JvmInnerClassInfo(thisClass, nameAt(u2), nameAt(u2), stringAt(u2), u2.toShort)
+
+ def readConstantPoolEntry(): Entry = (u1: @annotation.switch) match {
+ case CONSTANT_Utf8 => new Utf8_info(in.readUTF)
+ case CONSTANT_Integer => new Integer_info(in.readInt)
+ case CONSTANT_Float => new Float_info(in.readFloat)
+ case CONSTANT_Long => new Long_info(in.readLong)
+ case CONSTANT_Double => new Double_info(in.readDouble)
+ case CONSTANT_Class => new Class_info(u2)
+ case CONSTANT_String => new String_info(u2)
+ case CONSTANT_Fieldref => new Fieldref_info(u2, u2)
+ case CONSTANT_Methodref => new Methodref_info(u2, u2)
+ case CONSTANT_InterfaceMethodref => new InterfaceMethodref_info(u2, u2)
+ case CONSTANT_NameAndType => new NameAndType_info(u2, u2)
+ }
+
+ // field_info attributes:
+ // ConstantValue (§4.7.2), Synthetic (§4.7.8), Signature (§4.7.9), Deprecated (§4.7.15),
+ // RuntimeVisibleAnnotations (§4.7.16) and RuntimeInvisibleAnnotations (§4.7.17).
+ //
+ // method_info attributes:
+ // Code (§4.7.3), Exceptions (§4.7.5), Synthetic (§4.7.8), Signature (§4.7.9), Deprecated (§4.7.15),
+ // RuntimeVisibleAnnotations (§4.7.16), RuntimeInvisibleAnnotations (§4.7.17), RuntimeVisibleParameterAnnotations (§4.7.18),
+ // RuntimeInvisibleParameterAnnotations (§4.7.19) and AnnotationDefault (§4.7.20).
+
+ def readAttribute(): AttributeInfo = stringAt(u2) match {
+ case "Signature" => u4 ; new SignatureAttr(stringAt(u2))
+ case "InnerClasses" => u4 ; new InnerClassesAttr(readInnerClasses())
+ case name => val bytes = new Array[Byte](u4) ; in.readFully(bytes) ; new GenericAttr(name, bytes)
+ }
+}
+
+object Classify {
+
+ /*
+
+
+ 4.2.2 Unqualified Names
+
+Names of methods, fields and local variables are stored as unqualified
+names. Unqualified names must not contain the characters '.', ';', '['
+or '/'. Method names are further constrained so that, with the exception
+of the special method names <init> and <clinit> (§3.9), they must not
+contain the characters '<' or '>'.
+
+ 4.3 Descriptors and Signatures
+
+A descriptor is a string representing the type of a field or method.
+Descriptors are represented in the class file format using modified
+UTF-8 strings (§4.4.7) and thus may be drawn, where not further
+constrained, from the entire Unicode character set. A signature is a
+string representing the generic type of a field or method, or generic
+type information for a class declaration.
+*/
+
+}
+
+object ConstantPool {
+ type UShort = Char
+
+ final val CONSTANT_Utf8 = 1
+ final val CONSTANT_Integer = 3
+ final val CONSTANT_Float = 4
+ final val CONSTANT_Long = 5
+ final val CONSTANT_Double = 6
+ final val CONSTANT_Class = 7
+ final val CONSTANT_String = 8
+ final val CONSTANT_Fieldref = 9
+ final val CONSTANT_Methodref = 10
+ final val CONSTANT_InterfaceMethodref = 11
+ final val CONSTANT_NameAndType = 12
+
+ abstract class Name_Info(tag: Byte) extends PoolEntry(tag) {
+ def name_index: UShort
+ }
+ abstract class Ref_Info(tag: Byte) extends PoolEntry(tag) {
+ def class_index: UShort
+ def name_and_type_index: UShort
+ }
+ class Class_info(val name_index: UShort) extends Name_Info(CONSTANT_Class) { }
+ class Double_info(val value: Double) extends PoolEntry(CONSTANT_Double) {
+ override def width = 2
+ }
+ class Fieldref_info(val class_index: UShort, val name_and_type_index: UShort) extends Ref_Info(CONSTANT_Fieldref)
+ class Float_info(val value: Float) extends PoolEntry(CONSTANT_Float)
+ class Integer_info(val value: Int) extends PoolEntry(CONSTANT_Integer)
+ class InterfaceMethodref_info(val class_index: UShort, val name_and_type_index: UShort) extends Ref_Info(CONSTANT_InterfaceMethodref)
+ class Long_info(val value: Long) extends PoolEntry(CONSTANT_Long) {
+ override def width = 2
+ }
+ class Methodref_info(val class_index: UShort, val name_and_type_index: UShort) extends Ref_Info(CONSTANT_Methodref)
+ class NameAndType_info(val name_index: UShort, val descriptor_index: UShort) extends Name_Info(CONSTANT_NameAndType) {
+ override def toString = "NameAndType #%s:#%s;".format(name_index, descriptor_index)
+ }
+ class String_info(val string_index: UShort) extends PoolEntry(CONSTANT_String) { }
+ class Utf8_info(override val stringValue: String) extends PoolEntry(CONSTANT_Utf8) {
+ override def toString = ("Asciz " + stringValue).trim
+ }
+
+ abstract class PoolEntry(tag: Byte) {
+ def width = 1
+ def stringValue: String = sys.error("Not a String-valued constant pool entry: " + this)
+ override def toString = (
+ getClass.getName.split("[.$]").last + "/" + tag
+ )
+ }
+ object NoEntry extends PoolEntry(-1) { }
+}
+
+abstract class JvmInfo(attributes: Array[JvmAttributeInfo]) {
+ // def flags: Short
+ def name: String
+
+ val signature = attributes collectFirst { case x: SignatureAttr => x.value } getOrElse ""
+ val innerClasses = attributes collectFirst { case x: InnerClassesAttr => x.value } getOrElse Array()
+}
+
+
+class JvmClassInfo(
+ val name: String,
+ val superName: String,
+ val interfaces: Array[String],
+ val fields: Array[JvmMemberInfo],
+ val methods: Array[JvmMemberInfo],
+ attributes: Array[JvmAttributeInfo]
+) extends JvmInfo(attributes) {
+
+ def members = fields ++ methods sortBy (_.decodedName)
+ def memberDescriptors = members map (_.toErasedString)
+ def memberSignatures = members filter (_.hasSignature) map (_.toGenericString)
+ def descriptorsString = if (memberDescriptors.nonEmpty) memberDescriptors.mkString("\n-- Member Descriptors --\n", "\n", "\n") else ""
+ def signaturesString = if (memberSignatures.nonEmpty) memberSignatures.mkString("\n-- Member Signatures --\n", "\n", "\n") else ""
+ def innersString = if (innerClasses.isEmpty) "" else innerClasses.mkString("\n-- Inner Classes --\n", "\n", "\n")
+ def membersString = descriptorsString + signaturesString
+ def extendsString = if (superName == "") "" else " extends " + superName
+ def implementsString = if (interfaces.isEmpty) "" else interfaces.mkString("Implements: ", ", ", "")
+
+ private def group(label: String, xs: Traversable[(String, String)]) =
+ xs map { case (name, value) => line(label, name, value) } mkString "\n"
+
+ private def line(label: String, name: String, data: String) =
+ trimTrailingSpace(" %-15s %30s %s".format(label, name, data))
+
+ override def toString = (
+ List(
+ "class " + name + extendsString,
+ if (signature == "") "" else line("class sig", "", signature),
+ group("interface", interfaces map (x => (("", x)))),
+ (innerClasses map (ic => line(ic.kind, ic.innerName, ic.nestString))).sorted.mkString("\n"),
+ group("descriptor", members map (x => (x.name, x.descriptor))),
+ group("signature", members filter (_.hasSignature) map (x => (x.name, x.signature)))
+ ) map trimTrailingSpace filterNot (_ == "") mkString ("", "\n", "\n")
+ )
+}
+
+// method_info or field_info {
+// u2 access_flags;
+// u2 name_index;
+// u2 descriptor_index;
+// u2 attributes_count;
+// attribute_info attributes[attributes_count];
+// }
+class JvmMemberInfo(
+ val flags: Short,
+ val name: String,
+ val descriptor: String,
+ attributes: Array[JvmAttributeInfo]
+) extends JvmInfo(attributes) {
+ def decodedName = decode(name)
+ def hasSignature = signature != ""
+ def toErasedString = "%-30s %s".format(decodedName, descriptor)
+ def toGenericString = "%-30s %s".format(decodedName, signature)
+
+ override def toString = (
+ if (hasSignature) toGenericString else toErasedString
+ )
+}
+
+abstract class JvmAttributeInfo {
+ def name: String
+ def value: Any
+}
+class GenericAttr(val name: String, val value: Array[Byte]) extends JvmAttributeInfo {
+ // attribute_info {
+ // u2 attribute_name_index;
+ // u4 attribute_length;
+ // u1 info[attribute_length];
+ // }
+}
+class SignatureAttr(val value: String) extends JvmAttributeInfo {
+ def name = "Signature"
+}
+class InnerClassesAttr(val value: Array[JvmInnerClassInfo]) extends JvmAttributeInfo {
+ def name = "InnerClasses"
+}
+
+// package foo { class Foo { class Bar } }
+//
+// javap would say
+// Bar = class foo.Foo$Bar of class foo.Foo
+// which is translated as
+// innerClass = foo.Foo$Bar
+// outerClass = foo.Foo
+// innerName = Bar
+
+class JvmInnerClassInfo(
+ thisClass: String, // classfile which is being parsed
+ val innerClass: String, // the full name of the inner/nested class
+ val outerClass: String, // the full name of the outer class - must be a prefix of innerClass
+ val innerName: String, // the simple name of the inner class - should (?) be a suffix of innerClass
+ val flags: Short // flags
+) {
+ val isEntryOfEnclosingClass = !isAnonymousClass && (innerClass == thisClass)
+ val isEntryOfNestedClass = !isAnonymousClass && (outerClass == thisClass)
+
+ def isTopLevelClass = outerClass == ""
+ def isAnonymousClass = innerName == ""
+ def isMemberClass = !isTopLevelClass
+
+ def kind = (
+ if (isEntryOfEnclosingClass) "inner/enclosing"
+ else if (isEntryOfNestedClass) "inner/nested"
+ else if (isAnonymousClass) "inner/anon"
+ else "inner"
+ )
+ def nestString = (
+ if (isEntryOfEnclosingClass) "enclosing class: " + outerClass
+ else if (isEntryOfNestedClass) "member class: " + innerClass
+ else if (isAnonymousClass) "anonymous class: " + innerClass
+ else innerClass + " in " + outerClass
+ )
+ override def toString = innerName + "=" + nestString
+}
+
+object JvmClassInfo {
+ private def classFiles(path: String) =
+ Directory(path).deepFiles filter (_ hasExtension "class")
+
+ def classInfoMap(path: String): Map[String, JvmClassInfo] = {
+ classFiles(path) map (f => (f.path, JvmClassInfo fromFile f.jfile)) toMap
+ }
+ def classInfoList(path: String): List[(String, JvmClassInfo)] = {
+ classInfoMap(path).toList sortBy (_._1)
+ }
+
+ def fromFile(file: java.io.File) =
+ fromStream(new BufferedInputStream(new FileInputStream(file)))
+
+ def fromBytes(bytes: Array[Byte]) =
+ fromStream(new ByteArrayInputStream(bytes))
+
+ def fromPath(path: String) =
+ fromStream(new BufferedInputStream(new FileInputStream(path)))
+
+ def fromStream(in0: InputStream) = {
+ val in = new DataInputStream(in0)
+ try fromDataInput(in) finally in.close()
+ }
+
+ def fromDataInput(in: DataInput): JvmClassInfo = {
+ new JvmClassInfoBuilder(in) parse
+ }
+}
diff --git a/src/compiler/scala/reflect/makro/runtime/Context.scala b/src/compiler/scala/reflect/makro/runtime/Context.scala
index 15a4118b85..ca02822788 100644
--- a/src/compiler/scala/reflect/makro/runtime/Context.scala
+++ b/src/compiler/scala/reflect/makro/runtime/Context.scala
@@ -14,7 +14,8 @@ abstract class Context extends scala.reflect.makro.Context
with Settings
with Symbols
with Typers
- with Util {
+ with Util
+ with Traces {
val mirror: Global
diff --git a/src/compiler/scala/reflect/makro/runtime/Traces.scala b/src/compiler/scala/reflect/makro/runtime/Traces.scala
new file mode 100644
index 0000000000..6b61842316
--- /dev/null
+++ b/src/compiler/scala/reflect/makro/runtime/Traces.scala
@@ -0,0 +1,8 @@
+package scala.reflect.makro
+package runtime
+
+trait Traces extends util.Traces {
+ self: Context =>
+
+ def globalSettings = mirror.settings
+}
diff --git a/src/compiler/scala/reflect/makro/runtime/Typers.scala b/src/compiler/scala/reflect/makro/runtime/Typers.scala
index 98dbd65b72..c61e492250 100644
--- a/src/compiler/scala/reflect/makro/runtime/Typers.scala
+++ b/src/compiler/scala/reflect/makro/runtime/Typers.scala
@@ -9,8 +9,7 @@ trait Typers {
def openImplicits: List[(Type, Tree)] = callsiteTyper.context.openImplicits
def typeCheck(tree: Tree, pt: Type = mirror.WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree = {
- def trace(msg: Any) = if (mirror.settings.Ymacrodebug.value) println(msg)
- trace("typechecking %s with expected type %s, implicit views = %s, macros = %s".format(tree, pt, !withImplicitViewsDisabled, !withMacrosDisabled))
+ macroLogVerbose("typechecking %s with expected type %s, implicit views = %s, macros = %s".format(tree, pt, !withImplicitViewsDisabled, !withMacrosDisabled))
val wrapper1 = if (!withImplicitViewsDisabled) (callsiteTyper.context.withImplicitsEnabled[Tree] _) else (callsiteTyper.context.withImplicitsDisabled[Tree] _)
val wrapper2 = if (!withMacrosDisabled) (callsiteTyper.context.withMacrosEnabled[Tree] _) else (callsiteTyper.context.withMacrosDisabled[Tree] _)
def wrapper (tree: => Tree) = wrapper1(wrapper2(tree))
@@ -21,25 +20,24 @@ trait Typers {
// (also see reflect.runtime.ToolBoxes.typeCheckExpr for a workaround that might work for you)
wrapper(callsiteTyper.silent(_.typed(tree, mirror.analyzer.EXPRmode, pt)) match {
case mirror.analyzer.SilentResultValue(result) =>
- trace(result)
+ macroLogVerbose(result)
result
case error @ mirror.analyzer.SilentTypeError(_) =>
- trace(error.err.errMsg)
+ macroLogVerbose(error.err.errMsg)
if (!silent) throw new mirror.TypeError(error.err.errPos, error.err.errMsg)
mirror.EmptyTree
})
}
def inferImplicitValue(pt: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: Position = enclosingPosition): Tree = {
- def trace(msg: Any) = if (mirror.settings.Ymacrodebug.value) println(msg)
- trace("inferring implicit value of type %s, macros = %s".format(pt, !withMacrosDisabled))
+ macroLogVerbose("inferring implicit value of type %s, macros = %s".format(pt, !withMacrosDisabled))
import mirror.analyzer.SearchResult
val context = callsiteTyper.context
val wrapper1 = if (!withMacrosDisabled) (context.withMacrosEnabled[SearchResult] _) else (context.withMacrosDisabled[SearchResult] _)
def wrapper (inference: => SearchResult) = wrapper1(inference)
wrapper(mirror.analyzer.inferImplicit(mirror.EmptyTree, pt, true, false, context, !silent, pos)) match {
case failure if failure.tree.isEmpty =>
- trace("implicit search has failed. to find out the reason, turn on -Xlog-implicits")
+ macroLogVerbose("implicit search has failed. to find out the reason, turn on -Xlog-implicits")
if (context.hasErrors) throw new mirror.TypeError(context.errBuffer.head.errPos, context.errBuffer.head.errMsg)
mirror.EmptyTree
case success =>
@@ -48,8 +46,7 @@ trait Typers {
}
def inferImplicitView(tree: Tree, from: Type, to: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, reportAmbiguous: Boolean = true, pos: Position = enclosingPosition): Tree = {
- def trace(msg: Any) = if (mirror.settings.Ymacrodebug.value) println(msg)
- trace("inferring implicit view from %s to %s for %s, macros = %s, reportAmbiguous = %s".format(from, to, tree, !withMacrosDisabled, reportAmbiguous))
+ macroLogVerbose("inferring implicit view from %s to %s for %s, macros = %s, reportAmbiguous = %s".format(from, to, tree, !withMacrosDisabled, reportAmbiguous))
import mirror.analyzer.SearchResult
val context = callsiteTyper.context
val wrapper1 = if (!withMacrosDisabled) (context.withMacrosEnabled[SearchResult] _) else (context.withMacrosDisabled[SearchResult] _)
@@ -58,7 +55,7 @@ trait Typers {
val viewTpe = mirror.TypeRef(fun1.typeConstructor.prefix, fun1, List(from, to))
wrapper(mirror.analyzer.inferImplicit(tree, viewTpe, reportAmbiguous, true, context, !silent, pos)) match {
case failure if failure.tree.isEmpty =>
- trace("implicit search has failed. to find out the reason, turn on -Xlog-implicits")
+ macroLogVerbose("implicit search has failed. to find out the reason, turn on -Xlog-implicits")
if (context.hasErrors) throw new mirror.TypeError(context.errBuffer.head.errPos, context.errBuffer.head.errMsg)
mirror.EmptyTree
case success =>
diff --git a/src/compiler/scala/reflect/makro/util/Traces.scala b/src/compiler/scala/reflect/makro/util/Traces.scala
new file mode 100644
index 0000000000..2363cc4bac
--- /dev/null
+++ b/src/compiler/scala/reflect/makro/util/Traces.scala
@@ -0,0 +1,18 @@
+package scala.reflect.makro
+package util
+
+trait Traces {
+ def globalSettings: tools.nsc.Settings
+
+ // [Eugene] lots of ways to log:
+ // 1) trace(...)
+ // 2) log(...)
+ // 3) if (foo) { doStuff(); includingSomeLogs(); }
+ // what is the conventional way of unifying this?
+ val macroDebugLite = globalSettings.YmacrodebugLite.value
+ val macroDebugVerbose = globalSettings.YmacrodebugVerbose.value
+ val macroTraceLite = scala.tools.nsc.util.trace when (macroDebugLite || macroDebugVerbose)
+ val macroTraceVerbose = scala.tools.nsc.util.trace when macroDebugVerbose
+ @inline final def macroLogLite(msg: => Any) { if (macroDebugLite || macroDebugVerbose) println(msg) }
+ @inline final def macroLogVerbose(msg: => Any) { if (macroDebugVerbose) println(msg) }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/Errors.scala b/src/compiler/scala/reflect/reify/Errors.scala
index 1a881455f2..4466f281b8 100644
--- a/src/compiler/scala/reflect/reify/Errors.scala
+++ b/src/compiler/scala/reflect/reify/Errors.scala
@@ -10,8 +10,7 @@ trait Errors {
import mirror._
import definitions._
- lazy val defaultErrorPosition: Position =
- mirror.analyzer.openMacros.find(c => c.macroApplication.pos != NoPosition).map(_.macroApplication.pos).getOrElse(NoPosition)
+ def defaultErrorPosition = analyzer.enclosingMacroPosition
// expected errors: these can happen if the user casually writes whatever.reify(...)
// hence we don't crash here, but nicely report a typechecking error and bail out asap
diff --git a/src/compiler/scala/reflect/reify/codegen/Types.scala b/src/compiler/scala/reflect/reify/codegen/Types.scala
index 8fa24c5b00..1f336f4b0f 100644
--- a/src/compiler/scala/reflect/reify/codegen/Types.scala
+++ b/src/compiler/scala/reflect/reify/codegen/Types.scala
@@ -99,7 +99,7 @@ trait Types {
// if this fails, it might produce the dreaded "erroneous or inaccessible type" error
// to find out the whereabouts of the error run scalac with -Ydebug
if (reifyDebug) println("launching implicit search for %s.%s[%s]".format(prefix, tagClass.name, tpe))
- typer.resolveTypeTag(positionBearer.pos, prefix.tpe, tpe, concrete) match {
+ typer.resolveTypeTag(defaultErrorPosition, prefix.tpe, tpe, concrete) match {
case failure if failure.isEmpty =>
if (reifyDebug) println("implicit search was fruitless")
EmptyTree
diff --git a/src/compiler/scala/reflect/reify/codegen/Util.scala b/src/compiler/scala/reflect/reify/codegen/Util.scala
index 8d7cf39ff7..bb369a1adb 100644
--- a/src/compiler/scala/reflect/reify/codegen/Util.scala
+++ b/src/compiler/scala/reflect/reify/codegen/Util.scala
@@ -14,8 +14,6 @@ trait Util {
object reifiedNodePrinters extends { val global: mirror.type = mirror } with tools.nsc.ast.NodePrinters with NodePrinters
val reifiedNodeToString = reifiedNodePrinters.reifiedNodeToString
- val positionBearer = mirror.analyzer.openMacros.find(c => c.macroApplication.pos != NoPosition).map(_.macroApplication).getOrElse(EmptyTree).asInstanceOf[Tree]
-
def reifyList(xs: List[Any]): Tree =
mkList(xs map reify)
diff --git a/src/compiler/scala/reflect/reify/package.scala b/src/compiler/scala/reflect/reify/package.scala
index fa11c6313d..3f9d6200cd 100644
--- a/src/compiler/scala/reflect/reify/package.scala
+++ b/src/compiler/scala/reflect/reify/package.scala
@@ -31,8 +31,12 @@ package object reify {
def reifyErasure(global: Global)(typer0: global.analyzer.Typer, tpe: global.Type, concrete: Boolean = true): global.Tree = {
import global._
import definitions._
- val positionBearer = analyzer.openMacros.find(_.macroApplication.pos != NoPosition).map(_.macroApplication).getOrElse(EmptyTree).asInstanceOf[Tree]
- val inScope = typer0.context.withMacrosDisabled(typer0.resolveErasureTag(positionBearer.pos, tpe, concrete = concrete), typer0.resolveArrayTag(positionBearer.pos, tpe))
+ import analyzer.enclosingMacroPosition
+
+ def erasureTagInScope = typer0.context.withMacrosDisabled(typer0.resolveErasureTag(enclosingMacroPosition, tpe, concrete = concrete))
+ def arrayTagInScope = typer0.context.withMacrosDisabled(typer0.resolveArrayTag(enclosingMacroPosition, tpe))
+ val inScope = (erasureTagInScope, arrayTagInScope)
+
inScope match {
case (success, _) if !success.isEmpty =>
Select(success, nme.erasure)
@@ -44,7 +48,7 @@ package object reify {
val componentErasure = reifyErasure(global)(typer0, componentTpe, concrete)
gen.mkMethodCall(arrayClassMethod, List(componentErasure))
} else {
- if (tpe.isSpliceable && concrete) throw new ReificationError(positionBearer.pos, "tpe %s is an unresolved spliceable type".format(tpe))
+ if (tpe.isSpliceable && concrete) throw new ReificationError(enclosingMacroPosition, "tpe %s is an unresolved spliceable type".format(tpe))
var erasure = tpe.erasure
if (tpe.typeSymbol.isDerivedValueClass && global.phase.id < global.currentRun.erasurePhase.id) erasure = tpe
gen.mkNullaryCall(Predef_classOf, List(erasure))
diff --git a/src/compiler/scala/tools/cmd/program/DumpClass.scala b/src/compiler/scala/tools/cmd/program/DumpClass.scala
new file mode 100644
index 0000000000..a583f1d3ea
--- /dev/null
+++ b/src/compiler/scala/tools/cmd/program/DumpClass.scala
@@ -0,0 +1,40 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools
+package cmd
+package program
+
+import scala.reflect.internal.JvmClassInfo
+import scala.tools.nsc.io.Directory
+
+object DumpClass {
+ private val usage = """
+ |Usage: dump-class [options] <path> <path> ...
+ |
+ |Parses and dumps the bytecode of all classes found at the given paths.
+ |""".stripMargin
+
+ private val unaryOps = List(
+ "signatures" -> "dump signatures"
+ )
+ private val info = Simple.scalaProgramInfo("dump-class", usage)
+ private val spec = Simple(info, unaryOps, Nil, null)
+
+ def deepInfos(dir: String) = {
+ val files = Directory(dir).deepFiles.toList filter (_ hasExtension "class")
+ files.sortBy(_.path) map (f => (f.path, JvmClassInfo fromPath f.path))
+ }
+
+ def main(args: Array[String]): Unit = {
+ val runner = spec instance args
+ import runner._
+
+ if (args.isEmpty)
+ println(usage)
+ else
+ (residualArgs flatMap deepInfos) sortBy (_._1) map (_._2) foreach println
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala
index 108c8fcbfa..5d849b9622 100644
--- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala
+++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala
@@ -63,10 +63,14 @@ abstract class NodePrinters {
}
trait DefaultPrintAST extends PrintAST {
+ val printPos = settings.Xprintpos.value || settings.Yposdebug.value
+
+ def showNameAndPos(tree: NameTree) = showPosition(tree) + showName(tree.name)
def showDefTreeName(tree: DefTree) = showName(tree.name)
+ def showPosition(tree: Tree) = if (printPos) tree.pos.show else ""
def showFlags(tree: MemberDef) = flagsToString(tree.symbol.flags | tree.mods.flags)
- def showLiteral(lit: Literal) = lit.value.escapedStringValue
- def showTypeTree(tt: TypeTree) = "<tpt>" + emptyOrComment(showType(tt))
+ def showLiteral(lit: Literal) = showPosition(lit) + lit.value.escapedStringValue
+ def showTypeTree(tt: TypeTree) = showPosition(tt) + "<tpt>" + emptyOrComment(showType(tt))
def showName(name: Name) = name match {
case nme.EMPTY | tpnme.EMPTY => "<empty>"
case name => "\"" + name + "\""
@@ -97,17 +101,21 @@ abstract class NodePrinters {
private var level = 0
def showName(name: Name): String
+ def showPosition(tree: Tree): String
+ def showNameAndPos(tree: NameTree): String
def showDefTreeName(defTree: DefTree): String
def showFlags(tree: MemberDef): String
def showLiteral(lit: Literal): String
def showTypeTree(tt: TypeTree): String
def showAttributes(tree: Tree): String // symbol and type
- def showRefTreeName(tree: Tree): String = tree match {
- case SelectFromTypeTree(qual, name) => showRefTreeName(qual) + "#" + showName(name)
- case Select(qual, name) => showRefTreeName(qual) + "." + showName(name)
- case Ident(name) => showName(name)
- case _ => "" + tree
+ def showRefTreeName(tree: Tree): String = {
+ tree match {
+ case SelectFromTypeTree(qual, name) => showRefTreeName(qual) + "#" + showName(name)
+ case Select(qual, name) => showRefTreeName(qual) + "." + showName(name)
+ case id @ Ident(name) => showNameAndPos(id)
+ case _ => "" + tree
+ }
}
def showRefTree(tree: RefTree): String = {
def prefix0 = showRefTreeName(tree.qualifier)
@@ -116,7 +124,7 @@ abstract class NodePrinters {
case Select(_, _) => prefix0 + "."
case _ => ""
})
- prefix + showName(tree.name) + emptyOrComment(showAttributes(tree))
+ prefix + showNameAndPos(tree) + emptyOrComment(showAttributes(tree))
}
def emptyOrComment(s: String) = if (s == "") "" else " // " + s
@@ -191,8 +199,9 @@ abstract class NodePrinters {
}
}
+ def treePrefix(tree: Tree) = showPosition(tree) + tree.printingPrefix
def printMultiline(tree: Tree)(body: => Unit) {
- printMultiline(tree.printingPrefix, showAttributes(tree))(body)
+ printMultiline(treePrefix(tree), showAttributes(tree))(body)
}
def printMultiline(prefix: String, comment: String)(body: => Unit) {
printLine(prefix + "(", comment)
@@ -218,10 +227,12 @@ abstract class NodePrinters {
}
def printSingle(tree: Tree, name: Name) {
- println(tree.printingPrefix + "(" + showName(name) + ")" + showAttributes(tree))
+ println(treePrefix(tree) + "(" + showName(name) + ")" + showAttributes(tree))
}
def traverse(tree: Tree) {
+ showPosition(tree)
+
tree match {
case AppliedTypeTree(tpt, args) => applyCommon(tree, tpt, args)
case ApplyDynamic(fun, args) => applyCommon(tree, fun, args)
@@ -230,6 +241,19 @@ abstract class NodePrinters {
case Throw(Ident(name)) =>
printSingle(tree, name)
+ case b @ Bind(name, body) =>
+ printMultiline(tree) {
+ println(showDefTreeName(b))
+ traverse(body)
+ }
+
+ case ld @ LabelDef(name, params, rhs) =>
+ printMultiline(tree) {
+ showNameAndPos(ld)
+ traverseList("()", "params")(params)
+ traverse(rhs)
+ }
+
case Function(vparams, body) =>
printMultiline(tree) {
traverseList("()", "parameter")(vparams)
@@ -309,7 +333,7 @@ abstract class NodePrinters {
val ps0 = parents map { p =>
if (p.tpe eq null) p match {
case x: RefTree => showRefTree(x)
- case x => "" + x
+ case x => showPosition(x) + x
}
else showName(newTypeName(p.tpe.typeSymbol.fullName))
}
@@ -353,7 +377,7 @@ abstract class NodePrinters {
case _ =>
tree match {
case t: RefTree => println(showRefTree(t))
- case t if t.productArity == 0 => println(tree.printingPrefix)
+ case t if t.productArity == 0 => println(treePrefix(t))
case t => printMultiline(tree)(tree.productIterator foreach traverseAny)
}
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala
index 93fa9a60f6..f702f44338 100755
--- a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala
@@ -397,7 +397,7 @@ trait MarkupParsers {
/** xScalaPatterns ::= patterns
*/
- def xScalaPatterns: List[Tree] = escapeToScala(parser.seqPatterns(), "pattern")
+ def xScalaPatterns: List[Tree] = escapeToScala(parser.xmlSeqPatterns(), "pattern")
def reportSyntaxError(pos: Int, str: String) = parser.syntaxError(pos, str)
def reportSyntaxError(str: String) {
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index bca1cc4596..337ca7671c 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -1705,11 +1705,11 @@ self =>
* was threaded through methods as boolean seqOK.
*/
trait SeqContextSensitive extends PatternContextSensitive {
- /** Returns Some(tree) if it finds a star and prematurely ends parsing.
- * This is an artifact of old implementation which has proven difficult
- * to cleanly extract.
- */
- def interceptStarPattern(top: Tree): Option[Tree]
+ // is a sequence pattern _* allowed?
+ def isSequenceOK: Boolean
+
+ // are we in an XML pattern?
+ def isXML: Boolean = false
def functionArgType(): Tree = argType()
def argType(): Tree = {
@@ -1796,45 +1796,98 @@ self =>
/** {{{
* Pattern3 ::= SimplePattern
* | SimplePattern {Id [nl] SimplePattern}
- * SeqPattern3 ::= SeqSimplePattern [ `*' | `?' | `+' ]
- * | SeqSimplePattern {Id [nl] SeqSimplePattern}
* }}}
*/
def pattern3(): Tree = {
+ var top = simplePattern(badPattern3)
+ // after peekahead
+ def acceptWildStar() = atPos(top.pos.startOrPoint, in.prev.offset)(Star(stripParens(top)))
+ def peekahead() = {
+ in.prev copyFrom in
+ in.nextToken()
+ }
+ def pushback() = {
+ in.next copyFrom in
+ in copyFrom in.prev
+ }
+ // See SI-3189, SI-4832 for motivation. Cf SI-3480 for counter-motivation.
+ // TODO: dredge out the remnants of regexp patterns.
+ // /{/ peek for _*) or _*} (for xml escape)
+ if (isSequenceOK) {
+ top match {
+ case Ident(nme.WILDCARD) if (isRawStar) =>
+ peekahead()
+ in.token match {
+ case RBRACE if (isXML) => return acceptWildStar()
+ case RPAREN if (!isXML) => return acceptWildStar()
+ case _ => pushback()
+ }
+ case _ =>
+ }
+ }
val base = opstack
- var top = simplePattern()
- interceptStarPattern(top) foreach { x => return x }
-
while (isIdent && in.name != raw.BAR) {
- top = reduceStack(
- false, base, top, precedence(in.name), treeInfo.isLeftAssoc(in.name))
+ top = reduceStack(false, base, top, precedence(in.name), treeInfo.isLeftAssoc(in.name))
val op = in.name
opstack = OpInfo(top, op, in.offset) :: opstack
ident()
- top = simplePattern()
+ top = simplePattern(badPattern3)
}
stripParens(reduceStack(false, base, top, 0, true))
}
+ def badPattern3(): Tree = {
+ def isComma = in.token == COMMA
+ def isAnyBrace = in.token == RPAREN || in.token == RBRACE
+ val badStart = "illegal start of simple pattern"
+ // better recovery if don't skip delims of patterns
+ var skip = !(isComma || isAnyBrace)
+ val msg = if (!opstack.isEmpty && opstack.head.operator == nme.STAR) {
+ opstack.head.operand match {
+ case Ident(nme.WILDCARD) =>
+ if (isSequenceOK && isComma)
+ "bad use of _* (a sequence pattern must be the last pattern)"
+ else if (isSequenceOK && isAnyBrace) {
+ skip = true // do skip bad paren; scanner may skip bad brace already
+ "bad brace or paren after _*"
+ } else if (!isSequenceOK && isAnyBrace)
+ "bad use of _* (sequence pattern not allowed)"
+ else badStart
+ case _ =>
+ if (isSequenceOK && isAnyBrace)
+ "use _* to match a sequence"
+ else if (isComma || isAnyBrace)
+ "trailing * is not a valid pattern"
+ else badStart
+ }
+ } else {
+ badStart
+ }
+ syntaxErrorOrIncomplete(msg, skip)
+ errorPatternTree
+ }
/** {{{
* SimplePattern ::= varid
* | `_'
* | literal
* | XmlPattern
- * | StableId [TypeArgs] [`(' [SeqPatterns] `)']
+ * | StableId /[TypeArgs]/ [`(' [Patterns] `)']
+ * | StableId [`(' [Patterns] `)']
+ * | StableId [`(' [Patterns] `,' [varid `@'] `_' `*' `)']
* | `(' [Patterns] `)'
- * SimpleSeqPattern ::= varid
- * | `_'
- * | literal
- * | XmlPattern
- * | `<' xLiteralPattern
- * | StableId [TypeArgs] [`(' [SeqPatterns] `)']
- * | `(' [SeqPatterns] `)'
* }}}
*
* XXX: Hook for IDE
*/
def simplePattern(): Tree = {
+ // simple diagnostics for this entry point
+ def badStart(): Tree = {
+ syntaxErrorOrIncomplete("illegal start of simple pattern", true)
+ errorPatternTree
+ }
+ simplePattern(badStart)
+ }
+ def simplePattern(onError: () => Tree): Tree = {
val start = in.offset
in.token match {
case IDENTIFIER | BACKQUOTED_IDENT | THIS =>
@@ -1867,8 +1920,7 @@ self =>
case XMLSTART =>
xmlLiteralPattern()
case _ =>
- syntaxErrorOrIncomplete("illegal start of simple pattern", true)
- errorPatternTree
+ onError()
}
}
}
@@ -1879,16 +1931,16 @@ self =>
}
/** The implementation for parsing inside of patterns at points where sequences are allowed. */
object seqOK extends SeqContextSensitive {
- // See ticket #3189 for the motivation for the null check.
- // TODO: dredge out the remnants of regexp patterns.
- // ... and now this is back the way it was because it caused #3480.
- def interceptStarPattern(top: Tree): Option[Tree] =
- if (isRawStar) Some(atPos(top.pos.startOrPoint, in.skipToken())(Star(stripParens(top))))
- else None
+ val isSequenceOK = true
}
/** The implementation for parsing inside of patterns at points where sequences are disallowed. */
object noSeq extends SeqContextSensitive {
- def interceptStarPattern(top: Tree) = None
+ val isSequenceOK = false
+ }
+ /** For use from xml pattern, where sequence is allowed and encouraged. */
+ object xmlSeqOK extends SeqContextSensitive {
+ val isSequenceOK = true
+ override val isXML = true
}
/** These are default entry points into the pattern context sensitive methods:
* they are all initiated from non-pattern context.
@@ -1902,7 +1954,8 @@ self =>
/** Default entry points into some pattern contexts. */
def pattern(): Tree = noSeq.pattern()
def patterns(): List[Tree] = noSeq.patterns()
- def seqPatterns(): List[Tree] = seqOK.patterns() // Also called from xml parser
+ def seqPatterns(): List[Tree] = seqOK.patterns()
+ def xmlSeqPatterns(): List[Tree] = xmlSeqOK.patterns() // Called from xml parser
def argumentPatterns(): List[Tree] = inParens {
if (in.token == RPAREN) Nil
else seqPatterns()
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 6a5c4c92bc..91e31cae97 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -138,7 +138,7 @@ trait ScalaSettings extends AbsScalaSettings
val termConflict = ChoiceSetting ("-Yresolve-term-conflict", "strategy", "Resolve term conflicts", List("package", "object", "error"), "error")
val inline = BooleanSetting ("-Yinline", "Perform inlining when possible.")
val inlineHandlers = BooleanSetting ("-Yinline-handlers", "Perform exception handler inlining when possible.")
- val YinlinerWarnings= BooleanSetting ("-Yinline-warnings", "Emit inlining warnings. (Normally surpressed due to high volume)")
+ val YinlinerWarnings= BooleanSetting ("-Yinline-warnings", "Emit inlining warnings. (Normally surpressed due to high volume)")
val Xlinearizer = ChoiceSetting ("-Ylinearizer", "which", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo")
val log = PhasesSetting ("-Ylog", "Log operations during")
val Ylogcp = BooleanSetting ("-Ylog-classpath", "Output information about what classpath is being applied.")
@@ -172,7 +172,6 @@ trait ScalaSettings extends AbsScalaSettings
val YrichExes = BooleanSetting ("-Yrich-exceptions", "Fancier exceptions. Set source search path with -D" + sys.SystemProperties.traceSourcePath.key)
val Ybuilderdebug = ChoiceSetting ("-Ybuilder-debug", "manager", "Compile using the specified build manager.", List("none", "refined", "simple"), "none")
val Yreifycopypaste = BooleanSetting ("-Yreify-copypaste", "Dump the reified trees in copypasteable representation.")
- val Ymacrocopypaste = BooleanSetting ("-Ymacro-copypaste", "Dump macro expansions in copypasteable representation.")
val Yreplsync = BooleanSetting ("-Yrepl-sync", "Do not use asynchronous code for repl startup")
val Ynotnull = BooleanSetting ("-Ynotnull", "Enable (experimental and incomplete) scala.NotNull.")
val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overriden methods.")
@@ -193,7 +192,8 @@ trait ScalaSettings extends AbsScalaSettings
val Yidedebug = BooleanSetting("-Yide-debug", "Generate, validate and output trees using the interactive compiler.")
val Yinferdebug = BooleanSetting("-Yinfer-debug", "Trace type inference and implicit search.")
val Yissuedebug = BooleanSetting("-Yissue-debug", "Print stack traces when a context issues an error.")
- val Ymacrodebug = BooleanSetting("-Ymacro-debug", "Trace macro-related activities: compilation, generation of synthetics, classloading, expansion, exceptions.")
+ val YmacrodebugLite = BooleanSetting("-Ymacro-debug-lite", "Trace essential macro-related activities.")
+ val YmacrodebugVerbose = BooleanSetting("-Ymacro-debug-verbose", "Trace all macro-related activities: compilation, generation of synthetics, classloading, expansion, exceptions.")
val Ypmatdebug = BooleanSetting("-Ypmat-debug", "Trace all pattern matcher activity.")
val Yposdebug = BooleanSetting("-Ypos-debug", "Trace position validation.")
val Yreifydebug = BooleanSetting("-Yreify-debug", "Trace reification.")
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 14f09d9dc9..1b8a43bf27 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -10,6 +10,7 @@ import scala.compat.Platform.EOL
import scala.reflect.makro.runtime.{Context => MacroContext}
import scala.reflect.runtime.Mirror
import util.Statistics._
+import scala.reflect.makro.util._
/**
* Code to deal with macros, namely with:
@@ -36,13 +37,12 @@ import util.Statistics._
* (Expr(elems))
* (TypeTag(Int))
*/
-trait Macros { self: Analyzer =>
+trait Macros extends Traces {
+ self: Analyzer =>
+
import global._
import definitions._
-
- val macroDebug = settings.Ymacrodebug.value
- val macroCopypaste = settings.Ymacrocopypaste.value
- val macroTrace = scala.tools.nsc.util.trace when macroDebug
+ def globalSettings = global.settings
val globalMacroCache = collection.mutable.Map[Any, Any]()
val perRunMacroCache = perRunCaches.newMap[Symbol, collection.mutable.Map[Any, Any]]
@@ -136,11 +136,11 @@ trait Macros { self: Analyzer =>
}
import SigGenerator._
- macroTrace("generating macroImplSigs for: ")(macroDef)
- macroTrace("tparams are: ")(tparams)
- macroTrace("vparamss are: ")(vparamss)
- macroTrace("retTpe is: ")(retTpe)
- macroTrace("macroImplSigs are: ")(paramsss, implRetTpe)
+ macroTraceVerbose("generating macroImplSigs for: ")(macroDef)
+ macroTraceVerbose("tparams are: ")(tparams)
+ macroTraceVerbose("vparamss are: ")(vparamss)
+ macroTraceVerbose("retTpe is: ")(retTpe)
+ macroTraceVerbose("macroImplSigs are: ")(paramsss, implRetTpe)
}
private def transformTypeTagEvidenceParams(paramss: List[List[Symbol]], transform: (Symbol, Symbol) => Option[Symbol]): List[List[Symbol]] = {
@@ -183,7 +183,7 @@ trait Macros { self: Analyzer =>
*/
def typedMacroBody(typer: Typer, ddef: DefDef): Tree = {
import typer.context
- if (macroDebug) println("typechecking macro def %s at %s".format(ddef.symbol, ddef.pos))
+ macroLogVerbose("typechecking macro def %s at %s".format(ddef.symbol, ddef.pos))
if (!typer.checkFeature(ddef.pos, MacrosFeature, immediate = true)) {
ddef.symbol setFlag IS_ERROR
@@ -267,7 +267,7 @@ trait Macros { self: Analyzer =>
val rhs = ddef.rhs
validatePreTyper(rhs)
- if (hasErrors) macroTrace("macro def failed to satisfy trivial preconditions: ")(macroDef)
+ if (hasErrors) macroTraceVerbose("macro def failed to satisfy trivial preconditions: ")(macroDef)
// we use typed1 instead of typed, because otherwise adapt is going to mess us up
// if adapt sees <qualifier>.<method>, it will want to perform eta-expansion and will fail
@@ -284,12 +284,7 @@ trait Macros { self: Analyzer =>
case Success(expanded) =>
try {
val typechecked = typer.typed1(expanded, EXPRmode, WildcardType)
- if (macroDebug) {
- println("typechecked1:")
- println(typechecked)
- println(showRaw(typechecked))
- }
-
+ macroLogVerbose("typechecked1:%n%s%n%s".format(typechecked, showRaw(typechecked)))
typechecked
} finally {
openMacros = openMacros.tail
@@ -312,7 +307,7 @@ trait Macros { self: Analyzer =>
var rhs1 = typecheckRhs(rhs)
def typecheckedWithErrors = (rhs1 exists (_.isErroneous)) || reporter.ERROR.count != prevNumErrors
hasErrors = hasErrors || typecheckedWithErrors
- if (typecheckedWithErrors) macroTrace("body of a macro def failed to typecheck: ")(ddef)
+ if (typecheckedWithErrors) macroTraceVerbose("body of a macro def failed to typecheck: ")(ddef)
val macroImpl = rhs1.symbol
macroDef withAnnotation AnnotationInfo(MacroImplAnnotation.tpe, List(rhs1), Nil)
@@ -330,7 +325,7 @@ trait Macros { self: Analyzer =>
validatePostTyper(rhs1)
}
if (hasErrors)
- macroTrace("macro def failed to satisfy trivial preconditions: ")(macroDef)
+ macroTraceVerbose("macro def failed to satisfy trivial preconditions: ")(macroDef)
}
if (!hasErrors) {
@@ -352,7 +347,7 @@ trait Macros { self: Analyzer =>
compatibilityError("number of parameter sections differ")
def checkSubType(slot: String, reqtpe: Type, acttpe: Type): Unit = {
- val ok = if (macroDebug) {
+ val ok = if (macroDebugVerbose) {
if (reqtpe eq acttpe) println(reqtpe + " <: " + acttpe + "?" + EOL + "true")
withTypesExplained(reqtpe <:< acttpe)
} else reqtpe <:< acttpe
@@ -437,7 +432,7 @@ trait Macros { self: Analyzer =>
val implicitParams = actparamss.flatten filter (_.isImplicit)
if (implicitParams.length > 0) {
reportError(implicitParams.head.pos, "macro implementations cannot have implicit parameters other than TypeTag evidences")
- macroTrace("macro def failed to satisfy trivial preconditions: ")(macroDef)
+ macroTraceVerbose("macro def failed to satisfy trivial preconditions: ")(macroDef)
}
if (!hasErrors) {
@@ -458,9 +453,9 @@ trait Macros { self: Analyzer =>
"\n found : "+showMeth(actparamss, actres, false)+
"\n"+addendum)
- macroTrace("considering " + reqparamsss.length + " possibilities of compatible macro impl signatures for macro def: ")(ddef.name)
+ macroTraceVerbose("considering " + reqparamsss.length + " possibilities of compatible macro impl signatures for macro def: ")(ddef.name)
val results = reqparamsss map (checkCompatibility(_, actparamss, reqres, actres))
- if (macroDebug) (reqparamsss zip results) foreach { case (reqparamss, result) =>
+ if (macroDebugVerbose) (reqparamsss zip results) foreach { case (reqparamss, result) =>
println("%s %s".format(if (result.isEmpty) "[ OK ]" else "[FAILED]", reqparamss))
result foreach (errorMsg => println(" " + errorMsg))
}
@@ -472,7 +467,7 @@ trait Macros { self: Analyzer =>
compatibilityError(mostRelevantMessage)
} else {
assert((results filter (_.isEmpty)).length == 1, results)
- if (macroDebug) (reqparamsss zip results) filter (_._2.isEmpty) foreach { case (reqparamss, result) =>
+ if (macroDebugVerbose) (reqparamsss zip results) filter (_._2.isEmpty) foreach { case (reqparamss, result) =>
println("typechecked macro impl as: " + reqparamss)
}
}
@@ -596,11 +591,11 @@ trait Macros { self: Analyzer =>
val libraryClassLoader = {
if (settings.XmacroPrimaryClasspath.value != "") {
- if (macroDebug) println("primary macro mirror: initializing from -Xmacro-primary-classpath: %s".format(settings.XmacroPrimaryClasspath.value))
+ macroLogVerbose("primary macro mirror: initializing from -Xmacro-primary-classpath: %s".format(settings.XmacroPrimaryClasspath.value))
val classpath = toURLs(settings.XmacroFallbackClasspath.value)
ScalaClassLoader.fromURLs(classpath, self.getClass.getClassLoader)
} else {
- if (macroDebug) println("primary macro mirror: initializing from -cp: %s".format(global.classPath.asURLs))
+ macroLogVerbose("primary macro mirror: initializing from -cp: %s".format(global.classPath.asURLs))
val classpath = global.classPath.asURLs
var loader: ClassLoader = ScalaClassLoader.fromURLs(classpath, self.getClass.getClassLoader)
@@ -626,7 +621,7 @@ trait Macros { self: Analyzer =>
throw new UnsupportedOperationException("Scala reflection not available on this platform")
val fallbackClassLoader = {
- if (macroDebug) println("fallback macro mirror: initializing from -Xmacro-fallback-classpath: %s".format(settings.XmacroFallbackClasspath.value))
+ macroLogVerbose("fallback macro mirror: initializing from -Xmacro-fallback-classpath: %s".format(settings.XmacroFallbackClasspath.value))
val classpath = toURLs(settings.XmacroFallbackClasspath.value)
ScalaClassLoader.fromURLs(classpath, self.getClass.getClassLoader)
}
@@ -649,24 +644,24 @@ trait Macros { self: Analyzer =>
private def macroRuntime(macroDef: Symbol): Option[MacroRuntime] =
macroRuntimesCache.getOrElseUpdate(macroDef, {
val runtime = {
- macroTrace("looking for macro implementation: ")(macroDef)
- macroTrace("macroDef is annotated with: ")(macroDef.annotations)
+ macroTraceVerbose("looking for macro implementation: ")(macroDef)
+ macroTraceVerbose("macroDef is annotated with: ")(macroDef.annotations)
val ann = macroDef.getAnnotation(MacroImplAnnotation)
if (ann == None) {
- macroTrace("@macroImpl annotation is missing (this means that macro definition failed to typecheck)")(macroDef)
+ macroTraceVerbose("@macroImpl annotation is missing (this means that macro definition failed to typecheck)")(macroDef)
return None
}
val macroImpl = ann.get.args(0).symbol
if (macroImpl == NoSymbol) {
- macroTrace("@macroImpl annotation is malformed (this means that macro definition failed to typecheck)")(macroDef)
+ macroTraceVerbose("@macroImpl annotation is malformed (this means that macro definition failed to typecheck)")(macroDef)
return None
}
- if (macroDebug) println("resolved implementation %s at %s".format(macroImpl, macroImpl.pos))
+ macroLogVerbose("resolved implementation %s at %s".format(macroImpl, macroImpl.pos))
if (macroImpl.isErroneous) {
- macroTrace("macro implementation is erroneous (this means that either macro body or macro implementation signature failed to typecheck)")(macroDef)
+ macroTraceVerbose("macro implementation is erroneous (this means that either macro body or macro implementation signature failed to typecheck)")(macroDef)
return None
}
@@ -680,14 +675,14 @@ trait Macros { self: Analyzer =>
// however, the code below doesn't account for these guys, because it'd take a look of time to get it right
// for now I leave it as a todo and move along to more the important stuff
- macroTrace("loading implementation class from %s: ".format(macroMirror))(macroImpl.owner.fullName)
- macroTrace("classloader is: ")("%s of type %s".format(macroMirror.classLoader, if (macroMirror.classLoader != null) macroMirror.classLoader.getClass.toString else "primordial classloader"))
+ macroTraceVerbose("loading implementation class from %s: ".format(macroMirror))(macroImpl.owner.fullName)
+ macroTraceVerbose("classloader is: ")("%s of type %s".format(macroMirror.classLoader, if (macroMirror.classLoader != null) macroMirror.classLoader.getClass.toString else "primordial classloader"))
def inferClasspath(cl: ClassLoader) = cl match {
case cl: java.net.URLClassLoader => "[" + (cl.getURLs mkString ",") + "]"
case null => "[" + scala.tools.util.PathResolver.Environment.javaBootClassPath + "]"
case _ => "<unknown>"
}
- macroTrace("classpath is: ")(inferClasspath(macroMirror.classLoader))
+ macroTraceVerbose("classpath is: ")(inferClasspath(macroMirror.classLoader))
// [Eugene] relies on the fact that macro implementations can only be defined in static classes
// [Martin to Eugene] There's similar logic buried in Symbol#flatname. Maybe we can refactor?
@@ -711,7 +706,7 @@ trait Macros { self: Analyzer =>
val implClassName = classfile(macroImpl.owner)
val implClassSymbol: macroMirror.Symbol = macroMirror.symbolForName(implClassName)
- if (macroDebug) {
+ if (macroDebugVerbose) {
println("implClassSymbol is: " + implClassSymbol.fullNameString)
if (implClassSymbol != macroMirror.NoSymbol) {
@@ -723,7 +718,7 @@ trait Macros { self: Analyzer =>
}
val implObjSymbol = implClassSymbol.companionModule
- macroTrace("implObjSymbol is: ")(implObjSymbol.fullNameString)
+ macroTraceVerbose("implObjSymbol is: ")(implObjSymbol.fullNameString)
if (implObjSymbol == macroMirror.NoSymbol) None
else {
@@ -733,29 +728,27 @@ trait Macros { self: Analyzer =>
val implObjClass = java.lang.Class.forName(implClassName, true, macroMirror.classLoader)
implObjClass getField "MODULE$" get null
} catch {
- case ex: NoSuchFieldException => macroTrace("exception when loading implObj: ")(ex); null
- case ex: NoClassDefFoundError => macroTrace("exception when loading implObj: ")(ex); null
- case ex: ClassNotFoundException => macroTrace("exception when loading implObj: ")(ex); null
+ case ex: NoSuchFieldException => macroTraceVerbose("exception when loading implObj: ")(ex); null
+ case ex: NoClassDefFoundError => macroTraceVerbose("exception when loading implObj: ")(ex); null
+ case ex: ClassNotFoundException => macroTraceVerbose("exception when loading implObj: ")(ex); null
}
if (implObj == null) None
else {
val implMethSymbol = implObjSymbol.info.member(macroMirror.newTermName(macroImpl.name.toString))
- if (macroDebug) {
- println("implMethSymbol is: " + implMethSymbol.fullNameString)
- println("jimplMethSymbol is: " + macroMirror.methodToJava(implMethSymbol))
- }
+ macroLogVerbose("implMethSymbol is: " + implMethSymbol.fullNameString)
+ macroLogVerbose("jimplMethSymbol is: " + macroMirror.methodToJava(implMethSymbol))
if (implMethSymbol == macroMirror.NoSymbol) None
else {
- if (macroDebug) println("successfully loaded macro impl as (%s, %s)".format(implObj, implMethSymbol))
+ macroLogVerbose("successfully loaded macro impl as (%s, %s)".format(implObj, implMethSymbol))
Some((implObj, implMethSymbol))
}
}
}
} catch {
case ex: ClassNotFoundException =>
- macroTrace("implementation class failed to load: ")(ex.toString)
+ macroTraceVerbose("implementation class failed to load: ")(ex.toString)
None
}
}
@@ -767,7 +760,7 @@ trait Macros { self: Analyzer =>
Some(runtime _)
case None =>
if (settings.XmacroFallbackClasspath.value != "") {
- if (macroDebug) println("trying to load macro implementation from the fallback mirror: %s".format(settings.XmacroFallbackClasspath.value))
+ macroLogVerbose("trying to load macro implementation from the fallback mirror: %s".format(settings.XmacroFallbackClasspath.value))
val fallback = loadMacroImpl(fallbackMirror)
fallback match {
case Some((implObj, implMethSymbol)) =>
@@ -827,13 +820,13 @@ trait Macros { self: Analyzer =>
collectMacroArgs(expandee)
val context = expandee.attachmentOpt[MacroAttachment].flatMap(_.macroContext).getOrElse(macroContext(typer, prefixTree, expandee))
var argss: List[List[Any]] = List(context) :: exprArgs.toList
- macroTrace("argss: ")(argss)
+ macroTraceVerbose("argss: ")(argss)
val ann = macroDef.getAnnotation(MacroImplAnnotation).getOrElse(throw new Error("assertion failed. %s: %s".format(macroDef, macroDef.annotations)))
val macroImpl = ann.args(0).symbol
var paramss = macroImpl.paramss
val tparams = macroImpl.typeParams
- macroTrace("paramss: ")(paramss)
+ macroTraceVerbose("paramss: ")(paramss)
// we need to take care of all possible combos of nullary/empty-paramlist macro defs vs nullary/empty-arglist invocations
// nullary def + nullary invocation => paramss and argss match, everything is okay
@@ -845,7 +838,7 @@ trait Macros { self: Analyzer =>
val isEmptyParamlistDef = paramss_without_evidences.nonEmpty && paramss_without_evidences.last.isEmpty
val isEmptyArglistInvocation = argss.nonEmpty && argss.last.isEmpty
if (isEmptyParamlistDef && !isEmptyArglistInvocation) {
- if (macroDebug) println("isEmptyParamlistDef && !isEmptyArglistInvocation: appending a List() to argss")
+ macroLogVerbose("isEmptyParamlistDef && !isEmptyArglistInvocation: appending a List() to argss")
argss = argss :+ Nil
}
@@ -890,7 +883,7 @@ trait Macros { self: Analyzer =>
macroDef.owner)
} else
implRefTarg.tpe
- if (macroDebug) println("resolved tparam %s as %s".format(tparam, tpe))
+ macroLogVerbose("resolved tparam %s as %s".format(tparam, tpe))
resolved(tparam) = tpe
param.tpe.typeSymbol match {
case definitions.TypeTagClass =>
@@ -919,7 +912,7 @@ trait Macros { self: Analyzer =>
else as
}
val rawArgs = rawArgss.flatten
- macroTrace("rawArgs: ")(rawArgs)
+ macroTraceVerbose("rawArgs: ")(rawArgs)
Some(rawArgs)
}
@@ -927,16 +920,7 @@ trait Macros { self: Analyzer =>
* See more informations in comments to ``openMacros'' in ``scala.reflect.makro.Context''.
*/
var openMacros = List[MacroContext]()
- private def openMacroPos = openMacros map (_.expandee.pos) find (_ ne NoPosition) getOrElse NoPosition
-
- // !!! YOu should use a method like this which manages the stack.
- // That you presently need to spread this logic out is a major
- // design flaw.
- private def pushMacroContext[T](mc: MacroContext)(body: => T): T = {
- openMacros ::= mc
- try body
- finally openMacros = openMacros.tail
- }
+ def enclosingMacroPosition = openMacros map (_.macroApplication.pos) find (_ ne NoPosition) getOrElse NoPosition
/** Performs macro expansion:
* 1) Checks whether the expansion needs to be delayed (see ``mustDelayMacroExpansion'')
@@ -945,13 +929,13 @@ trait Macros { self: Analyzer =>
* 4) Checks that the result is a tree bound to this universe
* 5) Typechecks the result against the return type of the macro definition
*
- * If -Ymacro-debug is enabled, you will get detailed log of how exactly this function
+ * If -Ymacro-debug-lite is enabled, you will get basic notifications about macro expansion
+ * along with macro expansions logged in the form that can be copy/pasted verbatim into REPL.
+ *
+ * If -Ymacro-debug-verbose is enabled, you will get detailed log of how exactly this function
* performs class loading and method resolution in order to load the macro implementation.
* The log will also include other non-trivial steps of macro expansion.
*
- * If -Ymacro-copypaste is enabled along with -Ymacro-debug, you will get macro expansions
- * logged in the form that can be copy/pasted verbatim into REPL (useful for debugging!).
- *
* @return
* the expansion result if the expansion has been successful,
* the fallback method invocation if the expansion has been unsuccessful, but there is a fallback,
@@ -963,7 +947,7 @@ trait Macros { self: Analyzer =>
def macroExpand(typer: Typer, expandee: Tree, mode: Int = EXPRmode, pt: Type = WildcardType): Tree = {
def fail(what: String, tree: Tree): Tree = {
val err = typer.context.errBuffer.head
- this.fail(typer, tree, "failed to perform %s: %s at %s".format(what, err.errMsg, err.errPos))
+ this.fail(typer, tree, "failed to %s: %s at %s".format(what, err.errMsg, err.errPos))
return expandee
}
val start = startTimer(macroExpandNanos)
@@ -984,31 +968,23 @@ trait Macros { self: Analyzer =>
}
if (isNullaryInvocation) expectedTpe match {
case NullaryMethodType(restpe) =>
- macroTrace("nullary invocation of a nullary method. unwrapping expectedTpe from " + expectedTpe + " to: ")(restpe)
+ macroTraceVerbose("nullary invocation of a nullary method. unwrapping expectedTpe from " + expectedTpe + " to: ")(restpe)
expectedTpe = restpe
case MethodType(Nil, restpe) =>
- macroTrace("nullary invocation of a method with an empty parameter list. unwrapping expectedTpe from " + expectedTpe + " to: ")(restpe)
+ macroTraceVerbose("nullary invocation of a method with an empty parameter list. unwrapping expectedTpe from " + expectedTpe + " to: ")(restpe)
expectedTpe = restpe
case _ => ;
}
- if (macroDebug) println("typechecking1 against %s: %s".format(expectedTpe, expanded))
+ macroLogVerbose("typechecking1 against %s: %s".format(expectedTpe, expanded))
var typechecked = typer.context.withImplicitsEnabled(typer.typed(expanded, EXPRmode, expectedTpe))
- if (typer.context.hasErrors) fail("typecheck1", expanded)
- if (macroDebug) {
- println("typechecked1:")
- println(typechecked)
- println(showRaw(typechecked))
- }
+ if (typer.context.hasErrors) fail("typecheck against macro def return type", expanded)
+ macroLogVerbose("typechecked1:%n%s%n%s".format(typechecked, showRaw(typechecked)))
- if (macroDebug) println("typechecking2 against %s: %s".format(pt, expanded))
+ macroLogVerbose("typechecking2 against %s: %s".format(pt, expanded))
typechecked = typer.context.withImplicitsEnabled(typer.typed(typechecked, EXPRmode, pt))
- if (typer.context.hasErrors) fail("typecheck2", expanded)
- if (macroDebug) {
- println("typechecked2:")
- println(typechecked)
- println(showRaw(typechecked))
- }
+ if (typer.context.hasErrors) fail("typecheck against expected type", expanded)
+ macroLogVerbose("typechecked2:%n%s%n%s".format(typechecked, showRaw(typechecked)))
typechecked
} finally {
@@ -1033,11 +1009,9 @@ trait Macros { self: Analyzer =>
private def Cancel(expandee: Tree) = Other(expandee)
private def Failure(expandee: Tree) = Other(expandee)
private def fail(typer: Typer, expandee: Tree, msg: String = null) = {
- if (macroDebug || macroCopypaste) {
- var msg1 = if (msg != null && (msg contains "exception during macro expansion")) msg.split(EOL).drop(1).headOption.getOrElse("?") else msg
- if (macroDebug) println("macro expansion has failed: %s".format(msg1))
- }
- val pos = if (expandee.pos != NoPosition) expandee.pos else openMacros.find(c => c.expandee.pos != NoPosition).map(_.expandee.pos).getOrElse(NoPosition)
+ def msgForLog = if (msg != null && (msg contains "exception during macro expansion")) msg.split(EOL).drop(1).headOption.getOrElse("?") else msg
+ macroLogVerbose("macro expansion has failed: %s".format(msgForLog))
+ val pos = if (expandee.pos != NoPosition) expandee.pos else enclosingMacroPosition
if (msg != null) typer.context.error(pos, msg)
typer.infer.setError(expandee)
Failure(expandee)
@@ -1058,7 +1032,7 @@ trait Macros { self: Analyzer =>
// there is no sense to expand the macro itself => it will only make matters worse
if (expandee.symbol.isErroneous || (expandee exists (_.isErroneous))) {
val reason = if (expandee.symbol.isErroneous) "incompatible macro implementation" else "erroneous arguments"
- macroTrace("cancelled macro expansion because of %s: ".format(reason))(expandee)
+ macroTraceVerbose("cancelled macro expansion because of %s: ".format(reason))(expandee)
return Cancel(typer.infer.setError(expandee))
}
@@ -1092,7 +1066,7 @@ trait Macros { self: Analyzer =>
val wasDelayed = isDelayed(expandee)
val undetparams = calculateUndetparams(expandee)
val nowDelayed = !typer.context.macrosEnabled || undetparams.nonEmpty
-
+
def failExpansion(msg: String = null) = fail(typer, expandee, msg)
def performExpansion(args: List[Any]): MacroExpansionResult = {
val numErrors = reporter.ERROR.count
@@ -1104,17 +1078,18 @@ trait Macros { self: Analyzer =>
failExpansion() // errors have been reported by the macro itself
else expanded match {
case expanded: Expr[_] =>
- if (macroDebug) println("original:")
- macroDebugLog("" + expanded.tree + "\n" + showRaw(expanded.tree))
+ macroLogVerbose("original:")
+ macroLogVerbose("" + expanded.tree + "\n" + showRaw(expanded.tree))
freeTerms(expanded.tree) foreach issueFreeError
freeTypes(expanded.tree) foreach issueFreeError
+ if (hasNewErrors) failExpansion()
+
// inherit the position from the first position-ful expandee in macro callstack
// this is essential for sane error messages
// now macro expansion gets typechecked against the macro definition return type
// however, this happens in macroExpand, not here in macroExpand1
- if (hasNewErrors) failExpansion()
- else Success(atPos(openMacroPos.focus)(expanded.tree))
+ else Success(atPos(enclosingMacroPosition.focus)(expanded.tree))
case _ =>
failExpansion(
"macro must return a compiler-specific expr; returned value is " + (
@@ -1130,11 +1105,11 @@ trait Macros { self: Analyzer =>
else Skip(macroExpandAll(typer, expandee))
}
else {
- macroDebugLog("typechecking macro expansion %s at %s".format(expandee, expandee.pos))
+ macroLogVerbose("typechecking macro expansion %s at %s".format(expandee, expandee.pos))
macroArgs(typer, expandee).fold(failExpansion(): MacroExpansionResult) {
case args @ ((context: MacroContext) :: _) =>
if (nowDelayed) {
- macroDebugLog("macro expansion is delayed: %s".format(expandee))
+ macroLogVerbose("macro expansion is delayed: %s".format(expandee))
delayed += expandee -> undetparams
// need to save typer context for `macroExpandAll`
// need to save macro context to preserve enclosures
@@ -1144,7 +1119,9 @@ trait Macros { self: Analyzer =>
else {
// adding stuff to openMacros is easy, but removing it is a nightmare
// it needs to be sprinkled over several different code locations
- openMacros ::= args.head.asInstanceOf[MacroContext]
+ // why? https://github.com/scala/scala/commit/bd3eacbae21f39b1ac7fe8ade4ed71fa98e1a28d#L2R1137
+ // todo. will be improved
+ openMacros ::= context
var isSuccess = false
try performExpansion(args) match {
case x: Success => isSuccess = true ; x
@@ -1158,7 +1135,7 @@ trait Macros { self: Analyzer =>
}
}
}
-
+
try macroExpandInternal
catch { case ex => handleMacroExpansionException(typer, expandee, ex) }
}
@@ -1179,7 +1156,7 @@ trait Macros { self: Analyzer =>
case first :: _ =>
Some(Select(qual, name) setPos tree.pos setSymbol first)
case _ =>
- macroTrace("macro is not overridden: ")(tree)
+ macroTraceVerbose("macro is not overridden: ")(tree)
notFound()
}
case Apply(fn, args) =>
@@ -1193,33 +1170,29 @@ trait Macros { self: Analyzer =>
case _ => None
}
case _ =>
- macroTrace("unexpected tree in fallback: ")(tree)
+ macroTraceVerbose("unexpected tree in fallback: ")(tree)
notFound()
}
}
fallBackToOverridden(expandee) match {
case Some(tree1) =>
- macroTrace("falling back to: ")(tree1)
+ macroTraceVerbose("falling back to: ")(tree1)
currentRun.macroExpansionFailed = true
Fallback(tree1)
case None =>
fail(typer, expandee)
}
}
-
- @inline final def macroDebugLog(msg: => String) {
- if (macroDebug || macroCopypaste) println(msg)
- }
- private def handleMacroExpansionException(typer: Typer, expandee: Tree, ex: Throwable): MacroExpansionResult = {
+ private def handleMacroExpansionException(typer: Typer, expandee: Tree, ex: Throwable): MacroExpansionResult = {
// [Eugene] any ideas about how to improve this one?
val realex = ReflectionUtils.unwrapThrowable(ex)
realex match {
case realex: reflect.makro.runtime.AbortMacroException =>
- macroDebugLog("macro expansion has failed: %s".format(realex.msg))
+ macroLogVerbose("macro expansion has failed: %s".format(realex.msg))
fail(typer, expandee) // error has been reported by abort
case err: TypeError =>
- macroDebugLog("macro expansion has failed: %s at %s".format(err.msg, err.pos))
+ macroLogVerbose("macro expansion has failed: %s at %s".format(err.msg, err.pos))
throw err // error should be propagated, don't report
case _ =>
val message = {
@@ -1271,24 +1244,24 @@ trait Macros { self: Analyzer =>
if (sub.symbol != null) traverse(sub.symbol)
if (sub.tpe != null) sub.tpe foreach (sub => traverse(sub.typeSymbol))
})
- if (macroDebug) println("calculateUndetparams: %s".format(calculated))
+ macroLogVerbose("calculateUndetparams: %s".format(calculated))
calculated map (_.id)
}
private val undetparams = perRunCaches.newSet[Int]
def notifyUndetparamsAdded(newUndets: List[Symbol]): Unit = {
undetparams ++= newUndets map (_.id)
- if (macroDebug) newUndets foreach (sym => println("undetParam added: %s".format(sym)))
+ if (macroDebugVerbose) newUndets foreach (sym => println("undetParam added: %s".format(sym)))
}
def notifyUndetparamsInferred(undetNoMore: List[Symbol], inferreds: List[Type]): Unit = {
undetparams --= undetNoMore map (_.id)
- if (macroDebug) (undetNoMore zip inferreds) foreach {case (sym, tpe) => println("undetParam inferred: %s as %s".format(sym, tpe))}
+ if (macroDebugVerbose) (undetNoMore zip inferreds) foreach { case (sym, tpe) => println("undetParam inferred: %s as %s".format(sym, tpe))}
if (!delayed.isEmpty)
delayed.toList foreach {
case (expandee, undetparams) if !undetparams.isEmpty =>
undetparams --= undetNoMore map (_.id)
if (undetparams.isEmpty) {
hasPendingMacroExpansions = true
- macroTrace("macro expansion is pending: ")(expandee)
+ macroTraceVerbose("macro expansion is pending: ")(expandee)
}
case _ =>
// do nothing
diff --git a/src/compiler/scala/tools/util/StringOps.scala b/src/compiler/scala/tools/util/StringOps.scala
index 02eb364abe..725e0afb79 100644
--- a/src/compiler/scala/tools/util/StringOps.scala
+++ b/src/compiler/scala/tools/util/StringOps.scala
@@ -25,6 +25,16 @@ trait StringOps {
val ys = oempty(xs: _*)
if (ys.isEmpty) orElse else ys mkString sep
}
+ def trimTrailingSpace(s: String) = {
+ if (s.length == 0 || !s.charAt(s.length - 1).isWhitespace) s
+ else {
+ var idx = s.length - 1
+ while (idx >= 0 && s.charAt(idx).isWhitespace)
+ idx -= 1
+
+ s.substring(0, idx + 1)
+ }
+ }
def decompose(str: String, sep: Char): List[String] = {
def ws(start: Int): List[String] =