summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/CompilationUnits.scala14
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala19
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala24
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala13
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Scanners.scala2
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala18
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/xml/MarkupParserCommon.scala255
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/parser/xml/Utility.scala176
-rw-r--r--src/compiler/scala/tools/nsc/plugins/Plugin.scala7
-rw-r--r--src/compiler/scala/tools/nsc/plugins/PluginDescription.scala63
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala26
-rw-r--r--src/library/scala/Predef.scala8
-rw-r--r--src/library/scala/runtime/ScalaRunTime.scala7
-rw-r--r--src/library/scala/sys/process/Process.scala17
-rw-r--r--src/library/scala/sys/process/package.scala5
-rwxr-xr-xsrc/library/scala/xml/Elem.scala23
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala6
-rw-r--r--src/reflect/scala/reflect/internal/Mirrors.scala3
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala4
-rw-r--r--src/reflect/scala/reflect/internal/TreeInfo.scala17
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala2
-rw-r--r--test/files/neg/t7292-deprecation.check12
-rw-r--r--test/files/neg/t7292-removal.check12
-rw-r--r--test/files/pos/t7433.flags1
-rw-r--r--test/files/pos/t7433.scala10
-rw-r--r--test/files/pos/t7584.scala11
-rw-r--r--test/files/run/literals.check2
-rw-r--r--test/files/run/richs.check1
-rw-r--r--test/files/run/t7439.check2
-rw-r--r--test/files/run/t7439/A_1.java3
-rw-r--r--test/files/run/t7439/B_1.java3
-rw-r--r--test/files/run/t7439/Test_2.scala32
-rw-r--r--test/files/run/t7569.check12
-rw-r--r--test/files/run/t7569.scala19
-rw-r--r--test/files/run/t7584.check6
-rw-r--r--test/files/run/t7584.flags1
-rw-r--r--test/files/run/t7584.scala14
40 files changed, 747 insertions, 115 deletions
diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala
index 15d365ab8c..b52e6fdf57 100644
--- a/src/compiler/scala/tools/nsc/CompilationUnits.scala
+++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala
@@ -34,6 +34,20 @@ trait CompilationUnits { self: Global =>
/** the content of the compilation unit in tree form */
var body: Tree = EmptyTree
+ /** The position of the first xml literal encountered while parsing this compilation unit.
+ * NoPosition if there were none. Write-once.
+ */
+ private[this] var _firstXmlPos: Position = NoPosition
+
+ /** Record that we encountered XML. Should only be called once. */
+ protected[nsc] def encounteredXml(pos: Position) = _firstXmlPos = pos
+
+ /** Does this unit contain XML? */
+ def hasXml = _firstXmlPos ne NoPosition
+
+ /** Position of first XML literal in this unit. */
+ def firstXmlPos = _firstXmlPos
+
def exists = source != NoSourceFile && source != null
/** Note: depends now contains toplevel classes.
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index 692afbac66..c28a6ba337 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -19,11 +19,20 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
import global._
import definitions._
- /** Builds a fully attributed wildcard import node.
+ /** Builds a fully attributed, synthetic wildcard import node.
*/
- def mkWildcardImport(pkg: Symbol): Import = {
- assert(pkg ne null, this)
- val qual = gen.mkAttributedStableRef(pkg)
+ def mkWildcardImport(pkg: Symbol): Import =
+ mkImportFromSelector(pkg, ImportSelector.wildList)
+
+ /** Builds a fully attributed, synthetic import node.
+ * import `qualSym`.{`name` => `toName`}
+ */
+ def mkImport(qualSym: Symbol, name: Name, toName: Name): Import =
+ mkImportFromSelector(qualSym, ImportSelector(name, 0, toName, 0) :: Nil)
+
+ private def mkImportFromSelector(qualSym: Symbol, selector: List[ImportSelector]): Import = {
+ assert(qualSym ne null, this)
+ val qual = gen.mkAttributedStableRef(qualSym)
val importSym = (
NoSymbol
newImport NoPosition
@@ -31,7 +40,7 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
setInfo analyzer.ImportType(qual)
)
val importTree = (
- Import(qual, ImportSelector.wildList)
+ Import(qual, selector)
setSymbol importSym
setType NoType
)
diff --git a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala
index 832a9bf63e..d3f495f280 100755
--- a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala
@@ -10,8 +10,7 @@ import scala.collection.mutable
import mutable.{ Buffer, ArrayBuffer, ListBuffer }
import scala.util.control.ControlThrowable
import scala.tools.nsc.util.CharArrayReader
-import scala.xml.TextBuffer
-import scala.xml.parsing.MarkupParserCommon
+import scala.tools.nsc.ast.parser.xml.{MarkupParserCommon, Utility}
import scala.reflect.internal.Chars.{ SU, LF }
// XXX/Note: many/most of the functions in here are almost direct cut and pastes
@@ -42,7 +41,7 @@ trait MarkupParsers {
import global._
class MarkupParser(parser: SourceFileParser, final val preserveWS: Boolean) extends MarkupParserCommon {
-
+ import Utility.{ isNameStart, isSpace }
import Tokens.{ LBRACE, RBRACE }
type PositionType = Position
@@ -172,12 +171,21 @@ trait MarkupParsers {
xTakeUntil(handle.comment, () => r2p(start, start, curOffset), "-->")
}
- def appendText(pos: Position, ts: Buffer[Tree], txt: String) {
- val toAppend =
- if (preserveWS) Seq(txt)
- else TextBuffer.fromString(txt).toText map (_.text)
+ def appendText(pos: Position, ts: Buffer[Tree], txt: String): Unit = {
+ def append(t: String) = ts append handle.text(pos, t)
+
+ if (preserveWS) append(txt)
+ else {
+ val sb = new StringBuilder()
- toAppend foreach (t => ts append handle.text(pos, t))
+ txt foreach { c =>
+ if (!isSpace(c)) sb append c
+ else if (sb.isEmpty || !isSpace(sb.last)) sb append ' '
+ }
+
+ val trimmed = sb.toString.trim
+ if (!trimmed.isEmpty) append(trimmed)
+ }
}
/** adds entity/character to ts as side-effect
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index fc532f5d44..ef5872986c 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -166,13 +166,20 @@ self =>
def syntaxError(offset: Int, msg: String): Unit = throw new MalformedInput(offset, msg)
def incompleteInputError(msg: String): Unit = throw new MalformedInput(source.content.length - 1, msg)
- /** the markup parser */
- lazy val xmlp = new MarkupParser(this, preserveWS = true)
-
object symbXMLBuilder extends SymbolicXMLBuilder(this, preserveWS = true) { // DEBUG choices
val global: self.global.type = self.global
}
+ /** the markup parser
+ * The first time this lazy val is accessed, we assume we were trying to parse an xml literal.
+ * The current position is recorded for later error reporting if it turns out
+ * that we don't have the xml library on the compilation classpath.
+ */
+ private[this] lazy val xmlp = {
+ currentUnit.encounteredXml(o2p(in.offset))
+ new MarkupParser(this, preserveWS = true)
+ }
+
def xmlLiteral() : Tree = xmlp.xLiteral
def xmlLiteralPattern() : Tree = xmlp.xLiteralPattern
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index 80b6ad3cc7..2dca39f7a3 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -12,7 +12,7 @@ import Tokens._
import scala.annotation.{ switch, tailrec }
import scala.collection.{ mutable, immutable }
import mutable.{ ListBuffer, ArrayBuffer }
-import scala.xml.Utility.{ isNameStart }
+import scala.tools.nsc.ast.parser.xml.Utility.isNameStart
import scala.language.postfixOps
/** See Parsers.scala / ParsersCommon for some explanation of ScannersCommon.
diff --git a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala
index f326212d5b..1abc0c860c 100755
--- a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala
@@ -7,8 +7,6 @@ package scala.tools.nsc
package ast.parser
import scala.collection.{ mutable, immutable }
-import scala.xml.{ EntityRef, Text }
-import scala.xml.XML.{ xmlns }
import symtab.Flags.MUTABLE
import scala.reflect.internal.util.StringOps.splitWhere
@@ -143,14 +141,12 @@ abstract class SymbolicXMLBuilder(p: Parsers#Parser, preserveWS: Boolean) {
(buf map convertToTextPat).toList
def parseAttribute(pos: Position, s: String): Tree = {
- val ts = scala.xml.Utility.parseAttributeValue(s) map {
- case Text(s) => text(pos, s)
- case EntityRef(s) => entityRef(pos, s)
- }
- ts.length match {
- case 0 => gen.mkNil
- case 1 => ts.head
- case _ => makeXMLseq(pos, ts.toList)
+ import xml.Utility.parseAttributeValue
+
+ parseAttributeValue(s, text(pos, _), entityRef(pos, _)) match {
+ case Nil => gen.mkNil
+ case t :: Nil => t
+ case ts => makeXMLseq(pos, ts.toList)
}
}
@@ -198,7 +194,7 @@ abstract class SymbolicXMLBuilder(p: Parsers#Parser, preserveWS: Boolean) {
/* Extract all the namespaces from the attribute map. */
val namespaces: List[Tree] =
- for (z <- attrMap.keys.toList ; if z startsWith xmlns) yield {
+ for (z <- attrMap.keys.toList ; if z startsWith "xmlns") yield {
val ns = splitPrefix(z) match {
case (Some(_), rest) => rest
case _ => null
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index ec4e932aae..0ef71fa1b5 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -245,7 +245,7 @@ abstract class TreeBuilder {
/** Tree for `od op`, start is start0 if od.pos is borked. */
def makePostfixSelect(start0: Int, end: Int, od: Tree, op: Name): Tree = {
val start = if (od.pos.isDefined) od.pos.startOrPoint else start0
- atPos(r2p(start, end, end)) { new PostfixSelect(od, op.encode) }
+ atPos(r2p(start, end, end + op.length)) { new PostfixSelect(od, op.encode) }
}
/** A type tree corresponding to (possibly unary) intersection type */
diff --git a/src/compiler/scala/tools/nsc/ast/parser/xml/MarkupParserCommon.scala b/src/compiler/scala/tools/nsc/ast/parser/xml/MarkupParserCommon.scala
new file mode 100644
index 0000000000..f6cfb64ed8
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/parser/xml/MarkupParserCommon.scala
@@ -0,0 +1,255 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.tools.nsc.ast.parser.xml
+
+/** This is not a public trait - it contains common code shared
+ * between the library level XML parser and the compiler's.
+ * All members should be accessed through those.
+ */
+private[scala] trait MarkupParserCommon {
+ import Utility._
+ import scala.reflect.internal.Chars.SU
+
+ protected def unreachable = scala.sys.error("Cannot be reached.")
+
+ // type HandleType // MarkupHandler, SymbolicXMLBuilder
+ type InputType // Source, CharArrayReader
+ type PositionType // Int, Position
+ type ElementType // NodeSeq, Tree
+ type NamespaceType // NamespaceBinding, Any
+ type AttributesType // (MetaData, NamespaceBinding), mutable.Map[String, Tree]
+
+ def mkAttributes(name: String, pscope: NamespaceType): AttributesType
+ def mkProcInstr(position: PositionType, name: String, text: String): ElementType
+
+ /** parse a start or empty tag.
+ * [40] STag ::= '<' Name { S Attribute } [S]
+ * [44] EmptyElemTag ::= '<' Name { S Attribute } [S]
+ */
+ protected def xTag(pscope: NamespaceType): (String, AttributesType) = {
+ val name = xName
+ xSpaceOpt()
+
+ (name, mkAttributes(name, pscope))
+ }
+
+ /** '<?' ProcInstr ::= Name [S ({Char} - ({Char}'>?' {Char})]'?>'
+ *
+ * see [15]
+ */
+ def xProcInstr: ElementType = {
+ val n = xName
+ xSpaceOpt()
+ xTakeUntil(mkProcInstr(_, n, _), () => tmppos, "?>")
+ }
+
+ /** attribute value, terminated by either `'` or `"`. value may not contain `<`.
+ @param endCh either `'` or `"`
+ */
+ def xAttributeValue(endCh: Char): String = {
+ val buf = new StringBuilder
+ while (ch != endCh) {
+ // well-formedness constraint
+ if (ch == '<') return errorAndResult("'<' not allowed in attrib value", "")
+ else if (ch == SU) truncatedError("")
+ else buf append ch_returning_nextch
+ }
+ ch_returning_nextch
+ // @todo: normalize attribute value
+ buf.toString
+ }
+
+ def xAttributeValue(): String = {
+ val str = xAttributeValue(ch_returning_nextch)
+ // well-formedness constraint
+ normalizeAttributeValue(str)
+ }
+
+ private def takeUntilChar(it: Iterator[Char], end: Char): String = {
+ val buf = new StringBuilder
+ while (it.hasNext) it.next() match {
+ case `end` => return buf.toString
+ case ch => buf append ch
+ }
+ scala.sys.error("Expected '%s'".format(end))
+ }
+
+ /** [42] '<' xmlEndTag ::= '<' '/' Name S? '>'
+ */
+ def xEndTag(startName: String) {
+ xToken('/')
+ if (xName != startName)
+ errorNoEnd(startName)
+
+ xSpaceOpt()
+ xToken('>')
+ }
+
+ /** actually, Name ::= (Letter | '_' | ':') (NameChar)* but starting with ':' cannot happen
+ * Name ::= (Letter | '_') (NameChar)*
+ *
+ * see [5] of XML 1.0 specification
+ *
+ * pre-condition: ch != ':' // assured by definition of XMLSTART token
+ * post-condition: name does neither start, nor end in ':'
+ */
+ def xName: String = {
+ if (ch == SU)
+ truncatedError("")
+ else if (!isNameStart(ch))
+ return errorAndResult("name expected, but char '%s' cannot start a name" format ch, "")
+
+ val buf = new StringBuilder
+
+ do buf append ch_returning_nextch
+ while (isNameChar(ch))
+
+ if (buf.last == ':') {
+ reportSyntaxError( "name cannot end in ':'" )
+ buf.toString dropRight 1
+ }
+ else buf.toString
+ }
+
+ private def attr_unescape(s: String) = s match {
+ case "lt" => "<"
+ case "gt" => ">"
+ case "amp" => "&"
+ case "apos" => "'"
+ case "quot" => "\""
+ case "quote" => "\""
+ case _ => "&" + s + ";"
+ }
+
+ /** Replaces only character references right now.
+ * see spec 3.3.3
+ */
+ private def normalizeAttributeValue(attval: String): String = {
+ val buf = new StringBuilder
+ val it = attval.iterator.buffered
+
+ while (it.hasNext) buf append (it.next() match {
+ case ' ' | '\t' | '\n' | '\r' => " "
+ case '&' if it.head == '#' => it.next() ; xCharRef(it)
+ case '&' => attr_unescape(takeUntilChar(it, ';'))
+ case c => c
+ })
+
+ buf.toString
+ }
+
+ /** CharRef ::= "&#" '0'..'9' {'0'..'9'} ";"
+ * | "&#x" '0'..'9'|'A'..'F'|'a'..'f' { hexdigit } ";"
+ *
+ * see [66]
+ */
+ def xCharRef(ch: () => Char, nextch: () => Unit): String =
+ Utility.parseCharRef(ch, nextch, reportSyntaxError _, truncatedError _)
+
+ def xCharRef(it: Iterator[Char]): String = {
+ var c = it.next()
+ Utility.parseCharRef(() => c, () => { c = it.next() }, reportSyntaxError _, truncatedError _)
+ }
+
+ def xCharRef: String = xCharRef(() => ch, () => nextch())
+
+ /** Create a lookahead reader which does not influence the input */
+ def lookahead(): BufferedIterator[Char]
+
+ /** The library and compiler parsers had the interesting distinction of
+ * different behavior for nextch (a function for which there are a total
+ * of two plausible behaviors, so we know the design space was fully
+ * explored.) One of them returned the value of nextch before the increment
+ * and one of them the new value. So to unify code we have to at least
+ * temporarily abstract over the nextchs.
+ */
+ def ch: Char
+ def nextch(): Unit
+ protected def ch_returning_nextch: Char
+ def eof: Boolean
+
+ // def handle: HandleType
+ var tmppos: PositionType
+
+ def xHandleError(that: Char, msg: String): Unit
+ def reportSyntaxError(str: String): Unit
+ def reportSyntaxError(pos: Int, str: String): Unit
+
+ def truncatedError(msg: String): Nothing
+ def errorNoEnd(tag: String): Nothing
+
+ protected def errorAndResult[T](msg: String, x: T): T = {
+ reportSyntaxError(msg)
+ x
+ }
+
+ def xToken(that: Char) {
+ if (ch == that) nextch()
+ else xHandleError(that, "'%s' expected instead of '%s'".format(that, ch))
+ }
+ def xToken(that: Seq[Char]) { that foreach xToken }
+
+ /** scan [S] '=' [S]*/
+ def xEQ() = { xSpaceOpt(); xToken('='); xSpaceOpt() }
+
+ /** skip optional space S? */
+ def xSpaceOpt() = while (isSpace(ch) && !eof) nextch()
+
+ /** scan [3] S ::= (#x20 | #x9 | #xD | #xA)+ */
+ def xSpace() =
+ if (isSpace(ch)) { nextch(); xSpaceOpt() }
+ else xHandleError(ch, "whitespace expected")
+
+ /** Apply a function and return the passed value */
+ def returning[T](x: T)(f: T => Unit): T = { f(x); x }
+
+ /** Execute body with a variable saved and restored after execution */
+ def saving[A, B](getter: A, setter: A => Unit)(body: => B): B = {
+ val saved = getter
+ try body
+ finally setter(saved)
+ }
+
+ /** Take characters from input stream until given String "until"
+ * is seen. Once seen, the accumulated characters are passed
+ * along with the current Position to the supplied handler function.
+ */
+ protected def xTakeUntil[T](
+ handler: (PositionType, String) => T,
+ positioner: () => PositionType,
+ until: String): T =
+ {
+ val sb = new StringBuilder
+ val head = until.head
+ val rest = until.tail
+
+ while (true) {
+ if (ch == head && peek(rest))
+ return handler(positioner(), sb.toString)
+ else if (ch == SU)
+ truncatedError("") // throws TruncatedXMLControl in compiler
+
+ sb append ch
+ nextch()
+ }
+ unreachable
+ }
+
+ /** Create a non-destructive lookahead reader and see if the head
+ * of the input would match the given String. If yes, return true
+ * and drop the entire String from input; if no, return false
+ * and leave input unchanged.
+ */
+ private def peek(lookingFor: String): Boolean =
+ (lookahead() take lookingFor.length sameElements lookingFor.iterator) && {
+ // drop the chars from the real reader (all lookahead + orig)
+ (0 to lookingFor.length) foreach (_ => nextch())
+ true
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/xml/Utility.scala b/src/compiler/scala/tools/nsc/ast/parser/xml/Utility.scala
new file mode 100755
index 0000000000..39e4831af2
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/parser/xml/Utility.scala
@@ -0,0 +1,176 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.tools.nsc.ast.parser.xml
+
+import scala.collection.mutable
+
+
+/**
+ * The `Utility` object provides utility functions for processing instances
+ * of bound and not bound XML classes, as well as escaping text nodes.
+ *
+ * @author Burak Emir
+ */
+object Utility {
+ import scala.reflect.internal.Chars.SU
+
+ private val unescMap = Map(
+ "lt" -> '<',
+ "gt" -> '>',
+ "amp" -> '&',
+ "quot" -> '"',
+ "apos" -> '\''
+ )
+
+ /**
+ * Appends unescaped string to `s`, `amp` becomes `&amp;`,
+ * `lt` becomes `&lt;` etc..
+ *
+ * @return `'''null'''` if `ref` was not a predefined entity.
+ */
+ private final def unescape(ref: String, s: StringBuilder): StringBuilder =
+ ((unescMap get ref) map (s append _)).orNull
+
+ def parseAttributeValue[T](value: String, text: String => T, entityRef: String => T): List[T] = {
+ val sb = new StringBuilder
+ var rfb: StringBuilder = null
+ val nb = new mutable.ListBuffer[T]()
+
+ val it = value.iterator
+ while (it.hasNext) {
+ var c = it.next()
+ // entity! flush buffer into text node
+ if (c == '&') {
+ c = it.next()
+ if (c == '#') {
+ c = it.next()
+ val theChar = parseCharRef ({ ()=> c },{ () => c = it.next() },{s => throw new RuntimeException(s)}, {s => throw new RuntimeException(s)})
+ sb.append(theChar)
+ }
+ else {
+ if (rfb eq null) rfb = new StringBuilder()
+ rfb append c
+ c = it.next()
+ while (c != ';') {
+ rfb.append(c)
+ c = it.next()
+ }
+ val ref = rfb.toString()
+ rfb.clear()
+ unescape(ref,sb) match {
+ case null =>
+ if (!sb.isEmpty) { // flush buffer
+ nb += text(sb.toString())
+ sb.clear()
+ }
+ nb += entityRef(ref) // add entityref
+ case _ =>
+ }
+ }
+ }
+ else sb append c
+ }
+
+ if(!sb.isEmpty) // flush buffer
+ nb += text(sb.toString())
+
+ nb.toList
+ }
+
+ /**
+ * {{{
+ * CharRef ::= "&amp;#" '0'..'9' {'0'..'9'} ";"
+ * | "&amp;#x" '0'..'9'|'A'..'F'|'a'..'f' { hexdigit } ";"
+ * }}}
+ * See [66]
+ */
+ def parseCharRef(ch: () => Char, nextch: () => Unit, reportSyntaxError: String => Unit, reportTruncatedError: String => Unit): String = {
+ val hex = (ch() == 'x') && { nextch(); true }
+ val base = if (hex) 16 else 10
+ var i = 0
+ while (ch() != ';') {
+ ch() match {
+ case '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' =>
+ i = i * base + ch().asDigit
+ case 'a' | 'b' | 'c' | 'd' | 'e' | 'f'
+ | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' =>
+ if (! hex)
+ reportSyntaxError("hex char not allowed in decimal char ref\n" +
+ "Did you mean to write &#x ?")
+ else
+ i = i * base + ch().asDigit
+ case SU =>
+ reportTruncatedError("")
+ case _ =>
+ reportSyntaxError("character '" + ch() + "' not allowed in char ref\n")
+ }
+ nextch()
+ }
+ new String(Array(i), 0, 1)
+ }
+
+ /** {{{
+ * (#x20 | #x9 | #xD | #xA)
+ * }}} */
+ final def isSpace(ch: Char): Boolean = ch match {
+ case '\u0009' | '\u000A' | '\u000D' | '\u0020' => true
+ case _ => false
+ }
+ /** {{{
+ * (#x20 | #x9 | #xD | #xA)+
+ * }}} */
+ final def isSpace(cs: Seq[Char]): Boolean = cs.nonEmpty && (cs forall isSpace)
+
+ /** {{{
+ * NameChar ::= Letter | Digit | '.' | '-' | '_' | ':'
+ * | CombiningChar | Extender
+ * }}}
+ * See [4] and Appendix B of XML 1.0 specification.
+ */
+ def isNameChar(ch: Char) = {
+ import java.lang.Character._
+ // The constants represent groups Mc, Me, Mn, Lm, and Nd.
+
+ isNameStart(ch) || (getType(ch).toByte match {
+ case COMBINING_SPACING_MARK |
+ ENCLOSING_MARK | NON_SPACING_MARK |
+ MODIFIER_LETTER | DECIMAL_DIGIT_NUMBER => true
+ case _ => ".-:" contains ch
+ })
+ }
+
+ /** {{{
+ * NameStart ::= ( Letter | '_' )
+ * }}}
+ * where Letter means in one of the Unicode general
+ * categories `{ Ll, Lu, Lo, Lt, Nl }`.
+ *
+ * We do not allow a name to start with `:`.
+ * See [3] and Appendix B of XML 1.0 specification
+ */
+ def isNameStart(ch: Char) = {
+ import java.lang.Character._
+
+ getType(ch).toByte match {
+ case LOWERCASE_LETTER |
+ UPPERCASE_LETTER | OTHER_LETTER |
+ TITLECASE_LETTER | LETTER_NUMBER => true
+ case _ => ch == '_'
+ }
+ }
+
+ /** {{{
+ * Name ::= ( Letter | '_' ) (NameChar)*
+ * }}}
+ * See [5] of XML 1.0 specification.
+ */
+ def isName(s: String) =
+ s.nonEmpty && isNameStart(s.head) && (s.tail forall isNameChar)
+
+}
diff --git a/src/compiler/scala/tools/nsc/plugins/Plugin.scala b/src/compiler/scala/tools/nsc/plugins/Plugin.scala
index a584a4ed5d..4fd6ba7d9d 100644
--- a/src/compiler/scala/tools/nsc/plugins/Plugin.scala
+++ b/src/compiler/scala/tools/nsc/plugins/Plugin.scala
@@ -14,7 +14,6 @@ import java.util.zip.ZipException
import scala.collection.mutable.ListBuffer
import scala.util.{ Try, Success, Failure }
-import scala.xml.XML
/** Information about a plugin loaded from a jar file.
*
@@ -81,14 +80,14 @@ object Plugin {
private def loadDescriptionFromJar(jarp: Path): Try[PluginDescription] = {
// XXX Return to this once we have more ARM support
def read(is: Option[InputStream]) = is match {
- case None => throw new RuntimeException(s"Missing $PluginXML in $jarp")
- case _ => PluginDescription fromXML (XML load is.get)
+ case None => throw new RuntimeException(s"Missing $PluginXML in $jarp")
+ case Some(is) => PluginDescription.fromXML(is)
}
Try(new Jar(jarp.jfile).withEntryStream(PluginXML)(read))
}
private def loadDescriptionFromFile(f: Path): Try[PluginDescription] =
- Try(XML loadFile f.jfile) map (PluginDescription fromXML _)
+ Try(PluginDescription.fromXML(new java.io.FileInputStream(f.jfile)))
type AnyClass = Class[_]
diff --git a/src/compiler/scala/tools/nsc/plugins/PluginDescription.scala b/src/compiler/scala/tools/nsc/plugins/PluginDescription.scala
index 27693d1a45..bf78c93fcc 100644
--- a/src/compiler/scala/tools/nsc/plugins/PluginDescription.scala
+++ b/src/compiler/scala/tools/nsc/plugins/PluginDescription.scala
@@ -6,57 +6,50 @@
package scala.tools.nsc
package plugins
-import scala.xml.Node
+import scala.reflect.internal.util.StringContextStripMarginOps
/** A description of a compiler plugin, suitable for serialization
* to XML for inclusion in the plugin's .jar file.
*
* @author Lex Spoon
* @version 1.0, 2007-5-21
- * @param name A short name of the plugin, used to identify it in
- * various contexts. The phase defined by the plugin
- * should have the same name.
- * @param classname The name of the main Plugin class.
+ * @author Adriaan Moors
+ * @version 2.0, 2013
+ * @param name A short name of the plugin, used to identify it in
+ * various contexts. The phase defined by the plugin
+ * should have the same name.
+ * @param classname The name of the main Plugin class.
*/
case class PluginDescription(name: String, classname: String) {
-
- /** An XML representation of this description. It can be
- * read back using `PluginDescription.fromXML`.
+ /** An XML representation of this description.
* It should be stored inside the jar archive file.
*/
- def toXML: Node = {
- <plugin>
- <name>{name}</name>
- <classname>{classname}</classname>
- </plugin>
- }
+ def toXML: String =
+ sm"""<plugin>
+ | <name>${name}</name>
+ | <classname>${classname}</classname>
+ |</plugin>"""
}
/** Utilities for the PluginDescription class.
*
- * @author Lex Spoon
- * @version 1.0, 2007-5-21
+ * @author Lex Spoon
+ * @version 1.0, 2007-5-21
+ * @author Adriaan Moors
+ * @version 2.0, 2013
*/
object PluginDescription {
+ private def text(ns: org.w3c.dom.NodeList): String =
+ if (ns.getLength == 1) ns.item(0).getTextContent.trim
+ else throw new RuntimeException("Bad plugin descriptor.")
+
+ def fromXML(xml: java.io.InputStream): PluginDescription = {
+ import javax.xml.parsers.DocumentBuilderFactory
+ val root = DocumentBuilderFactory.newInstance.newDocumentBuilder.parse(xml).getDocumentElement
+ root.normalize()
+ if (root.getNodeName != "plugin")
+ throw new RuntimeException("Plugin descriptor root element must be <plugin>.")
- def fromXML(xml: Node): PluginDescription = {
- // extract one field
- def getField(field: String): Option[String] = {
- val text = (xml \\ field).text.trim
- if (text == "") None else Some(text)
- }
- def extracted = {
- val name = "name"
- val claas = "classname"
- val vs = Map(name -> getField(name), claas -> getField(claas))
- if (vs.values exists (_.isEmpty)) fail()
- else PluginDescription(name = vs(name).get, classname = vs(claas).get)
- }
- def fail() = throw new RuntimeException("Bad plugin descriptor.")
- // check the top-level tag
- xml match {
- case <plugin>{_*}</plugin> => extracted
- case _ => fail()
- }
+ PluginDescription(text(root.getElementsByTagName("name")), text(root.getElementsByTagName("classname")))
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 64f4e579e1..e2ce2743f7 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -187,8 +187,14 @@ abstract class UnCurry extends InfoTransform
val keyDef = ValDef(key, New(ObjectTpe))
val tryCatch = Try(body, pat -> rhs)
- for (Try(t, catches, _) <- body ; cdef <- catches ; if treeInfo catchesThrowable cdef)
+ import treeInfo.{catchesThrowable, isSyntheticCase}
+ for {
+ Try(t, catches, _) <- body
+ cdef <- catches
+ if catchesThrowable(cdef) && !isSyntheticCase(cdef)
+ } {
unit.warning(body.pos, "catch block may intercept non-local return from " + meth)
+ }
Block(List(keyDef), tryCatch)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index 61967d4cee..1f4ff7cc2d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -16,7 +16,7 @@ import scala.reflect.internal.util.shortClassOfInstance
*/
trait Contexts { self: Analyzer =>
import global._
- import definitions.{ JavaLangPackage, ScalaPackage, PredefModule }
+ import definitions.{ JavaLangPackage, ScalaPackage, PredefModule, ScalaXmlTopScope, ScalaXmlPackage }
import ContextMode._
object NoContext
@@ -93,9 +93,31 @@ trait Contexts { self: Analyzer =>
else RootImports.completeList
}
+
def rootContext(unit: CompilationUnit, tree: Tree = EmptyTree, erasedTypes: Boolean = false): Context = {
val rootImportsContext = (startContext /: rootImports(unit))((c, sym) => c.make(gen.mkWildcardImport(sym)))
- val c = rootImportsContext.make(tree, unit = unit)
+
+ // there must be a scala.xml package when xml literals were parsed in this unit
+ if (unit.hasXml && ScalaXmlPackage == NoSymbol)
+ unit.error(unit.firstXmlPos, "XML literals may only be used if the package scala.xml is present in the compilation classpath.")
+
+ // TODO: remove the def below and drop `|| predefDefinesDollarScope` in the condition for `contextWithXML`
+ // as soon as 2.11.0-M4 is released and used as STARR (and $scope is no longer defined in Predef)
+ // Until then, to allow compiling quick with pre-2.11.0-M4 STARR,
+ // which relied on Predef defining `val $scope`, we've left it in place.
+ // Since the new scheme also imports $scope (as an alias for scala.xml.TopScope),
+ // we must check whether it is still there and not import the alias to avoid ambiguity.
+ // (All of this is only necessary to compile the full quick stage with STARR.
+ // if using locker, Predef.$scope is no longer needed.)
+ def predefDefinesDollarScope = definitions.getMemberIfDefined(PredefModule, nme.dollarScope) != NoSymbol
+
+ // hack for the old xml library (detected by looking for scala.xml.TopScope, which needs to be in scope as $scope)
+ // import scala.xml.{TopScope => $scope}
+ val contextWithXML =
+ if (!unit.hasXml || ScalaXmlTopScope == NoSymbol || predefDefinesDollarScope) rootImportsContext
+ else rootImportsContext.make(gen.mkImport(ScalaXmlPackage, nme.TopScope, nme.dollarScope))
+
+ val c = contextWithXML.make(tree, unit = unit)
if (erasedTypes) c.setThrowErrors() else c.setReportErrors()
c(EnrichmentEnabled | ImplicitsEnabled) = !erasedTypes
c
diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala
index 5ba38600b6..a188602543 100644
--- a/src/library/scala/Predef.scala
+++ b/src/library/scala/Predef.scala
@@ -134,7 +134,13 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef {
@inline def implicitly[T](implicit e: T) = e // for summoning implicit values from the nether world -- TODO: when dependent method types are on by default, give this result type `e.type`, so that inliner has better chance of knowing which method to inline in calls like `implicitly[MatchingStrategy[Option]].zero`
@inline def locally[T](x: T): T = x // to communicate intent and avoid unmoored statements
- // Apparently needed for the xml library
+ // TODO: remove `val $scope = ...` as soon as 2.11.0-M4 is released and used as STARR
+ // As it has a '$' in its name, we don't have to deprecate first.
+ // The compiler now aliases `scala.xml.TopScope` to `$scope` (unless Predef.$scope is still there).
+ // This definition left in place for older compilers and to compile quick with pre-2.11.0-M4 STARR.
+ // In principle we don't need it to compile library/reflect/compiler (there's no xml left there),
+ // so a new locker can be built without this definition, and locker can build quick
+ // (partest, scaladoc still require xml).
val $scope = scala.xml.TopScope
// errors and asserts -------------------------------------------------
diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala
index 3a85207235..c049de3a28 100644
--- a/src/library/scala/runtime/ScalaRunTime.scala
+++ b/src/library/scala/runtime/ScalaRunTime.scala
@@ -15,7 +15,6 @@ import scala.collection.immutable.{ StringLike, NumericRange, List, Stream, Nil,
import scala.collection.generic.{ Sorted }
import scala.reflect.{ ClassTag, classTag }
import scala.util.control.ControlThrowable
-import scala.xml.{ Node, MetaData }
import java.lang.{ Class => jClass }
import java.lang.Double.doubleToLongBits
@@ -268,11 +267,10 @@ object ScalaRunTime {
}
def isScalaClass(x: AnyRef) = packageOf(x) startsWith "scala."
def isScalaCompilerClass(x: AnyRef) = packageOf(x) startsWith "scala.tools.nsc."
+ def isXmlClass(x: AnyRef) = packageOf(x) startsWith "scala.xml."
// When doing our own iteration is dangerous
def useOwnToString(x: Any) = x match {
- // Node extends NodeSeq extends Seq[Node] and MetaData extends Iterable[MetaData]
- case _: Node | _: MetaData => true
// Range/NumericRange have a custom toString to avoid walking a gazillion elements
case _: Range | _: NumericRange[_] => true
// Sorted collections to the wrong thing (for us) on iteration - ticket #3493
@@ -281,10 +279,11 @@ object ScalaRunTime {
case _: StringLike[_] => true
// Don't want to evaluate any elements in a view
case _: TraversableView[_, _] => true
+ // Node extends NodeSeq extends Seq[Node] and MetaData extends Iterable[MetaData] -> catch those and more by isXmlClass(x)
// Don't want to a) traverse infinity or b) be overly helpful with peoples' custom
// collections which may have useful toString methods - ticket #3710
// or c) print AbstractFiles which are somehow also Iterable[AbstractFile]s.
- case x: Traversable[_] => !x.hasDefiniteSize || !isScalaClass(x) || isScalaCompilerClass(x)
+ case x: Traversable[_] => !x.hasDefiniteSize || !isScalaClass(x) || isScalaCompilerClass(x) || isXmlClass(x)
// Otherwise, nothing could possibly go wrong
case _ => false
}
diff --git a/src/library/scala/sys/process/Process.scala b/src/library/scala/sys/process/Process.scala
index 402183a1f0..dcd06c89e9 100644
--- a/src/library/scala/sys/process/Process.scala
+++ b/src/library/scala/sys/process/Process.scala
@@ -127,15 +127,6 @@ trait ProcessCreation {
*/
def apply(url: URL): URLBuilder = new URLImpl(url)
- /** Creates a [[scala.sys.process.ProcessBuilder]] from a Scala XML Element.
- * This can be used as a way to template strings.
- *
- * @example {{{
- * apply(<x> {dxPath.absolutePath} --dex --output={classesDexPath.absolutePath} {classesMinJarPath.absolutePath}</x>)
- * }}}
- */
- def apply(command: scala.xml.Elem): ProcessBuilder = apply(command.text.trim)
-
/** Creates a [[scala.sys.process.ProcessBuilder]] from a `Boolean`. This can be
* to force an exit value.
*/
@@ -220,14 +211,6 @@ trait ProcessImplicits {
*/
implicit def urlToProcess(url: URL): URLBuilder = apply(url)
- /** Implicitly convert a [[scala.xml.Elem]] into a
- * [[scala.sys.process.ProcessBuilder]]. This is done by obtaining the text
- * elements of the element, trimming spaces, and then converting the result
- * from string to a process. Importantly, tags are completely ignored, so
- * they cannot be used to separate parameters.
- */
- implicit def xmlToProcess(command: scala.xml.Elem): ProcessBuilder = apply(command)
-
/** Implicitly convert a `String` into a [[scala.sys.process.ProcessBuilder]]. */
implicit def stringToProcess(command: String): ProcessBuilder = apply(command)
diff --git a/src/library/scala/sys/process/package.scala b/src/library/scala/sys/process/package.scala
index 902543665f..d68cd004f8 100644
--- a/src/library/scala/sys/process/package.scala
+++ b/src/library/scala/sys/process/package.scala
@@ -80,10 +80,7 @@ package scala.sys {
* spaces -- no escaping of spaces is possible -- or out of a
* [[scala.collection.Seq]], where the first element represents the command
* name, and the remaining elements are arguments to it. In this latter case,
- * arguments may contain spaces. One can also implicitly convert
- * [[scala.xml.Elem]] and `java.lang.ProcessBuilder` into a `ProcessBuilder`.
- * In the introductory example, the strings were converted into
- * `ProcessBuilder` implicitly.
+ * arguments may contain spaces.
*
* To further control what how the process will be run, such as specifying
* the directory in which it will be run, see the factories on
diff --git a/src/library/scala/xml/Elem.scala b/src/library/scala/xml/Elem.scala
index 4200b7046a..484cf98744 100755
--- a/src/library/scala/xml/Elem.scala
+++ b/src/library/scala/xml/Elem.scala
@@ -35,8 +35,31 @@ object Elem {
case _: SpecialNode | _: Group => None
case _ => Some((n.prefix, n.label, n.attributes, n.scope, n.child))
}
+
+ import scala.sys.process._
+ /** Implicitly convert a [[scala.xml.Elem]] into a
+ * [[scala.sys.process.ProcessBuilder]]. This is done by obtaining the text
+ * elements of the element, trimming spaces, and then converting the result
+ * from string to a process. Importantly, tags are completely ignored, so
+ * they cannot be used to separate parameters.
+ */
+ @deprecated("To create a scala.sys.process.Process from an xml.Elem, please use Process(elem.text.trim).", "2.11.0")
+ implicit def xmlToProcess(command: scala.xml.Elem): ProcessBuilder = Process(command.text.trim)
+
+ @deprecated("To create a scala.sys.process.Process from an xml.Elem, please use Process(elem.text.trim).", "2.11.0")
+ implicit def processXml(p: Process.type) = new {
+ /** Creates a [[scala.sys.process.ProcessBuilder]] from a Scala XML Element.
+ * This can be used as a way to template strings.
+ *
+ * @example {{{
+ * apply(<x> {dxPath.absolutePath} --dex --output={classesDexPath.absolutePath} {classesMinJarPath.absolutePath}</x>)
+ * }}}
+ */
+ def apply(command: Elem): ProcessBuilder = Process(command.text.trim)
+ }
}
+
/** The case class `Elem` extends the `Node` class,
* providing an immutable data object representing an XML element.
*
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 4f2b7e2642..3470b05495 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -16,7 +16,7 @@ import scala.reflect.api.{Universe => ApiUniverse}
trait Definitions extends api.StandardDefinitions {
self: SymbolTable =>
- import rootMirror.{getModule, getPackage, getClassByName, getRequiredClass, getRequiredModule, getClassIfDefined, getModuleIfDefined, getPackageObject, getPackageObjectIfDefined, requiredClass, requiredModule}
+ import rootMirror.{getModule, getPackage, getClassByName, getRequiredClass, getRequiredModule, getClassIfDefined, getModuleIfDefined, getPackageObject, getPackageIfDefined, getPackageObjectIfDefined, requiredClass, requiredModule}
object definitions extends DefinitionsClass
@@ -471,6 +471,10 @@ trait Definitions extends api.StandardDefinitions {
def methodCache_find = getMemberMethod(MethodCacheClass, nme.find_)
def methodCache_add = getMemberMethod(MethodCacheClass, nme.add_)
+ // XML
+ lazy val ScalaXmlTopScope = getModuleIfDefined("scala.xml.TopScope")
+ lazy val ScalaXmlPackage = getPackageIfDefined("scala.xml")
+
// scala.reflect
lazy val ReflectPackage = requiredModule[scala.reflect.`package`.type]
lazy val ReflectApiPackage = getPackageObjectIfDefined("scala.reflect.api") // defined in scala-reflect.jar, so we need to be careful
diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala
index bf38c3bf1e..6ed9de8e20 100644
--- a/src/reflect/scala/reflect/internal/Mirrors.scala
+++ b/src/reflect/scala/reflect/internal/Mirrors.scala
@@ -176,6 +176,9 @@ trait Mirrors extends api.Mirrors {
def getPackage(fullname: TermName): ModuleSymbol =
ensurePackageSymbol(fullname.toString, getModuleOrClass(fullname), allowModules = true)
+ def getPackageIfDefined(fullname: TermName): Symbol =
+ wrapMissing(getPackage(fullname))
+
@deprecated("Use getPackage", "2.11.0") def getRequiredPackage(fullname: String): ModuleSymbol =
getPackage(newTermNameCached(fullname))
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index 81fffc833c..30aaaa1f3a 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -599,6 +599,7 @@ trait StdNames {
val currentMirror: NameType = "currentMirror"
val delayedInit: NameType = "delayedInit"
val delayedInitArg: NameType = "delayedInit$body"
+ val dollarScope: NameType = "$scope"
val drop: NameType = "drop"
val elem: NameType = "elem"
val emptyValDef: NameType = "emptyValDef"
@@ -684,6 +685,7 @@ trait StdNames {
val thisPrefix : NameType = "thisPrefix"
val toArray: NameType = "toArray"
val toObjectArray : NameType = "toObjectArray"
+ val TopScope: NameType = "TopScope"
val toString_ : NameType = "toString"
val toTypeConstructor: NameType = "toTypeConstructor"
val tpe : NameType = "tpe"
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 2da9fa1cca..c3596fe62e 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -752,7 +752,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def isMonomorphicType =
isType && {
val info = originalInfo
- info.isComplete && !info.isHigherKinded
+ ( (info eq null)
+ || (info.isComplete && !info.isHigherKinded)
+ )
}
def isStrictFP = hasAnnotation(ScalaStrictFPAttr) || (enclClass hasAnnotation ScalaStrictFPAttr)
diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala
index 3a8d3fd460..5c92512193 100644
--- a/src/reflect/scala/reflect/internal/TreeInfo.scala
+++ b/src/reflect/scala/reflect/internal/TreeInfo.scala
@@ -98,7 +98,7 @@ abstract class TreeInfo {
*/
def isStableIdentifier(tree: Tree, allowVolatile: Boolean): Boolean =
tree match {
- case Ident(_) => symOk(tree.symbol) && tree.symbol.isStable && !tree.symbol.hasVolatileType // TODO SPEC: not required by spec
+ case i @ Ident(_) => isStableIdent(i)
case Select(qual, _) => isStableMemberOf(tree.symbol, qual, allowVolatile) && isPath(qual, allowVolatile)
case Apply(Select(free @ Ident(_), nme.apply), _) if free.symbol.name endsWith nme.REIFY_FREE_VALUE_SUFFIX =>
// see a detailed explanation of this trick in `GenSymbols.reifyFreeTerm`
@@ -119,6 +119,13 @@ abstract class TreeInfo {
typeOk(tree.tpe) && (allowVolatile || !hasVolatileType(tree)) && !definitions.isByNameParamType(tree.tpe)
)
+ private def isStableIdent(tree: Ident): Boolean = (
+ symOk(tree.symbol)
+ && tree.symbol.isStable
+ && !definitions.isByNameParamType(tree.tpe)
+ && !tree.symbol.hasVolatileType // TODO SPEC: not required by spec
+ )
+
/** Is `tree`'s type volatile? (Ignored if its symbol has the @uncheckedStable annotation.)
*/
def hasVolatileType(tree: Tree): Boolean =
@@ -201,7 +208,7 @@ abstract class TreeInfo {
}
def isWarnableSymbol = {
val sym = tree.symbol
- (sym == null) || !(sym.isModule || sym.isLazy) || {
+ (sym == null) || !(sym.isModule || sym.isLazy || definitions.isByNameParamType(sym.tpe_*)) || {
debuglog("'Pure' but side-effecting expression in statement position: " + tree)
false
}
@@ -553,6 +560,12 @@ abstract class TreeInfo {
})
)
+ /** Is this CaseDef synthetically generated, e.g. by `MatchTranslation.translateTry`? */
+ def isSyntheticCase(cdef: CaseDef) = cdef.pat.exists {
+ case dt: DefTree => dt.symbol.isSynthetic
+ case _ => false
+ }
+
/** Is this pattern node a catch-all or type-test pattern? */
def isCatchCase(cdef: CaseDef) = cdef match {
case CaseDef(Typed(Ident(nme.WILDCARD), tpt), EmptyTree, _) =>
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index 8781423a6d..ceb3b383d7 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -327,7 +327,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
case class ImportSelector(name: Name, namePos: Int, rename: Name, renamePos: Int) extends ImportSelectorApi
object ImportSelector extends ImportSelectorExtractor {
val wild = ImportSelector(nme.WILDCARD, -1, null, -1)
- val wildList = List(wild)
+ val wildList = List(wild) // OPT This list is shared for performance.
}
case class Import(expr: Tree, selectors: List[ImportSelector])
diff --git a/test/files/neg/t7292-deprecation.check b/test/files/neg/t7292-deprecation.check
index c7e6111962..17f010dfdf 100644
--- a/test/files/neg/t7292-deprecation.check
+++ b/test/files/neg/t7292-deprecation.check
@@ -1,11 +1,11 @@
-t7292-deprecation.scala:2: warning: Octal escape literals are deprecated, use /u0000 instead.
- val chr1 = '/0'
+t7292-deprecation.scala:2: warning: Octal escape literals are deprecated, use \u0000 instead.
+ val chr1 = '\0'
^
-t7292-deprecation.scala:3: warning: Octal escape literals are deprecated, use /u0053 instead.
- val str1 = "abc/123456"
+t7292-deprecation.scala:3: warning: Octal escape literals are deprecated, use \u0053 instead.
+ val str1 = "abc\123456"
^
-t7292-deprecation.scala:4: warning: Octal escape literals are deprecated, use /n instead.
- val lf = '/012'
+t7292-deprecation.scala:4: warning: Octal escape literals are deprecated, use \n instead.
+ val lf = '\012'
^
error: No warnings can be incurred under -Xfatal-warnings.
three warnings found
diff --git a/test/files/neg/t7292-removal.check b/test/files/neg/t7292-removal.check
index fffd0a1104..1cd59b0992 100644
--- a/test/files/neg/t7292-removal.check
+++ b/test/files/neg/t7292-removal.check
@@ -1,10 +1,10 @@
-t7292-removal.scala:2: error: Octal escape literals are unsupported, use /u0000 instead.
- val chr1 = '/0'
+t7292-removal.scala:2: error: Octal escape literals are unsupported, use \u0000 instead.
+ val chr1 = '\0'
^
-t7292-removal.scala:3: error: Octal escape literals are unsupported, use /u0053 instead.
- val str1 = "abc/123456"
+t7292-removal.scala:3: error: Octal escape literals are unsupported, use \u0053 instead.
+ val str1 = "abc\123456"
^
-t7292-removal.scala:4: error: Octal escape literals are unsupported, use /n instead.
- val lf = '/012'
+t7292-removal.scala:4: error: Octal escape literals are unsupported, use \n instead.
+ val lf = '\012'
^
three errors found
diff --git a/test/files/pos/t7433.flags b/test/files/pos/t7433.flags
new file mode 100644
index 0000000000..e8fb65d50c
--- /dev/null
+++ b/test/files/pos/t7433.flags
@@ -0,0 +1 @@
+-Xfatal-warnings \ No newline at end of file
diff --git a/test/files/pos/t7433.scala b/test/files/pos/t7433.scala
new file mode 100644
index 0000000000..f2109f4afa
--- /dev/null
+++ b/test/files/pos/t7433.scala
@@ -0,0 +1,10 @@
+object Test {
+ def foo() {
+ try {
+ for (i <- 1 until 5) return
+ } catch {
+ case _: NullPointerException | _: RuntimeException =>
+ // was: "catch block may intercept non-local return from method check"
+ }
+ }
+}
diff --git a/test/files/pos/t7584.scala b/test/files/pos/t7584.scala
new file mode 100644
index 0000000000..52d127ecb9
--- /dev/null
+++ b/test/files/pos/t7584.scala
@@ -0,0 +1,11 @@
+object Test {
+ def fold[A, B](f: (A, => B) => B) = ???
+ def f[A, B](x: A, y: B): B = ???
+ def bip[A, B] = fold[A, B]((x, y) => f(x, y))
+ def bop[A, B] = fold[A, B](f)
+
+ // these work:
+ fold[Int, Int]((x, y) => f(x, y))
+ fold[Int, Int](f)
+}
+
diff --git a/test/files/run/literals.check b/test/files/run/literals.check
index 6be5137994..5f948762b7 100644
--- a/test/files/run/literals.check
+++ b/test/files/run/literals.check
@@ -1,4 +1,4 @@
-warning: there were 13 deprecation warning(s); re-run with -deprecation for details
+warning: there were 18 deprecation warning(s); re-run with -deprecation for details
test '\u0024' == '$' was successful
test '\u005f' == '_' was successful
test 65.asInstanceOf[Char] == 'A' was successful
diff --git a/test/files/run/richs.check b/test/files/run/richs.check
index a970a814b1..02a98b376d 100644
--- a/test/files/run/richs.check
+++ b/test/files/run/richs.check
@@ -1,3 +1,4 @@
+warning: there were 2 deprecation warning(s); re-run with -deprecation for details
RichCharTest1:
true
diff --git a/test/files/run/t7439.check b/test/files/run/t7439.check
new file mode 100644
index 0000000000..9ea09f9c40
--- /dev/null
+++ b/test/files/run/t7439.check
@@ -0,0 +1,2 @@
+Recompiling after deleting t7439-run.obj/A_1.class
+pos: NoPosition Class A_1 not found - continuing with a stub. WARNING
diff --git a/test/files/run/t7439/A_1.java b/test/files/run/t7439/A_1.java
new file mode 100644
index 0000000000..4accd95d57
--- /dev/null
+++ b/test/files/run/t7439/A_1.java
@@ -0,0 +1,3 @@
+public class A_1 {
+
+} \ No newline at end of file
diff --git a/test/files/run/t7439/B_1.java b/test/files/run/t7439/B_1.java
new file mode 100644
index 0000000000..5dd3b93d6f
--- /dev/null
+++ b/test/files/run/t7439/B_1.java
@@ -0,0 +1,3 @@
+public class B_1 {
+ public void b(A_1[] a) {}
+}
diff --git a/test/files/run/t7439/Test_2.scala b/test/files/run/t7439/Test_2.scala
new file mode 100644
index 0000000000..3ebbcfe753
--- /dev/null
+++ b/test/files/run/t7439/Test_2.scala
@@ -0,0 +1,32 @@
+import scala.tools.partest._
+import java.io.File
+
+object Test extends StoreReporterDirectTest {
+ def code = ???
+
+ def compileCode(code: String) = {
+ val classpath = List(sys.props("partest.lib"), testOutput.path) mkString sys.props("path.separator")
+ compileString(newCompiler("-cp", classpath, "-d", testOutput.path))(code)
+ }
+
+ def C = """
+ class C {
+ new B_1
+ }
+ """
+
+ def show(): Unit = {
+ //compileCode(C)
+ assert(filteredInfos.isEmpty, filteredInfos)
+
+ // blow away the entire package
+ val a1Class = new File(testOutput.path, "A_1.class")
+ assert(a1Class.exists)
+ assert(a1Class.delete())
+ println(s"Recompiling after deleting $a1Class")
+
+ // bad symbolic reference error expected (but no stack trace!)
+ compileCode(C)
+ println(storeReporter.infos.mkString("\n")) // Included a NullPointerException before.
+ }
+}
diff --git a/test/files/run/t7569.check b/test/files/run/t7569.check
new file mode 100644
index 0000000000..98513c3ab2
--- /dev/null
+++ b/test/files/run/t7569.check
@@ -0,0 +1,12 @@
+source-newSource1.scala,line-3,offset=49 A.this.one
+source-newSource1.scala,line-3,offset=49 A.this
+source-newSource1.scala,line-4,offset=67 A.super.<init>()
+source-newSource1.scala,line-4,offset=67 A.super.<init>
+source-newSource1.scala,line-4,offset=67 this
+source-newSource1.scala,line-3,offset=49 A.this.one
+source-newSource1.scala,line-3,offset=49 A.this
+RangePosition(newSource1.scala, 55, 57, 65) scala.Int.box(1).toString()
+RangePosition(newSource1.scala, 55, 57, 65) scala.Int.box(1).toString
+RangePosition(newSource1.scala, 55, 55, 56) scala.Int.box(1)
+NoPosition scala.Int.box
+NoPosition scala.Int
diff --git a/test/files/run/t7569.scala b/test/files/run/t7569.scala
new file mode 100644
index 0000000000..b1b1443a18
--- /dev/null
+++ b/test/files/run/t7569.scala
@@ -0,0 +1,19 @@
+import scala.tools.partest._
+object Test extends CompilerTest {
+ import global._
+ override def extraSettings = super.extraSettings + " -Yrangepos"
+ override def sources = List(
+ """|import scala.language.postfixOps
+ |class A {
+ | val one = 1 toString
+ |}""".stripMargin
+ )
+ def check(source: String, unit: CompilationUnit) {
+ for (ClassDef(_, _, _, Template(_, _, stats)) <- unit.body ; stat <- stats ; t <- stat) {
+ t match {
+ case _: Select | _ : Apply | _:This => println("%-15s %s".format(t.pos.toString, t))
+ case _ =>
+ }
+ }
+ }
+}
diff --git a/test/files/run/t7584.check b/test/files/run/t7584.check
new file mode 100644
index 0000000000..9f53e5dde5
--- /dev/null
+++ b/test/files/run/t7584.check
@@ -0,0 +1,6 @@
+no calls
+call A
+a
+call B twice
+b
+b
diff --git a/test/files/run/t7584.flags b/test/files/run/t7584.flags
new file mode 100644
index 0000000000..e8fb65d50c
--- /dev/null
+++ b/test/files/run/t7584.flags
@@ -0,0 +1 @@
+-Xfatal-warnings \ No newline at end of file
diff --git a/test/files/run/t7584.scala b/test/files/run/t7584.scala
new file mode 100644
index 0000000000..6d7f4f7ebb
--- /dev/null
+++ b/test/files/run/t7584.scala
@@ -0,0 +1,14 @@
+// Test case added to show the behaviour of functions with
+// by-name parameters. The evaluation behaviour was already correct.
+//
+// We did flush out a spurious "pure expression does nothing in statement position"
+// warning, hence -Xfatal-warnings in the flags file.
+object Test extends App {
+ def foo(f: (=> Int, => Int) => Unit) = f({println("a"); 0}, {println("b"); 1})
+ println("no calls")
+ foo((a, b) => ())
+ println("call A")
+ foo((a, b) => a)
+ println("call B twice")
+ foo((a, b) => {b; b})
+}