summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2014-02-16 16:58:28 +0100
committerEugene Burmako <xeno.by@gmail.com>2014-02-16 19:25:38 +0100
commit862f7709cdabd82327ca0f37a480884c88f96be7 (patch)
tree688717816eeee19ddb391f1009c82d9b6f09f224 /src/compiler/scala/tools
parent2fc0164a5e777a0495c1801d8d38d60158ec2a77 (diff)
parent6ef6c96eff2f0d2f505d45a1436d73a960193076 (diff)
downloadscala-862f7709cdabd82327ca0f37a480884c88f96be7.tar.gz
scala-862f7709cdabd82327ca0f37a480884c88f96be7.tar.bz2
scala-862f7709cdabd82327ca0f37a480884c88f96be7.zip
Merge remote-tracking branch 'origin/master' into topic/palladium0
Conflicts: src/compiler/scala/reflect/macros/compiler/Resolvers.scala src/compiler/scala/reflect/macros/contexts/Typers.scala src/compiler/scala/tools/reflect/ToolBoxFactory.scala src/reflect/scala/reflect/api/BuildUtils.scala
Diffstat (limited to 'src/compiler/scala/tools')
-rw-r--r--src/compiler/scala/tools/nsc/ScriptRunner.scala4
-rw-r--r--src/compiler/scala/tools/nsc/ast/Printers.scala6
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala11
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala127
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala274
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala27
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala28
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala93
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala25
-rw-r--r--src/compiler/scala/tools/reflect/FormatInterpolator.scala51
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala126
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala41
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala28
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala25
19 files changed, 443 insertions, 436 deletions
diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala
index d553d71bf5..c2d62db558 100644
--- a/src/compiler/scala/tools/nsc/ScriptRunner.scala
+++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala
@@ -19,7 +19,7 @@ import util.Exceptional.unwrap
* exec scala "$0" "$@"
* !#
* Console.println("Hello, world!")
- * argv.toList foreach Console.println
+ * args.toList foreach Console.println
* </pre>
* <p>And here is a batch file example on Windows XP:</p>
* <pre>
@@ -29,7 +29,7 @@ import util.Exceptional.unwrap
* goto :eof
* ::!#
* Console.println("Hello, world!")
- * argv.toList foreach Console.println
+ * args.toList foreach Console.println
* </pre>
*
* @author Lex Spoon
diff --git a/src/compiler/scala/tools/nsc/ast/Printers.scala b/src/compiler/scala/tools/nsc/ast/Printers.scala
index c64b18207a..f3def3c80c 100644
--- a/src/compiler/scala/tools/nsc/ast/Printers.scala
+++ b/src/compiler/scala/tools/nsc/ast/Printers.scala
@@ -178,9 +178,9 @@ trait Printers extends scala.reflect.internal.Printers { this: Global =>
}
}
- def asString(t: Tree): String = render(t, newStandardTreePrinter, settings.printtypes, settings.uniqid, settings.Yshowsymkinds)
- def asCompactString(t: Tree): String = render(t, newCompactTreePrinter, settings.printtypes, settings.uniqid, settings.Yshowsymkinds)
- def asCompactDebugString(t: Tree): String = render(t, newCompactTreePrinter, true, true, true)
+ def asString(t: Tree): String = render(t, newStandardTreePrinter, settings.printtypes, settings.uniqid, settings.Yshowsymowners, settings.Yshowsymkinds)
+ def asCompactString(t: Tree): String = render(t, newCompactTreePrinter, settings.printtypes, settings.uniqid, settings.Yshowsymowners, settings.Yshowsymkinds)
+ def asCompactDebugString(t: Tree): String = render(t, newCompactTreePrinter, true, true, true, true)
def newStandardTreePrinter(writer: PrintWriter): TreePrinter = new TreePrinter(writer)
def newCompactTreePrinter(writer: PrintWriter): CompactTreePrinter = new CompactTreePrinter(writer)
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 0a753f157c..3542fe5945 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -413,12 +413,10 @@ self =>
*
* {{{
* object moduleName {
- * def main(argv: Array[String]): Unit = {
- * val args = argv
+ * def main(args: Array[String]): Unit =
* new AnyRef {
* stmts
* }
- * }
* }
* }}}
*/
@@ -433,9 +431,8 @@ self =>
// def main
def mainParamType = AppliedTypeTree(Ident(tpnme.Array), List(Ident(tpnme.String)))
- def mainParameter = List(ValDef(Modifiers(Flags.PARAM), nme.argv, mainParamType, EmptyTree))
- def mainSetArgv = List(ValDef(NoMods, nme.args, TypeTree(), Ident(nme.argv)))
- def mainDef = DefDef(NoMods, nme.main, Nil, List(mainParameter), scalaDot(tpnme.Unit), Block(mainSetArgv, gen.mkAnonymousNew(stmts)))
+ def mainParameter = List(ValDef(Modifiers(Flags.PARAM), nme.args, mainParamType, EmptyTree))
+ def mainDef = DefDef(NoMods, nme.main, Nil, List(mainParameter), scalaDot(tpnme.Unit), gen.mkAnonymousNew(stmts))
// object Main
def moduleName = newTermName(ScriptRunner scriptMain settings)
@@ -2495,7 +2492,7 @@ self =>
def mkDefs(p: Tree, tp: Tree, rhs: Tree): List[Tree] = {
val trees = {
val pat = if (tp.isEmpty) p else Typed(p, tp) setPos (p.pos union tp.pos)
- gen.mkPatDef(newmods, pat, rhs)
+ makePatDef(newmods, pat, rhs)
}
if (newmods.isDeferred) {
trees match {
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index 525dcffb0c..6e5a3f6ef7 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -168,4 +168,6 @@ abstract class TreeBuilder {
vparamss ::: List(evidenceParams)
}
}
+
+ def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree) = gen.mkPatDef(mods, pat, rhs)
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
index 18ccced75e..359e5d6c29 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
@@ -583,53 +583,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
trait BCAnnotGen extends BCInnerClassGen {
- /*
- * can-multi-thread
- */
- def ubytesToCharArray(bytes: Array[Byte]): Array[Char] = {
- val ca = new Array[Char](bytes.length)
- var idx = 0
- while (idx < bytes.length) {
- val b: Byte = bytes(idx)
- assert((b & ~0x7f) == 0)
- ca(idx) = b.asInstanceOf[Char]
- idx += 1
- }
-
- ca
- }
-
- /*
- * can-multi-thread
- */
- private def arrEncode(sb: ScalaSigBytes): Array[String] = {
- var strs: List[String] = Nil
- val bSeven: Array[Byte] = sb.sevenBitsMayBeZero
- // chop into slices of at most 65535 bytes, counting 0x00 as taking two bytes (as per JVMS 4.4.7 The CONSTANT_Utf8_info Structure)
- var prevOffset = 0
- var offset = 0
- var encLength = 0
- while (offset < bSeven.size) {
- val deltaEncLength = (if (bSeven(offset) == 0) 2 else 1)
- val newEncLength = encLength.toLong + deltaEncLength
- if (newEncLength >= 65535) {
- val ba = bSeven.slice(prevOffset, offset)
- strs ::= new java.lang.String(ubytesToCharArray(ba))
- encLength = 0
- prevOffset = offset
- } else {
- encLength += deltaEncLength
- offset += 1
- }
- }
- if (prevOffset < offset) {
- assert(offset == bSeven.length)
- val ba = bSeven.slice(prevOffset, offset)
- strs ::= new java.lang.String(ubytesToCharArray(ba))
- }
- assert(strs.size > 1, "encode instead as one String via strEncode()") // TODO too strict?
- mkArrayReverse(strs)
- }
+ import genASM.{ubytesToCharArray, arrEncode}
/*
* can-multi-thread
@@ -676,7 +630,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
av.visit(name, strEncode(sb))
} else {
val arrAnnotV: asm.AnnotationVisitor = av.visitArray(name)
- for(arg <- arrEncode(sb)) { arrAnnotV.visit(name, arg) }
+ for(arg <- genASM.arrEncode(sb)) { arrAnnotV.visit(name, arg) }
arrAnnotV.visitEnd()
} // for the lazy val in ScalaSigBytes to be GC'ed, the invoker of emitAnnotations() should hold the ScalaSigBytes in a method-local var that doesn't escape.
@@ -772,25 +726,6 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
trait BCJGenSigGen {
- // @M don't generate java generics sigs for (members of) implementation
- // classes, as they are monomorphic (TODO: ok?)
- /*
- * must-single-thread
- */
- private def needsGenericSignature(sym: Symbol) = !(
- // PP: This condition used to include sym.hasExpandedName, but this leads
- // to the total loss of generic information if a private member is
- // accessed from a closure: both the field and the accessor were generated
- // without it. This is particularly bad because the availability of
- // generic information could disappear as a consequence of a seemingly
- // unrelated change.
- settings.Ynogenericsig
- || sym.isArtifact
- || sym.isLiftedMethod
- || sym.isBridge
- || (sym.ownerChain exists (_.isImplClass))
- )
-
def getCurrentCUnit(): CompilationUnit
/* @return
@@ -799,61 +734,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
*
* must-single-thread
*/
- def getGenericSignature(sym: Symbol, owner: Symbol): String = {
-
- if (!needsGenericSignature(sym)) { return null }
-
- val memberTpe = enteringErasure(owner.thisType.memberInfo(sym))
-
- val jsOpt: Option[String] = erasure.javaSig(sym, memberTpe)
- if (jsOpt.isEmpty) { return null }
-
- val sig = jsOpt.get
- log(sig) // This seems useful enough in the general case.
-
- def wrap(op: => Unit) = {
- try { op; true }
- catch { case _: Throwable => false }
- }
-
- if (settings.Xverify) {
- // Run the signature parser to catch bogus signatures.
- val isValidSignature = wrap {
- // Alternative: scala.tools.reflect.SigParser (frontend to sun.reflect.generics.parser.SignatureParser)
- import scala.tools.asm.util.CheckClassAdapter
- if (sym.isMethod) { CheckClassAdapter checkMethodSignature sig }
- else if (sym.isTerm) { CheckClassAdapter checkFieldSignature sig }
- else { CheckClassAdapter checkClassSignature sig }
- }
-
- if (!isValidSignature) {
- getCurrentCUnit().warning(sym.pos,
- """|compiler bug: created invalid generic signature for %s in %s
- |signature: %s
- |if this is reproducible, please report bug at https://issues.scala-lang.org/
- """.trim.stripMargin.format(sym, sym.owner.skipPackageObject.fullName, sig))
- return null
- }
- }
-
- if ((settings.check containsName phaseName)) {
- val normalizedTpe = enteringErasure(erasure.prepareSigMap(memberTpe))
- val bytecodeTpe = owner.thisType.memberInfo(sym)
- if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym)(normalizedTpe) =:= bytecodeTpe)) {
- getCurrentCUnit().warning(sym.pos,
- """|compiler bug: created generic signature for %s in %s that does not conform to its erasure
- |signature: %s
- |original type: %s
- |normalized type: %s
- |erasure type: %s
- |if this is reproducible, please report bug at http://issues.scala-lang.org/
- """.trim.stripMargin.format(sym, sym.owner.skipPackageObject.fullName, sig, memberTpe, normalizedTpe, bytecodeTpe))
- return null
- }
- }
-
- sig
- }
+ def getGenericSignature(sym: Symbol, owner: Symbol): String = genASM.getGenericSignature(sym, owner, getCurrentCUnit())
} // end of trait BCJGenSigGen
@@ -906,7 +787,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
)
// TODO needed? for(ann <- m.annotations) { ann.symbol.initialize }
- val jgensig = if (m.isDeferred) null else getGenericSignature(m, module); // only add generic signature if method concrete; bug #1745
+ val jgensig = genASM.staticForwarderGenericSignature(m, module, getCurrentCUnit())
addRemoteExceptionAnnot(isRemoteClass, hasPublicBitSet(flags), m)
val (throws, others) = m.annotations partition (_.symbol == definitions.ThrowsClass)
val thrownExceptions: List[String] = getExceptions(throws)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index b03519ce7d..a389816caf 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -20,7 +20,7 @@ import scala.annotation.tailrec
*
* Documentation at http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/2012Q2/GenASM.pdf
*/
-abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
+abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { self =>
import global._
import icodes._
import icodes.opcodes._
@@ -803,134 +803,9 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
annot.args.isEmpty &&
!annot.matches(DeprecatedAttr)
- // @M don't generate java generics sigs for (members of) implementation
- // classes, as they are monomorphic (TODO: ok?)
- private def needsGenericSignature(sym: Symbol) = !(
- // PP: This condition used to include sym.hasExpandedName, but this leads
- // to the total loss of generic information if a private member is
- // accessed from a closure: both the field and the accessor were generated
- // without it. This is particularly bad because the availability of
- // generic information could disappear as a consequence of a seemingly
- // unrelated change.
- settings.Ynogenericsig
- || sym.isArtifact
- || sym.isLiftedMethod
- || sym.isBridge
- || (sym.ownerChain exists (_.isImplClass))
- )
-
def getCurrentCUnit(): CompilationUnit
- /** @return
- * - `null` if no Java signature is to be added (`null` is what ASM expects in these cases).
- * - otherwise the signature in question
- */
- def getGenericSignature(sym: Symbol, owner: Symbol): String = {
-
- if (!needsGenericSignature(sym)) { return null }
-
- val memberTpe = enteringErasure(owner.thisType.memberInfo(sym))
-
- val jsOpt: Option[String] = erasure.javaSig(sym, memberTpe)
- if (jsOpt.isEmpty) { return null }
-
- val sig = jsOpt.get
- log(sig) // This seems useful enough in the general case.
-
- def wrap(op: => Unit) = {
- try { op; true }
- catch { case _: Throwable => false }
- }
-
- if (settings.Xverify) {
- // Run the signature parser to catch bogus signatures.
- val isValidSignature = wrap {
- // Alternative: scala.tools.reflect.SigParser (frontend to sun.reflect.generics.parser.SignatureParser)
- import scala.tools.asm.util.CheckClassAdapter
- if (sym.isMethod) { CheckClassAdapter checkMethodSignature sig } // requires asm-util.jar
- else if (sym.isTerm) { CheckClassAdapter checkFieldSignature sig }
- else { CheckClassAdapter checkClassSignature sig }
- }
-
- if(!isValidSignature) {
- getCurrentCUnit().warning(sym.pos,
- """|compiler bug: created invalid generic signature for %s in %s
- |signature: %s
- |if this is reproducible, please report bug at https://issues.scala-lang.org/
- """.trim.stripMargin.format(sym, sym.owner.skipPackageObject.fullName, sig))
- return null
- }
- }
-
- if ((settings.check containsName phaseName)) {
- val normalizedTpe = enteringErasure(erasure.prepareSigMap(memberTpe))
- val bytecodeTpe = owner.thisType.memberInfo(sym)
- if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym)(normalizedTpe) =:= bytecodeTpe)) {
- getCurrentCUnit().warning(sym.pos,
- """|compiler bug: created generic signature for %s in %s that does not conform to its erasure
- |signature: %s
- |original type: %s
- |normalized type: %s
- |erasure type: %s
- |if this is reproducible, please report bug at http://issues.scala-lang.org/
- """.trim.stripMargin.format(sym, sym.owner.skipPackageObject.fullName, sig, memberTpe, normalizedTpe, bytecodeTpe))
- return null
- }
- }
-
- sig
- }
-
- def ubytesToCharArray(bytes: Array[Byte]): Array[Char] = {
- val ca = new Array[Char](bytes.length)
- var idx = 0
- while(idx < bytes.length) {
- val b: Byte = bytes(idx)
- assert((b & ~0x7f) == 0)
- ca(idx) = b.asInstanceOf[Char]
- idx += 1
- }
-
- ca
- }
-
- private def arrEncode(sb: ScalaSigBytes): Array[String] = {
- var strs: List[String] = Nil
- val bSeven: Array[Byte] = sb.sevenBitsMayBeZero
- // chop into slices of at most 65535 bytes, counting 0x00 as taking two bytes (as per JVMS 4.4.7 The CONSTANT_Utf8_info Structure)
- var prevOffset = 0
- var offset = 0
- var encLength = 0
- while(offset < bSeven.length) {
- val deltaEncLength = (if(bSeven(offset) == 0) 2 else 1)
- val newEncLength = encLength.toLong + deltaEncLength
- if(newEncLength >= 65535) {
- val ba = bSeven.slice(prevOffset, offset)
- strs ::= new java.lang.String(ubytesToCharArray(ba))
- encLength = 0
- prevOffset = offset
- } else {
- encLength += deltaEncLength
- offset += 1
- }
- }
- if(prevOffset < offset) {
- assert(offset == bSeven.length)
- val ba = bSeven.slice(prevOffset, offset)
- strs ::= new java.lang.String(ubytesToCharArray(ba))
- }
- assert(strs.size > 1, "encode instead as one String via strEncode()") // TODO too strict?
- strs.reverse.toArray
- }
-
- private def strEncode(sb: ScalaSigBytes): String = {
- val ca = ubytesToCharArray(sb.sevenBitsMayBeZero)
- new java.lang.String(ca)
- // debug val bvA = new asm.ByteVector; bvA.putUTF8(s)
- // debug val enc: Array[Byte] = scala.reflect.internal.pickling.ByteCodecs.encode(bytes)
- // debug assert(enc(idx) == bvA.getByte(idx + 2))
- // debug assert(bvA.getLength == enc.size + 2)
- }
+ def getGenericSignature(sym: Symbol, owner: Symbol) = self.getGenericSignature(sym, owner, getCurrentCUnit())
def emitArgument(av: asm.AnnotationVisitor,
name: String,
@@ -1064,7 +939,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
)
// TODO needed? for(ann <- m.annotations) { ann.symbol.initialize }
- val jgensig = if (m.isDeferred) null else getGenericSignature(m, module); // only add generic signature if method concrete; bug #1745
+ val jgensig = staticForwarderGenericSignature(m, module, getCurrentCUnit())
addRemoteExceptionAnnot(isRemoteClass, hasPublicBitSet(flags), m)
val (throws, others) = m.annotations partition (_.symbol == ThrowsClass)
val thrownExceptions: List[String] = getExceptions(throws)
@@ -3303,4 +3178,147 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
}
+ // @M don't generate java generics sigs for (members of) implementation
+ // classes, as they are monomorphic (TODO: ok?)
+ private def needsGenericSignature(sym: Symbol) = !(
+ // PP: This condition used to include sym.hasExpandedName, but this leads
+ // to the total loss of generic information if a private member is
+ // accessed from a closure: both the field and the accessor were generated
+ // without it. This is particularly bad because the availability of
+ // generic information could disappear as a consequence of a seemingly
+ // unrelated change.
+ settings.Ynogenericsig
+ || sym.isArtifact
+ || sym.isLiftedMethod
+ || sym.isBridge
+ || (sym.ownerChain exists (_.isImplClass))
+ )
+
+ final def staticForwarderGenericSignature(sym: Symbol, moduleClass: Symbol, unit: CompilationUnit): String = {
+ if (sym.isDeferred) null // only add generic signature if method concrete; bug #1745
+ else {
+ // SI-3452 Static forwarder generation uses the same erased signature as the method if forwards to.
+ // By rights, it should use the signature as-seen-from the module class, and add suitable
+ // primitive and value-class boxing/unboxing.
+ // But for now, just like we did in mixin, we just avoid writing a wrong generic signature
+ // (one that doesn't erase to the actual signature). See run/t3452b for a test case.
+ val memberTpe = enteringErasure(moduleClass.thisType.memberInfo(sym))
+ val erasedMemberType = erasure.erasure(sym)(memberTpe)
+ if (erasedMemberType =:= sym.info)
+ getGenericSignature(sym, moduleClass, memberTpe, unit)
+ else null
+ }
+ }
+
+ /** @return
+ * - `null` if no Java signature is to be added (`null` is what ASM expects in these cases).
+ * - otherwise the signature in question
+ */
+ def getGenericSignature(sym: Symbol, owner: Symbol, unit: CompilationUnit): String = {
+ val memberTpe = enteringErasure(owner.thisType.memberInfo(sym))
+ getGenericSignature(sym, owner, memberTpe, unit)
+ }
+ def getGenericSignature(sym: Symbol, owner: Symbol, memberTpe: Type, unit: CompilationUnit): String = {
+ if (!needsGenericSignature(sym)) { return null }
+
+ val jsOpt: Option[String] = erasure.javaSig(sym, memberTpe)
+ if (jsOpt.isEmpty) { return null }
+
+ val sig = jsOpt.get
+ log(sig) // This seems useful enough in the general case.
+
+ def wrap(op: => Unit) = {
+ try { op; true }
+ catch { case _: Throwable => false }
+ }
+
+ if (settings.Xverify) {
+ // Run the signature parser to catch bogus signatures.
+ val isValidSignature = wrap {
+ // Alternative: scala.tools.reflect.SigParser (frontend to sun.reflect.generics.parser.SignatureParser)
+ import scala.tools.asm.util.CheckClassAdapter
+ if (sym.isMethod) { CheckClassAdapter checkMethodSignature sig } // requires asm-util.jar
+ else if (sym.isTerm) { CheckClassAdapter checkFieldSignature sig }
+ else { CheckClassAdapter checkClassSignature sig }
+ }
+
+ if(!isValidSignature) {
+ unit.warning(sym.pos,
+ """|compiler bug: created invalid generic signature for %s in %s
+ |signature: %s
+ |if this is reproducible, please report bug at https://issues.scala-lang.org/
+ """.trim.stripMargin.format(sym, sym.owner.skipPackageObject.fullName, sig))
+ return null
+ }
+ }
+
+ if ((settings.check containsName phaseName)) {
+ val normalizedTpe = enteringErasure(erasure.prepareSigMap(memberTpe))
+ val bytecodeTpe = owner.thisType.memberInfo(sym)
+ if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym)(normalizedTpe) =:= bytecodeTpe)) {
+ unit.warning(sym.pos,
+ """|compiler bug: created generic signature for %s in %s that does not conform to its erasure
+ |signature: %s
+ |original type: %s
+ |normalized type: %s
+ |erasure type: %s
+ |if this is reproducible, please report bug at http://issues.scala-lang.org/
+ """.trim.stripMargin.format(sym, sym.owner.skipPackageObject.fullName, sig, memberTpe, normalizedTpe, bytecodeTpe))
+ return null
+ }
+ }
+
+ sig
+ }
+
+ def ubytesToCharArray(bytes: Array[Byte]): Array[Char] = {
+ val ca = new Array[Char](bytes.length)
+ var idx = 0
+ while(idx < bytes.length) {
+ val b: Byte = bytes(idx)
+ assert((b & ~0x7f) == 0)
+ ca(idx) = b.asInstanceOf[Char]
+ idx += 1
+ }
+
+ ca
+ }
+
+ final def arrEncode(sb: ScalaSigBytes): Array[String] = {
+ var strs: List[String] = Nil
+ val bSeven: Array[Byte] = sb.sevenBitsMayBeZero
+ // chop into slices of at most 65535 bytes, counting 0x00 as taking two bytes (as per JVMS 4.4.7 The CONSTANT_Utf8_info Structure)
+ var prevOffset = 0
+ var offset = 0
+ var encLength = 0
+ while(offset < bSeven.length) {
+ val deltaEncLength = (if(bSeven(offset) == 0) 2 else 1)
+ val newEncLength = encLength.toLong + deltaEncLength
+ if(newEncLength >= 65535) {
+ val ba = bSeven.slice(prevOffset, offset)
+ strs ::= new java.lang.String(ubytesToCharArray(ba))
+ encLength = 0
+ prevOffset = offset
+ } else {
+ encLength += deltaEncLength
+ offset += 1
+ }
+ }
+ if(prevOffset < offset) {
+ assert(offset == bSeven.length)
+ val ba = bSeven.slice(prevOffset, offset)
+ strs ::= new java.lang.String(ubytesToCharArray(ba))
+ }
+ assert(strs.size > 1, "encode instead as one String via strEncode()") // TODO too strict?
+ strs.reverse.toArray
+ }
+
+ private def strEncode(sb: ScalaSigBytes): String = {
+ val ca = ubytesToCharArray(sb.sevenBitsMayBeZero)
+ new java.lang.String(ca)
+ // debug val bvA = new asm.ByteVector; bvA.putUTF8(s)
+ // debug val enc: Array[Byte] = scala.reflect.internal.pickling.ByteCodecs.encode(bytes)
+ // debug assert(enc(idx) == bvA.getByte(idx + 2))
+ // debug assert(bvA.getLength == enc.size + 2)
+ }
}
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index a3114a3d7b..a385a31165 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -168,6 +168,7 @@ trait ScalaSettings extends AbsScalaSettings
= BooleanSetting ("-Yshow-trees-stringified", "(Requires -Xprint:) Print stringifications along with detailed ASTs.")
val Yshowsyms = BooleanSetting ("-Yshow-syms", "Print the AST symbol hierarchy after each phase.")
val Yshowsymkinds = BooleanSetting ("-Yshow-symkinds", "Print abbreviated symbol kinds next to symbol names.")
+ val Yshowsymowners = BooleanSetting ("-Yshow-symowners", "Print owner identifiers next to symbol names.")
val skip = PhasesSetting ("-Yskip", "Skip")
val Ygenjavap = StringSetting ("-Ygen-javap", "dir", "Generate a parallel output directory of .javap files.", "")
val Ygenasmp = StringSetting ("-Ygen-asmp", "dir", "Generate a parallel output directory of .asmp files (ie ASM Textifier output).", "")
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 89f9cb4b06..673bc04bd9 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -172,18 +172,23 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
// info) as they are seen from the class. We can't use the member that we get from the
// implementation class, as it's a clone that was made after erasure, and thus it does not
// know its info at the beginning of erasure anymore.
- // Optimize: no need if mixinClass has no typeparams.
- mixinMember cloneSymbol clazz modifyInfo (info =>
- if (mixinClass.typeParams.isEmpty) info
- else (clazz.thisType baseType mixinClass) memberInfo mixinMember
- )
+ val sym = mixinMember cloneSymbol clazz
+
+ val erasureMap = erasure.erasure(mixinMember)
+ val erasedInterfaceInfo: Type = erasureMap(mixinMember.info)
+ val specificForwardInfo = (clazz.thisType baseType mixinClass) memberInfo mixinMember
+ val forwarderInfo =
+ if (erasureMap(specificForwardInfo) =:= erasedInterfaceInfo)
+ specificForwardInfo
+ else {
+ erasedInterfaceInfo
+ }
+ // Optimize: no need if mixinClass has no typeparams.
+ // !!! JZ Really? What about the effect of abstract types, prefix?
+ if (mixinClass.typeParams.isEmpty) sym
+ else sym modifyInfo (_ => forwarderInfo)
}
- // clone before erasure got rid of type info we'll need to generate a javaSig
- // now we'll have the type info at (the beginning of) erasure in our history,
- // and now newSym has the info that's been transformed to fit this period
- // (no need for asSeenFrom as phase.erasedTypes)
- // TODO: verify we need the updateInfo and document why
- newSym updateInfo (mixinMember.info cloneInfo newSym)
+ newSym
}
/** Add getters and setters for all non-module fields of an implementation
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 2043eb5d5d..40b97394f2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -501,10 +501,6 @@ trait ContextErrors {
}
// doTypeApply
- //tryNamesDefaults
- def NamedAndDefaultArgumentsNotSupportedForMacros(tree: Tree, fun: Tree) =
- NormalTypeError(tree, "macro applications do not support named and/or default arguments")
-
def TooManyArgsNamesDefaultsError(tree: Tree, fun: Tree) =
NormalTypeError(tree, "too many arguments for "+treeSymTypeMsg(fun))
@@ -603,12 +599,11 @@ trait ContextErrors {
//adapt
def MissingArgsForMethodTpeError(tree: Tree, meth: Symbol) = {
+ val errorExplanation = "missing arguments for " + meth.fullLocationString
+ val suggestPartialApplication = ";\nfollow this method with `_' if you want to treat it as a partially applied function"
val message =
- if (meth.isMacro) MacroTooFewArgumentListsMessage
- else "missing arguments for " + meth.fullLocationString + (
- if (meth.isConstructor) ""
- else ";\nfollow this method with `_' if you want to treat it as a partially applied function"
- )
+ if (meth.isMacro || meth.isConstructor) errorExplanation
+ else errorExplanation + suggestPartialApplication
issueNormalTypeError(tree, message)
setError(tree)
}
@@ -748,15 +743,12 @@ trait ContextErrors {
throw MacroExpansionException
}
- private def MacroTooFewArgumentListsMessage = "too few argument lists for macro invocation"
- def MacroTooFewArgumentListsError(expandee: Tree) = macroExpansionError2(expandee, MacroTooFewArgumentListsMessage)
-
- private def MacroTooManyArgumentListsMessage = "too many argument lists for macro invocation"
- def MacroTooManyArgumentListsError(expandee: Tree) = macroExpansionError2(expandee, MacroTooManyArgumentListsMessage)
-
- def MacroTooFewArgumentsError(expandee: Tree) = macroExpansionError2(expandee, "too few arguments for macro invocation")
-
- def MacroTooManyArgumentsError(expandee: Tree) = macroExpansionError2(expandee, "too many arguments for macro invocation")
+ def MacroFastTrackFailed(expandee: Tree) = {
+ // here we speculate that the reason why FastTrackEntry.validate failed is the lack arguments for a given method
+ // that's not ideal, but on the other hand this allows us to keep FastTrack simple without hooking errorgen into it
+ MissingArgsForMethodTpeError(expandee, expandee.symbol)
+ throw MacroExpansionException
+ }
def MacroGeneratedAbort(expandee: Tree, ex: AbortMacroException) = {
// errors have been reported by the macro itself, so we do nothing here
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 677c94e063..1f90dd4939 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -353,7 +353,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
new {
val universe: self.global.type = self.global
val callsiteTyper: universe.analyzer.Typer = typer.asInstanceOf[global.analyzer.Typer]
- val expandee = universe.analyzer.macroExpanderAttachment(expandeeTree).original orElse duplicateAndKeepPositions(expandeeTree)
+ val expandee = universe.analyzer.macroExpanderAttachment(expandeeTree).desugared orElse duplicateAndKeepPositions(expandeeTree)
} with UnaffiliatedMacroContext {
val prefix = Expr[Nothing](prefixTree)(TypeTag.Nothing)
override def toString = "MacroContext(%s@%s +%d)".format(expandee.symbol.name, expandee.pos, enclosingMacros.length - 1 /* exclude myself */)
@@ -371,7 +371,15 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
def standardMacroArgs(typer: Typer, expandee: Tree): MacroArgs = {
val macroDef = expandee.symbol
val paramss = macroDef.paramss
- val treeInfo.Applied(core, targs, argss) = expandee
+ val treeInfo.Applied(core, targs, maybeNamedArgss) = expandee
+ val argss = map2(maybeNamedArgss, paramss)((args, params) => {
+ if (args.exists(_.isInstanceOf[AssignOrNamedArg])) {
+ val sorted = ListBuffer.fill(params.length)(EmptyTree: Tree)
+ args foreach { case AssignOrNamedArg(Ident(name), arg) => sorted(params.indexWhere(_.name == name)) = arg }
+ sorted.toList
+ } else if (params.length == args.length) args
+ else args ++ List.fill(params.length - args.length)(EmptyTree)
+ })
val prefix = core match { case Select(qual, _) => qual; case _ => EmptyTree }
val context = expandee.attachments.get[MacroRuntimeAttachment].flatMap(_.macroContext).getOrElse(macroContext(typer, prefix, expandee))
@@ -383,16 +391,11 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
|paramss: $paramss
""".trim)
- import typer.TyperErrorGen._
- val isNullaryArgsEmptyParams = argss.isEmpty && paramss == ListOfNil
- if (paramss.length < argss.length) MacroTooManyArgumentListsError(expandee)
- if (paramss.length > argss.length && !isNullaryArgsEmptyParams) MacroTooFewArgumentListsError(expandee)
-
val macroImplArgs: List[Any] =
if (fastTrack contains macroDef) {
// Take a dry run of the fast track implementation
if (fastTrack(macroDef) validate expandee) argss.flatten
- else MacroTooFewArgumentListsError(expandee)
+ else typer.TyperErrorGen.MacroFastTrackFailed(expandee)
}
else {
def calculateMacroArgs(binding: MacroImplBinding) = {
@@ -403,14 +406,6 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
// wrap argss in c.Expr if necessary (i.e. if corresponding macro impl param is of type c.Expr[T])
// expand varargs (nb! varargs can apply to any parameter section, not necessarily to the last one)
val trees = map3(argss, paramss, signature)((args, defParams, implParams) => {
- val isVarargs = isVarArgsList(defParams)
- if (isVarargs) {
- if (defParams.length > args.length + 1) MacroTooFewArgumentsError(expandee)
- } else {
- if (defParams.length < args.length) MacroTooManyArgumentsError(expandee)
- if (defParams.length > args.length) MacroTooFewArgumentsError(expandee)
- }
-
val wrappedArgs = mapWithIndex(args)((arg, j) => {
val fingerprint = implParams(min(j, implParams.length - 1))
fingerprint match {
@@ -421,7 +416,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
}
})
- if (isVarargs) {
+ if (isVarArgsList(defParams)) {
val (normal, varargs) = wrappedArgs splitAt (defParams.length - 1)
normal :+ varargs // pack all varargs into a single Seq argument (varargs Scala style)
} else wrappedArgs
@@ -529,9 +524,11 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
* the expandee with an error marker set if there has been an error
*/
abstract class MacroExpander(val typer: Typer, val expandee: Tree) {
+ val symbol = expandee match { case Block(_, expr) => expr.symbol; case tree => tree.symbol }
+
def onSuccess(expanded: Tree): Tree
def onFallback(expanded: Tree): Tree
- def onSuppressed(expandee: Tree): Tree = expandee
+ def onSuppressed(expanded: Tree): Tree = expanded
def onDelayed(expanded: Tree): Tree = expanded
def onSkipped(expanded: Tree): Tree = expanded
def onFailure(expanded: Tree): Tree = { typer.infer.setError(expandee); expandee }
@@ -551,15 +548,15 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
if (Statistics.canEnable) Statistics.incCounter(macroExpandCount)
try {
withInfoLevel(nodePrinters.InfoLevel.Quiet) { // verbose printing might cause recursive macro expansions
- if (expandee.symbol.isErroneous || (expandee exists (_.isErroneous))) {
- val reason = if (expandee.symbol.isErroneous) "not found or incompatible macro implementation" else "erroneous arguments"
+ if (symbol.isErroneous || (expandee exists (_.isErroneous)) || (desugared exists (_.isErroneous))) {
+ val reason = if (symbol.isErroneous) "not found or incompatible macro implementation" else "erroneous arguments"
macroLogVerbose(s"cancelled macro expansion because of $reason: $expandee")
onFailure(typer.infer.setError(expandee))
} else try {
val expanded = {
- val runtime = macroRuntime(expandee)
- if (runtime != null) macroExpandWithRuntime(typer, expandee, runtime)
- else macroExpandWithoutRuntime(typer, expandee)
+ val runtime = macroRuntime(desugared)
+ if (runtime != null) macroExpandWithRuntime(typer, desugared, runtime)
+ else macroExpandWithoutRuntime(typer, desugared)
}
expanded match {
case Success(expanded) =>
@@ -591,7 +588,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
extends MacroExpander(typer, expandee) {
lazy val innerPt = {
val tp = if (isNullaryInvocation(expandee)) expandee.tpe.finalResultType else expandee.tpe
- if (isBlackbox(expandee)) tp
+ if (isBlackbox(symbol)) tp
else {
// approximation is necessary for whitebox macros to guide type inference
// read more in the comments for onDelayed below
@@ -599,6 +596,50 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
deriveTypeWithWildcards(undetparams)(tp)
}
}
+ override protected def expand(desugared: Tree) = {
+ // SI-5940 in order for a macro expansion that involves named or default arguments
+ // to see the actual prefix and arguments being passed by the user instead of their desugarings
+ // we need to inline synthetics in case when `fun` is actually a macro
+ // underlying macro implementation is going to get explicitly passed arguments in correct order
+ // and the rest (defaults filled in by the vanilla part of `tryNamesDefaults`) will become empty trees
+ // in order for the macro to be able to account for evaluation order, the original is provided in `c.macroApplication`
+ // of course, ideally we would like to provide the impl with right-hand sides of those default arguments
+ // but currently that is flat out impossible because of the difference in scopes
+ // anyway this is already an improvement over the former status quo when named/default invocations were outright prohibited
+ def undoNamesDefaults(tree: Tree): Tree = {
+ val (qualsym, qual, vdefs0, app @ Applied(_, _, argss)) = tree match {
+ case Block((qualdef @ ValDef(_, name, _, qual)) +: vdefs, app) if name.startsWith(nme.QUAL_PREFIX) => (qualdef.symbol, qual, vdefs, app)
+ case Block(vdefs, app) => (NoSymbol, EmptyTree, vdefs, app)
+ case tree => (NoSymbol, EmptyTree, Nil, tree)
+ }
+ val vdefs = vdefs0.map{ case vdef: ValDef => vdef }
+ def hasNamesDefaults(args: List[Tree]) = {
+ args.exists(arg => isDefaultGetter(arg) || vdefs.exists(_.symbol == arg.symbol))
+ }
+ def undoNamesDefaults(args: List[Tree], depth: Int) = {
+ def extractRhs(vdef: ValDef) = vdef.rhs.changeOwner(vdef.symbol -> typer.context.owner)
+ case class Arg(tree: Tree, ipos: Int, inamed: Int) { val param = app.symbol.paramss(depth)(ipos) }
+ val indexed = args.map(arg => arg -> vdefs.indexWhere(_.symbol == arg.symbol)).zipWithIndex.flatMap({
+ /* default */ case ((arg, _), _) if isDefaultGetter(arg) => None
+ /* positional */ case ((arg, -1), ipos) => Some(Arg(arg, ipos, -1))
+ /* default+named */ case ((_, inamed), _) if isDefaultGetter(extractRhs(vdefs(inamed))) => None
+ /* named */ case ((arg, inamed), ipos) => Some(Arg(extractRhs(vdefs(inamed)), ipos, inamed))
+ })
+ if (indexed.forall(_.inamed == -1)) indexed.map(_.tree)
+ else indexed.sortBy(_.inamed).map(arg => AssignOrNamedArg(Ident(arg.param.name), arg.tree))
+ }
+ def loop(tree: Tree, depth: Int): Tree = tree match {
+ case Apply(fun, args) if hasNamesDefaults(args) => treeCopy.Apply(tree, loop(fun, depth - 1), undoNamesDefaults(args, depth))
+ case Apply(fun, args) => treeCopy.Apply(tree, loop(fun, depth - 1), args)
+ case TypeApply(core, targs) => treeCopy.TypeApply(tree, core, targs)
+ case Select(core, name) if qualsym != NoSymbol && core.symbol == qualsym => treeCopy.Select(tree, qual, name)
+ case core => core
+ }
+ if (app.symbol == null || app.symbol == NoSymbol || app.exists(_.isErroneous)) tree
+ else loop(app, depth = argss.length - 1)
+ }
+ super.expand(undoNamesDefaults(desugared))
+ }
override def onSuccess(expanded0: Tree) = {
// prematurely annotate the tree with a macro expansion attachment
// so that adapt called indirectly by typer.typed knows that it needs to apply the existential fixup
@@ -616,7 +657,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
}
}
- if (isBlackbox(expandee)) {
+ if (isBlackbox(symbol)) {
val expanded1 = atPos(enclosingMacroPosition.makeTransparent)(Typed(expanded0, TypeTree(innerPt)))
typecheck("blackbox typecheck", expanded1, outerPt)
} else {
@@ -678,7 +719,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
// Thanks to that the materializer can take a look at what's going on and react accordingly.
val shouldInstantiate = typer.context.undetparams.nonEmpty && !mode.inPolyMode
if (shouldInstantiate) {
- if (isBlackbox(expandee)) typer.instantiatePossiblyExpectingUnit(delayed, mode, outerPt)
+ if (isBlackbox(symbol)) typer.instantiatePossiblyExpectingUnit(delayed, mode, outerPt)
else {
forced += delayed
typer.infer.inferExprInstance(delayed, typer.context.extractUndetparams(), outerPt, keepNothings = false)
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index 6a4df415ae..dceb0a47d8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -162,7 +162,7 @@ trait NamesDefaults { self: Analyzer =>
// never used for constructor calls, they always have a stable qualifier
def blockWithQualifier(qual: Tree, selected: Name) = {
- val sym = blockTyper.context.owner.newValue(unit.freshTermName("qual$"), newFlags = ARTIFACT) setInfo uncheckedBounds(qual.tpe) setPos (qual.pos.makeTransparent)
+ val sym = blockTyper.context.owner.newValue(unit.freshTermName(nme.QUAL_PREFIX), newFlags = ARTIFACT) setInfo uncheckedBounds(qual.tpe) setPos (qual.pos.makeTransparent)
blockTyper.context.scope enter sym
val vd = atPos(sym.pos)(ValDef(sym, qual) setType NoType)
// it stays in Vegas: SI-5720, SI-5727
@@ -292,7 +292,7 @@ trait NamesDefaults { self: Analyzer =>
arg.tpe
}
).widen // have to widen or types inferred from literal defaults will be singletons
- val s = context.owner.newValue(unit.freshTermName(), arg.pos, newFlags = ARTIFACT) setInfo {
+ val s = context.owner.newValue(unit.freshTermName(nme.NAMEDARG_PREFIX), arg.pos, newFlags = ARTIFACT) setInfo {
val tp = if (byName) functionType(Nil, argTpe) else argTpe
uncheckedBounds(tp)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
index 57f27a05fd..1a6d2f0011 100644
--- a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
@@ -85,6 +85,7 @@ trait StdAttachments {
tree match {
// see the comment to `isMacroExpansionSuppressed` to learn why we need
// a special traversal strategy here
+ case Block(_, expr) => unsuppressMacroExpansion(expr)
case Apply(fn, _) => unsuppressMacroExpansion(fn)
case TypeApply(fn, _) => unsuppressMacroExpansion(fn)
case _ => // do nothing
@@ -101,6 +102,8 @@ trait StdAttachments {
// we have to account for the fact that during typechecking an expandee might become wrapped,
// i.e. surrounded by an inferred implicit argument application or by an inferred type argument application.
// in that case the expandee itself will no longer be suppressed and we need to look at the core
+ // upd. we also need to allow for blocks, because that's what names and defaults are often desugared to
+ case Block(_, expr) => isMacroExpansionSuppressed(expr)
case Apply(fn, _) => isMacroExpansionSuppressed(fn)
case TypeApply(fn, _) => isMacroExpansionSuppressed(fn)
case _ => false
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index 4e3e00b66a..ca960d7b11 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -525,7 +525,6 @@ trait TypeDiagnostics {
val unused = p.unusedTerms
unused foreach { defn: DefTree =>
val sym = defn.symbol
- val isDefaultGetter = sym.name containsName nme.DEFAULT_GETTER_STRING
val pos = (
if (defn.pos.isDefined) defn.pos
else if (sym.pos.isDefined) sym.pos
@@ -536,7 +535,7 @@ trait TypeDiagnostics {
)
val why = if (sym.isPrivate) "private" else "local"
val what = (
- if (isDefaultGetter) "default argument"
+ if (sym.isDefaultGetter) "default argument"
else if (sym.isConstructor) "constructor"
else if (sym.isVar || sym.isGetter && sym.accessed.isVar) "var"
else if (sym.isVal || sym.isGetter && sym.accessed.isVal) "val"
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index ea8ad0bf42..ba4b3499e5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -56,6 +56,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
sealed abstract class SilentResult[+T] {
+ def isEmpty: Boolean
+ def nonEmpty = !isEmpty
+
@inline final def fold[U](none: => U)(f: T => U): U = this match {
case SilentResultValue(value) => f(value)
case _ => none
@@ -74,6 +77,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
}
class SilentTypeError private(val errors: List[AbsTypeError]) extends SilentResult[Nothing] {
+ override def isEmpty = true
def err: AbsTypeError = errors.head
def reportableErrors = errors match {
case (e1: AmbiguousImplicitTypeError) +: _ =>
@@ -87,7 +91,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
def unapply(error: SilentTypeError): Option[AbsTypeError] = error.errors.headOption
}
- case class SilentResultValue[+T](value: T) extends SilentResult[T] { }
+ case class SilentResultValue[+T](value: T) extends SilentResult[T] { override def isEmpty = false }
def newTyper(context: Context): Typer = new NormalTyper(context)
@@ -1157,7 +1161,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case mt: MethodType if mode.typingExprNotFunNotLhs && mt.isImplicit => // (4.1)
adaptToImplicitMethod(mt)
- case mt: MethodType if mode.typingExprNotFunNotLhs && !hasUndetsInMonoMode && !treeInfo.isMacroApplicationOrBlock(tree) =>
+ case mt: MethodType if mode.typingExprNotFunNotLhs && !hasUndetsInMonoMode =>
instantiateToMethodType(mt)
case _ =>
vanillaAdapt(tree)
@@ -3268,12 +3272,6 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
*/
def tryNamesDefaults: Tree = {
val lencmp = compareLengths(args, formals)
-
- def checkNotMacro() = {
- if (treeInfo.isMacroApplication(fun))
- tryTupleApply orElse duplErrorTree(NamedAndDefaultArgumentsNotSupportedForMacros(tree, fun))
- }
-
if (mt.isErroneous) duplErrTree
else if (mode.inPatternMode) {
// #2064
@@ -3292,18 +3290,15 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
else if (allArgsArePositional(argPos) && !isNamedApplyBlock(fun)) {
// if there's no re-ordering, and fun is not transformed, no need to transform
// more than an optimization, e.g. important in "synchronized { x = update-x }"
- checkNotMacro()
doTypedApply(tree, fun, namelessArgs, mode, pt)
} else {
- checkNotMacro()
- transformNamedApplication(Typer.this, mode, pt)(
- treeCopy.Apply(tree, fun, namelessArgs), argPos)
+ unsuppressMacroExpansion(transformNamedApplication(Typer.this, mode, pt)(
+ treeCopy.Apply(tree, suppressMacroExpansion(fun), namelessArgs), argPos))
}
} else {
// defaults are needed. they are added to the argument list in named style as
// calls to the default getters. Example:
// foo[Int](a)() ==> foo[Int](a)(b = foo$qual.foo$default$2[Int](a))
- checkNotMacro()
// SI-8111 transformNamedApplication eagerly shuffles around the application to preserve
// evaluation order. During this process, it calls `changeOwner` on symbols that
@@ -3326,7 +3321,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
symsOwnedByContextOwner foreach (_.owner = context.owner)
}
- val fun1 = transformNamedApplication(Typer.this, mode, pt)(fun, x => x)
+ val fun1 = transformNamedApplication(Typer.this, mode, pt)(suppressMacroExpansion(fun), x => x)
if (fun1.isErroneous) duplErrTree
else {
assert(isNamedApplyBlock(fun1), fun1)
@@ -3352,7 +3347,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// useful when a default doesn't match parameter type, e.g. def f[T](x:T="a"); f[Int]()
val note = "Error occurred in an application involving default arguments."
if (!(context.diagnostic contains note)) context.diagnostic = note :: context.diagnostic
- doTypedApply(tree, if (blockIsEmpty) fun else fun1, allArgs, mode, pt)
+ unsuppressMacroExpansion(doTypedApply(tree, if (blockIsEmpty) fun else fun1, allArgs, mode, pt))
} else {
rollbackNamesDefaultsOwnerChanges()
tryTupleApply orElse duplErrorTree(NotEnoughArgsError(tree, fun, missing))
diff --git a/src/compiler/scala/tools/reflect/FormatInterpolator.scala b/src/compiler/scala/tools/reflect/FormatInterpolator.scala
index d5e674ebae..0258002850 100644
--- a/src/compiler/scala/tools/reflect/FormatInterpolator.scala
+++ b/src/compiler/scala/tools/reflect/FormatInterpolator.scala
@@ -81,7 +81,56 @@ abstract class FormatInterpolator {
case Literal(Constant(x: String)) => x
case _ => throw new IllegalArgumentException("internal error: argument parts must be a list of string literals")
}
- val s = StringContext.treatEscapes(s0)
+ def escapeHatch: PartialFunction[Throwable, String] = {
+ // trailing backslash, octal escape, or other
+ case e: StringContext.InvalidEscapeException =>
+ def errPoint = part.pos withPoint (part.pos.point + e.index)
+ def octalOf(c: Char) = Character.digit(c, 8)
+ def alt = {
+ def altOf(i: Int) = i match {
+ case '\b' => "\\b"
+ case '\t' => "\\t"
+ case '\n' => "\\n"
+ case '\f' => "\\f"
+ case '\r' => "\\r"
+ case '\"' => "\\u0022" // $" in future
+ case '\'' => "'"
+ case '\\' => """\\"""
+ case x => "\\u%04x" format x
+ }
+ val suggest = {
+ val r = "([0-7]{1,3}).*".r
+ (s0 drop e.index + 1) match {
+ case r(n) => altOf { (0 /: n) { case (a, o) => (8 * a) + (o - '0') } }
+ case _ => ""
+ }
+ }
+ val txt =
+ if ("" == suggest) ""
+ else s", use $suggest instead"
+ txt
+ }
+ def badOctal = {
+ def msg(what: String) = s"Octal escape literals are $what$alt."
+ if (settings.future) {
+ c.error(errPoint, msg("unsupported"))
+ s0
+ } else {
+ c.enclosingUnit.deprecationWarning(errPoint, msg("deprecated"))
+ try StringContext.treatEscapes(s0) catch escapeHatch
+ }
+ }
+ if (e.index == s0.length - 1) {
+ c.error(errPoint, """Trailing '\' escapes nothing.""")
+ s0
+ } else if (octalOf(s0(e.index + 1)) >= 0) {
+ badOctal
+ } else {
+ c.error(errPoint, e.getMessage)
+ s0
+ }
+ }
+ val s = try StringContext.processEscapes(s0) catch escapeHatch
val ms = fpat findAllMatchIn s
def errorLeading(op: Conversion) = op.errorAt(Spec, s"conversions must follow a splice; ${Conversion.literalHelp}")
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
index 3a40b44c74..3b12086cc7 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -64,7 +64,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
lastSeenContext = null
}
- def verify(expr: Tree): Unit = {
+ def verify(expr: Tree): Tree = {
// Previously toolboxes used to typecheck their inputs before compiling.
// Actually, the initial demo by Martin first typechecked the reified tree,
// then ran it, which typechecked it again, and only then launched the
@@ -86,14 +86,8 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
|if you have troubles tracking free type variables, consider using -Xlog-free-types
""".stripMargin.trim)
}
- }
-
- def wrapIntoTerm(tree: Tree): Tree =
- if (!tree.isTerm) Block(List(tree), Literal(Constant(()))) else tree
- def unwrapFromTerm(tree: Tree): Tree = tree match {
- case Block(List(tree), Literal(Constant(()))) => tree
- case tree => tree
+ expr
}
def extractFreeTerms(expr0: Tree, wrapFreeTermRefs: Boolean): (Tree, scala.collection.mutable.LinkedHashMap[FreeTermSymbol, TermName]) = {
@@ -122,59 +116,58 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
(expr, freeTermNames)
}
- def transformDuringTyper(expr0: Tree, withImplicitViewsDisabled: Boolean, withMacrosDisabled: Boolean)(transform: (analyzer.Typer, Tree) => Tree): Tree = {
- verify(expr0)
-
- // need to wrap the expr, because otherwise you won't be able to typecheck macros against something that contains free vars
- val exprAndFreeTerms = extractFreeTerms(expr0, wrapFreeTermRefs = false)
- var expr = exprAndFreeTerms._1
- val freeTerms = exprAndFreeTerms._2
- val dummies = freeTerms.map{ case (freeTerm, name) => ValDef(NoMods, name, TypeTree(freeTerm.info), Select(Ident(PredefModule), newTermName("$qmark$qmark$qmark"))) }.toList
- expr = Block(dummies, wrapIntoTerm(expr))
-
- // [Eugene] how can we implement that?
- // !!! Why is this is in the empty package? If it's only to make
- // it inaccessible then please put it somewhere designed for that
- // rather than polluting the empty package with synthetics.
- val ownerClass = rootMirror.EmptyPackageClass.newClassSymbol(newTypeName("<expression-owner>"))
- build.setInfo(ownerClass, ClassInfoType(List(ObjectTpe), newScope, ownerClass))
- val owner = ownerClass.newLocalDummy(expr.pos)
- val currentTyper = analyzer.newTyper(analyzer.rootContext(NoCompilationUnit, EmptyTree).make(expr, owner))
- val wrapper1 = if (!withImplicitViewsDisabled) (currentTyper.context.withImplicitsEnabled[Tree] _) else (currentTyper.context.withImplicitsDisabled[Tree] _)
- val wrapper2 = if (!withMacrosDisabled) (currentTyper.context.withMacrosEnabled[Tree] _) else (currentTyper.context.withMacrosDisabled[Tree] _)
- def wrapper (tree: => Tree) = wrapper1(wrapper2(tree))
-
- val run = new Run
- run.symSource(ownerClass) = NoAbstractFile // need to set file to something different from null, so that currentRun.defines works
- phase = run.typerPhase // need to set a phase to something <= typerPhase, otherwise implicits in typedSelect will be disabled
- currentTyper.context.setReportErrors() // need to manually set context mode, otherwise typer.silent will throw exceptions
- reporter.reset()
-
- val expr1 = wrapper(transform(currentTyper, expr))
- var (dummies1, unwrapped) = expr1 match {
- case Block(dummies, unwrapped) => ((dummies, unwrapped))
- case unwrapped => ((Nil, unwrapped))
- }
- val invertedIndex = freeTerms map (_.swap)
- // todo. also fixup singleton types
- unwrapped = new Transformer {
- override def transform(tree: Tree): Tree =
- tree match {
- case Ident(name: TermName) if invertedIndex contains name =>
- Ident(invertedIndex(name)) setType tree.tpe
- case _ =>
- super.transform(tree)
- }
- }.transform(unwrapped)
- new TreeTypeSubstituter(dummies1 map (_.symbol), dummies1 map (dummy => SingleType(NoPrefix, invertedIndex(dummy.symbol.name.toTermName)))).traverse(unwrapped)
- unwrapped = if (expr0.isTerm) unwrapped else unwrapFromTerm(unwrapped)
- unwrapped
+ def transformDuringTyper(expr: Tree, mode: scala.reflect.internal.Mode, withImplicitViewsDisabled: Boolean, withMacrosDisabled: Boolean)(transform: (analyzer.Typer, Tree) => Tree): Tree = {
+ def withWrapping(tree: Tree)(op: Tree => Tree) = if (mode == TERMmode) wrappingIntoTerm(tree)(op) else op(tree)
+ withWrapping(verify(expr))(expr1 => {
+ // need to extract free terms, because otherwise you won't be able to typecheck macros against something that contains them
+ val exprAndFreeTerms = extractFreeTerms(expr1, wrapFreeTermRefs = false)
+ var expr2 = exprAndFreeTerms._1
+ val freeTerms = exprAndFreeTerms._2
+ val dummies = freeTerms.map{ case (freeTerm, name) => ValDef(NoMods, name, TypeTree(freeTerm.info), Select(Ident(PredefModule), newTermName("$qmark$qmark$qmark"))) }.toList
+ expr2 = Block(dummies, expr2)
+
+ // !!! Why is this is in the empty package? If it's only to make
+ // it inaccessible then please put it somewhere designed for that
+ // rather than polluting the empty package with synthetics.
+ // [Eugene] how can we implement that?
+ val ownerClass = rootMirror.EmptyPackageClass.newClassSymbol(newTypeName("<expression-owner>"))
+ build.setInfo(ownerClass, ClassInfoType(List(ObjectTpe), newScope, ownerClass))
+ val owner = ownerClass.newLocalDummy(expr2.pos)
+ val currentTyper = analyzer.newTyper(analyzer.rootContext(NoCompilationUnit, EmptyTree).make(expr2, owner))
+ val withImplicitFlag = if (!withImplicitViewsDisabled) (currentTyper.context.withImplicitsEnabled[Tree] _) else (currentTyper.context.withImplicitsDisabled[Tree] _)
+ val withMacroFlag = if (!withMacrosDisabled) (currentTyper.context.withMacrosEnabled[Tree] _) else (currentTyper.context.withMacrosDisabled[Tree] _)
+ def withContext (tree: => Tree) = withImplicitFlag(withMacroFlag(tree))
+
+ val run = new Run
+ run.symSource(ownerClass) = NoAbstractFile // need to set file to something different from null, so that currentRun.defines works
+ phase = run.typerPhase // need to set a phase to something <= typerPhase, otherwise implicits in typedSelect will be disabled
+ currentTyper.context.setReportErrors() // need to manually set context mode, otherwise typer.silent will throw exceptions
+ reporter.reset()
+
+ val expr3 = withContext(transform(currentTyper, expr2))
+ var (dummies1, result) = expr3 match {
+ case Block(dummies, result) => ((dummies, result))
+ case result => ((Nil, result))
+ }
+ val invertedIndex = freeTerms map (_.swap)
+ result = new Transformer {
+ override def transform(tree: Tree): Tree =
+ tree match {
+ case Ident(name: TermName) if invertedIndex contains name =>
+ Ident(invertedIndex(name)) setType tree.tpe
+ case _ =>
+ super.transform(tree)
+ }
+ }.transform(result)
+ new TreeTypeSubstituter(dummies1 map (_.symbol), dummies1 map (dummy => SingleType(NoPrefix, invertedIndex(dummy.symbol.name.toTermName)))).traverse(result)
+ result
+ })
}
def typecheck(expr: Tree, pt: Type, mode: scala.reflect.internal.Mode, silent: Boolean, withImplicitViewsDisabled: Boolean, withMacrosDisabled: Boolean): Tree =
- transformDuringTyper(expr, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled)(
+ transformDuringTyper(expr, mode, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled)(
(currentTyper, expr) => {
- trace("typing (implicit views = %s, macros = %s): ".format(!withImplicitViewsDisabled, !withMacrosDisabled))(showAttributed(expr, true, true, settings.Yshowsymkinds.value))
+ trace("typing (implicit views = %s, macros = %s): ".format(!withImplicitViewsDisabled, !withMacrosDisabled))(showAttributed(expr, true, true, settings.Yshowsymowners.value, settings.Yshowsymkinds.value))
currentTyper.silent(_.typed(expr, mode, pt), reportAmbiguousErrors = false) match {
case analyzer.SilentResultValue(result) =>
trace("success: ")(showAttributed(result, true, true, settings.Yshowsymkinds.value))
@@ -187,9 +180,9 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
})
def inferImplicit(tree: Tree, pt: Type, isView: Boolean, silent: Boolean, withMacrosDisabled: Boolean, pos: Position): Tree =
- transformDuringTyper(tree, withImplicitViewsDisabled = false, withMacrosDisabled = withMacrosDisabled)(
+ transformDuringTyper(tree, TERMmode, withImplicitViewsDisabled = false, withMacrosDisabled = withMacrosDisabled)(
(currentTyper, tree) => {
- trace("inferring implicit %s (macros = %s): ".format(if (isView) "view" else "value", !withMacrosDisabled))(showAttributed(pt, true, true, settings.Yshowsymkinds.value))
+ trace("inferring implicit %s (macros = %s): ".format(if (isView) "view" else "value", !withMacrosDisabled))(showAttributed(pt, true, true, settings.Yshowsymowners.value, settings.Yshowsymkinds.value))
analyzer.inferImplicit(tree, pt, isView, currentTyper.context, silent, withMacrosDisabled, pos, (pos, msg) => throw ToolBoxError(msg))
})
@@ -207,7 +200,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
}
def compile(expr0: Tree): () => Any = {
- val expr = wrapIntoTerm(expr0)
+ val expr = build.SyntacticBlock(expr0 :: Nil)
val freeTerms = expr.freeTerms // need to calculate them here, because later on they will be erased
val thunks = freeTerms map (fte => () => fte.value) // need to be lazy in order not to distort evaluation order
@@ -247,10 +240,10 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
List(),
List(methdef),
NoPosition))
- trace("wrapped: ")(showAttributed(moduledef, true, true, settings.Yshowsymkinds.value))
+ trace("wrapped: ")(showAttributed(moduledef, true, true, settings.Yshowsymowners.value, settings.Yshowsymkinds.value))
val cleanedUp = resetAttrs(moduledef)
- trace("cleaned up: ")(showAttributed(cleanedUp, true, true, settings.Yshowsymkinds.value))
+ trace("cleaned up: ")(showAttributed(cleanedUp, true, true, settings.Yshowsymowners.value, settings.Yshowsymkinds.value))
cleanedUp.asInstanceOf[ModuleDef]
}
@@ -298,19 +291,22 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
tree
}
- def showAttributed(artifact: Any, printTypes: Boolean = true, printIds: Boolean = true, printKinds: Boolean = false): String = {
+ def showAttributed(artifact: Any, printTypes: Boolean = true, printIds: Boolean = true, printOwners: Boolean = false, printKinds: Boolean = false): String = {
val saved1 = settings.printtypes.value
val saved2 = settings.uniqid.value
- val saved3 = settings.Yshowsymkinds.value
+ val saved3 = settings.Yshowsymowners.value
+ val saved4 = settings.Yshowsymkinds.value
try {
settings.printtypes.value = printTypes
settings.uniqid.value = printIds
+ settings.Yshowsymowners.value = printOwners
settings.Yshowsymkinds.value = printKinds
artifact.toString
} finally {
settings.printtypes.value = saved1
settings.uniqid.value = saved2
- settings.Yshowsymkinds.value = saved3
+ settings.Yshowsymowners.value = saved3
+ settings.Yshowsymkinds.value = saved4
}
}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
index 9f6807fe17..301e7051df 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
@@ -14,6 +14,7 @@ import scala.util.Try
*/
trait Parsers { self: Quasiquotes =>
import global.{Try => _, _}
+ import build.implodePatDefs
abstract class Parser extends {
val global: self.global.type = self.global
@@ -61,12 +62,10 @@ trait Parsers { self: Quasiquotes =>
override implicit def fresh: FreshNameCreator = parser.fresh
// q"(..$xs)"
- override def makeTupleTerm(trees: List[Tree]): Tree =
- Apply(Ident(nme.QUASIQUOTE_TUPLE), trees)
+ override def makeTupleTerm(trees: List[Tree]): Tree = TuplePlaceholder(trees)
// tq"(..$xs)"
- override def makeTupleType(trees: List[Tree]): Tree =
- AppliedTypeTree(Ident(tpnme.QUASIQUOTE_TUPLE), trees)
+ override def makeTupleType(trees: List[Tree]): Tree = TupleTypePlaceholder(trees)
// q"{ $x }"
override def makeBlock(stats: List[Tree]): Tree = stats match {
@@ -75,30 +74,32 @@ trait Parsers { self: Quasiquotes =>
}
// tq"$a => $b"
- override def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree =
- AppliedTypeTree(Ident(tpnme.QUASIQUOTE_FUNCTION), argtpes :+ restpe)
+ override def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = FunctionTypePlaceholder(argtpes, restpe)
+
+ // make q"val (x: T) = rhs" be equivalent to q"val x: T = rhs" for sake of bug compatibility (SI-8211)
+ override def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree) = pat match {
+ case TuplePlaceholder(inParensPat :: Nil) => super.makePatDef(mods, inParensPat, rhs)
+ case _ => super.makePatDef(mods, pat, rhs)
+ }
}
import treeBuilder.{global => _, unit => _, _}
- def quasiquoteParam(name: Name, flags: FlagSet = NoFlags) =
- ValDef(Modifiers(flags), name.toTermName, Ident(tpnme.QUASIQUOTE_PARAM), EmptyTree)
-
// q"def foo($x)"
override def param(owner: Name, implicitmod: Int, caseParam: Boolean): ValDef =
if (isHole && lookingAhead { in.token == COMMA || in.token == RPAREN }) {
- quasiquoteParam(ident(), implicitmod)
+ ParamPlaceholder(implicitmod, ident())
} else super.param(owner, implicitmod, caseParam)
// q"($x) => ..." && q"class X { selfie => }
override def convertToParam(tree: Tree): ValDef = tree match {
- case Ident(name) if isHole(name) => quasiquoteParam(name)
+ case Ident(name) if isHole(name) => ParamPlaceholder(NoFlags, name)
case _ => super.convertToParam(tree)
}
// q"foo match { case $x }"
override def caseClause(): CaseDef =
if (isHole && lookingAhead { in.token == CASE || in.token == RBRACE || in.token == SEMI }) {
- val c = makeCaseDef(Apply(Ident(nme.QUASIQUOTE_CASE), List(Ident(ident()))), EmptyTree, EmptyTree)
+ val c = CasePlaceholder(ident())
while (in.token == SEMI) in.nextToken()
c
} else
@@ -132,7 +133,7 @@ trait Parsers { self: Quasiquotes =>
in.nextToken()
annot :: readAnnots(annot)
case _ if isHole && lookingAhead { isAnnotation || isModifier || isDefIntro || isIdent || isStatSep || in.token == LPAREN } =>
- val ann = Apply(Select(New(Ident(tpnme.QUASIQUOTE_MODS)), nme.CONSTRUCTOR), List(Literal(Constant(in.name.toString))))
+ val ann = ModsPlaceholder(in.name)
in.nextToken()
ann :: readAnnots(annot)
case _ =>
@@ -141,13 +142,13 @@ trait Parsers { self: Quasiquotes =>
override def refineStat(): List[Tree] =
if (isHole && !isDclIntro) {
- val result = ValDef(NoMods, in.name, Ident(tpnme.QUASIQUOTE_REFINE_STAT), EmptyTree) :: Nil
+ val result = RefineStatPlaceholder(in.name) :: Nil
in.nextToken()
result
} else super.refineStat()
override def ensureEarlyDef(tree: Tree) = tree match {
- case Ident(name: TermName) if isHole(name) => ValDef(NoMods | Flag.PRESUPER, name, Ident(tpnme.QUASIQUOTE_EARLY_DEF), EmptyTree)
+ case Ident(name: TermName) if isHole(name) => EarlyDefPlaceholder(name)
case _ => super.ensureEarlyDef(tree)
}
@@ -158,14 +159,14 @@ trait Parsers { self: Quasiquotes =>
override def topStat = super.topStat.orElse {
case _ if isHole =>
- val stats = ValDef(NoMods, in.name, Ident(tpnme.QUASIQUOTE_PACKAGE_STAT), EmptyTree) :: Nil
+ val stats = PackageStatPlaceholder(in.name) :: Nil
in.nextToken()
stats
}
override def enumerator(isFirst: Boolean, allowNestedIf: Boolean = true) =
if (isHole && lookingAhead { in.token == EOF || in.token == RPAREN || isStatSep }) {
- val res = build.SyntacticValFrom(Bind(in.name, Ident(nme.WILDCARD)), Ident(nme.QUASIQUOTE_FOR_ENUM)) :: Nil
+ val res = ForEnumPlaceholder(in.name) :: Nil
in.nextToken()
res
} else super.enumerator(isFirst, allowNestedIf)
@@ -182,7 +183,7 @@ trait Parsers { self: Quasiquotes =>
}
object TermParser extends Parser {
- def entryPoint = parser => Q(gen.mkTreeOrBlock(parser.templateOrTopStatSeq()))
+ def entryPoint = parser => Q(implodePatDefs(gen.mkTreeOrBlock(parser.templateOrTopStatSeq())))
}
object TypeParser extends Parser {
@@ -195,7 +196,7 @@ trait Parsers { self: Quasiquotes =>
}
object CaseParser extends Parser {
- def entryPoint = _.caseClause()
+ def entryPoint = parser => implodePatDefs(parser.caseClause())
}
object PatternParser extends Parser {
@@ -209,7 +210,7 @@ trait Parsers { self: Quasiquotes =>
def entryPoint = { parser =>
val enums = parser.enumerator(isFirst = false, allowNestedIf = false)
assert(enums.length == 1)
- enums.head
+ implodePatDefs(enums.head)
}
}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
index 29df0ae670..e7730f878f 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
@@ -100,6 +100,8 @@ trait Placeholders { self: Quasiquotes =>
}
object ModsPlaceholder extends HolePlaceholder {
+ def apply(name: Name) =
+ Apply(Select(New(Ident(tpnme.QUASIQUOTE_MODS)), nme.CONSTRUCTOR), List(Literal(Constant(name.toString))))
def matching = {
case Apply(Select(New(Ident(tpnme.QUASIQUOTE_MODS)), nme.CONSTRUCTOR), List(Literal(Constant(s: String)))) => TermName(s)
}
@@ -112,12 +114,16 @@ trait Placeholders { self: Quasiquotes =>
}
object ParamPlaceholder extends HolePlaceholder {
+ def apply(flags: FlagSet, name: Name) =
+ ValDef(Modifiers(flags), nme.QUASIQUOTE_PARAM, Ident(name), EmptyTree)
def matching = {
- case ValDef(_, name, Ident(tpnme.QUASIQUOTE_PARAM), EmptyTree) => name
+ case ValDef(_, nme.QUASIQUOTE_PARAM, Ident(name), EmptyTree) => name
}
}
object TuplePlaceholder {
+ def apply(args: List[Tree]) =
+ Apply(Ident(nme.QUASIQUOTE_TUPLE), args)
def unapply(tree: Tree): Option[List[Tree]] = tree match {
case Apply(Ident(nme.QUASIQUOTE_TUPLE), args) => Some(args)
case _ => None
@@ -125,6 +131,8 @@ trait Placeholders { self: Quasiquotes =>
}
object TupleTypePlaceholder {
+ def apply(args: List[Tree]) =
+ AppliedTypeTree(Ident(tpnme.QUASIQUOTE_TUPLE), args)
def unapply(tree: Tree): Option[List[Tree]] = tree match {
case AppliedTypeTree(Ident(tpnme.QUASIQUOTE_TUPLE), args) => Some(args)
case _ => None
@@ -132,6 +140,8 @@ trait Placeholders { self: Quasiquotes =>
}
object FunctionTypePlaceholder {
+ def apply(args: List[Tree], res: Tree) =
+ AppliedTypeTree(Ident(tpnme.QUASIQUOTE_FUNCTION), args :+ res)
def unapply(tree: Tree): Option[(List[Tree], Tree)] = tree match {
case AppliedTypeTree(Ident(tpnme.QUASIQUOTE_FUNCTION), args :+ res) => Some((args, res))
case _ => None
@@ -146,6 +156,8 @@ trait Placeholders { self: Quasiquotes =>
}
object CasePlaceholder {
+ def apply(name: Name) =
+ CaseDef(Apply(Ident(nme.QUASIQUOTE_CASE), Ident(name) :: Nil), EmptyTree, EmptyTree)
def unapply(tree: Tree): Option[Hole] = tree match {
case CaseDef(Apply(Ident(nme.QUASIQUOTE_CASE), List(Placeholder(hole))), EmptyTree, EmptyTree) => Some(hole)
case _ => None
@@ -153,27 +165,35 @@ trait Placeholders { self: Quasiquotes =>
}
object RefineStatPlaceholder {
+ def apply(name: Name) =
+ ValDef(NoMods, nme.QUASIQUOTE_REFINE_STAT, Ident(name), EmptyTree)
def unapply(tree: Tree): Option[Hole] = tree match {
- case ValDef(_, Placeholder(hole), Ident(tpnme.QUASIQUOTE_REFINE_STAT), _) => Some(hole)
+ case ValDef(_, nme.QUASIQUOTE_REFINE_STAT, Ident(Placeholder(hole)), _) => Some(hole)
case _ => None
}
}
object EarlyDefPlaceholder {
+ def apply(name: Name) =
+ ValDef(Modifiers(Flag.PRESUPER), nme.QUASIQUOTE_EARLY_DEF, Ident(name), EmptyTree)
def unapply(tree: Tree): Option[Hole] = tree match {
- case ValDef(_, Placeholder(hole), Ident(tpnme.QUASIQUOTE_EARLY_DEF), _) => Some(hole)
+ case ValDef(_, nme.QUASIQUOTE_EARLY_DEF, Ident(Placeholder(hole)), _) => Some(hole)
case _ => None
}
}
object PackageStatPlaceholder {
+ def apply(name: Name) =
+ ValDef(NoMods, nme.QUASIQUOTE_PACKAGE_STAT, Ident(name), EmptyTree)
def unapply(tree: Tree): Option[Hole] = tree match {
- case ValDef(NoMods, Placeholder(hole), Ident(tpnme.QUASIQUOTE_PACKAGE_STAT), EmptyTree) => Some(hole)
+ case ValDef(NoMods, nme.QUASIQUOTE_PACKAGE_STAT, Ident(Placeholder(hole)), EmptyTree) => Some(hole)
case _ => None
}
}
object ForEnumPlaceholder {
+ def apply(name: Name) =
+ build.SyntacticValFrom(Bind(name, Ident(nme.WILDCARD)), Ident(nme.QUASIQUOTE_FOR_ENUM))
def unapply(tree: Tree): Option[Hole] = tree match {
case build.SyntacticValFrom(Bind(Placeholder(hole), Ident(nme.WILDCARD)), Ident(nme.QUASIQUOTE_FOR_ENUM)) =>
Some(hole)
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
index af8b0be92c..339937adc3 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
@@ -194,8 +194,8 @@ trait Reifiers { self: Quasiquotes =>
reifyBuildCall(nme.SyntacticEmptyTypeTree)
case SyntacticImport(expr, selectors) =>
reifyBuildCall(nme.SyntacticImport, expr, selectors)
- case Q(Placeholder(Hole(tree, DotDot))) =>
- mirrorBuildCall(nme.SyntacticBlock, tree)
+ case Q(tree) if fillListHole.isDefinedAt(tree) =>
+ mirrorBuildCall(nme.SyntacticBlock, fillListHole(tree))
case Q(other) =>
reifyTree(other)
// Syntactic block always matches so we have to be careful
@@ -311,11 +311,7 @@ trait Reifiers { self: Quasiquotes =>
*/
def reifyMultiCardinalityList(xs: List[Any])(fill: PartialFunction[Any, Tree])(fallback: Any => Tree): Tree
- /** Reifies arbitrary list filling ..$x and ...$y holeMap when they are put
- * in the correct position. Fallbacks to regular reification for non-high cardinality
- * elements.
- */
- override def reifyList(xs: List[Any]): Tree = reifyMultiCardinalityList(xs) {
+ val fillListHole: PartialFunction[Any, Tree] = {
case Placeholder(Hole(tree, DotDot)) => tree
case CasePlaceholder(Hole(tree, DotDot)) => tree
case RefineStatPlaceholder(h @ Hole(_, DotDot)) => reifyRefineStat(h)
@@ -323,12 +319,23 @@ trait Reifiers { self: Quasiquotes =>
case PackageStatPlaceholder(h @ Hole(_, DotDot)) => reifyPackageStat(h)
case ForEnumPlaceholder(Hole(tree, DotDot)) => tree
case ParamPlaceholder(Hole(tree, DotDot)) => tree
+ case SyntacticPatDef(mods, pat, tpt, rhs) =>
+ reifyBuildCall(nme.SyntacticPatDef, mods, pat, tpt, rhs)
+ case SyntacticValDef(mods, p @ Placeholder(h: ApplyHole), tpt, rhs) if h.tpe <:< treeType =>
+ mirrorBuildCall(nme.SyntacticPatDef, reify(mods), h.tree, reify(tpt), reify(rhs))
+ }
+
+ val fillListOfListsHole: PartialFunction[Any, Tree] = {
case List(ParamPlaceholder(Hole(tree, DotDotDot))) => tree
case List(Placeholder(Hole(tree, DotDotDot))) => tree
- } {
- reify(_)
}
+ /** Reifies arbitrary list filling ..$x and ...$y holeMap when they are put
+ * in the correct position. Fallbacks to regular reification for non-high cardinality
+ * elements.
+ */
+ override def reifyList(xs: List[Any]): Tree = reifyMultiCardinalityList(xs)(fillListHole.orElse(fillListOfListsHole))(reify)
+
def reifyAnnotList(annots: List[Tree]): Tree = reifyMultiCardinalityList(annots) {
case AnnotPlaceholder(h @ Hole(_, DotDot)) => reifyAnnotation(h)
} {