diff options
Diffstat (limited to 'src')
7 files changed, 107 insertions, 30 deletions
diff --git a/src/compiler/scala/reflect/internal/Chars.scala b/src/compiler/scala/reflect/internal/Chars.scala index 7bd37618ed..f2c90a6721 100644 --- a/src/compiler/scala/reflect/internal/Chars.scala +++ b/src/compiler/scala/reflect/internal/Chars.scala @@ -21,27 +21,31 @@ trait Chars { final val SU = '\u001A' /** Convert a character digit to an Int according to given base, - * -1 if no success */ + * -1 if no success + */ def digit2int(ch: Char, base: Int): Int = { - if ('0' <= ch && ch <= '9' && ch < '0' + base) - ch - '0' - else if ('A' <= ch && ch < 'A' + base - 10) - ch - 'A' + 10 - else if ('a' <= ch && ch < 'a' + base - 10) - ch - 'a' + 10 - else - -1 + val num = ( + if (ch <= '9') ch - '0' + else if ('a' <= ch && ch <= 'z') ch - 'a' + 10 + else if ('A' <= ch && ch <= 'Z') ch - 'A' + 10 + else -1 + ) + if (0 <= num && num < base) num else -1 } + /** Buffer for creating '\ u XXXX' strings. */ + private[this] val char2uescapeArray = Array[Char]('\\', 'u', 0, 0, 0, 0) /** Convert a character to a backslash-u escape */ def char2uescape(c: Char): String = { - var rest = c.toInt - val buf = new StringBuilder - for (i <- 1 to 4) { - buf ++= (rest % 16).toHexString - rest = rest / 16 - } - "\\u" + buf.toString.reverse + @inline def hexChar(ch: Int): Char = + ( if (ch < 10) '0' else 'A' - 10 ) + ch toChar + + char2uescapeArray(2) = hexChar((c >> 12) ) + char2uescapeArray(3) = hexChar((c >> 8) % 16) + char2uescapeArray(4) = hexChar((c >> 4) % 16) + char2uescapeArray(5) = hexChar((c ) % 16) + + new String(char2uescapeArray) } /** Is character a line break? */ diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index 75fd733e7e..bc0c81a54b 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -1097,6 +1097,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => def typeParams: List[Symbol] = if (isMonomorphicType) Nil else { + // analogously to the "info" getter, here we allow for two completions: + // one: sourceCompleter to LazyType, two: LazyType to completed type + if (validTo == NoPeriod) + atPhase(phaseOf(infos.validFrom))(rawInfo load this) if (validTo == NoPeriod) atPhase(phaseOf(infos.validFrom))(rawInfo load this) diff --git a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl index c59d46683e..9f1fbc4524 100644 --- a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl +++ b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl @@ -86,3 +86,4 @@ goto :eof :end
@@endlocal
+exit /b %errorlevel%
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 91ac00d946..f319abd060 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -374,7 +374,9 @@ abstract class UnCurry extends InfoTransform assert(toArraySym != NoSymbol) def getManifest(tp: Type): Tree = { val manifestOpt = localTyper.findManifest(tp, false) - if (!manifestOpt.tree.isEmpty) manifestOpt.tree + // Don't want bottom types getting any further than this (SI-4024) + if (tp.typeSymbol.isBottomClass) getManifest(AnyClass.tpe) + else if (!manifestOpt.tree.isEmpty) manifestOpt.tree else if (tp.bounds.hi ne tp) getManifest(tp.bounds.hi) else localTyper.getManifestTree(tree.pos, tp, false) } diff --git a/src/library/scala/collection/immutable/Map.scala b/src/library/scala/collection/immutable/Map.scala index 45cf088dd9..bbefd983fd 100644 --- a/src/library/scala/collection/immutable/Map.scala +++ b/src/library/scala/collection/immutable/Map.scala @@ -47,6 +47,7 @@ trait Map[A, +B] extends Iterable[(A, B)] def withDefault[B1 >: B](d: A => B1): immutable.Map[A, B1] = new Map.WithDefault[A, B1](this, d) /** The same map with a given default value. + * Note: `get`, `contains`, `iterator`, `keys`, etc are not affected by `withDefaultValue`. * * Invoking transformer methods (e.g. `map`) will not preserve the default value. * diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala index e891f8bec8..16d7e68dee 100644 --- a/src/library/scala/collection/immutable/Range.scala +++ b/src/library/scala/collection/immutable/Range.scala @@ -71,18 +71,6 @@ extends collection.AbstractSeq[Int] def isInclusive = false - @inline final override def foreach[@specialized(Unit) U](f: Int => U) { - if (length > 0) { - val last = this.last - var i = start - while (i != last) { - f(i) - i += step - } - f(i) - } - } - override def length: Int = numRangeElements override lazy val last: Int = if (length == 0) Nil.last @@ -95,6 +83,83 @@ extends collection.AbstractSeq[Int] if (idx < 0 || idx >= length) throw new IndexOutOfBoundsException(idx.toString) locationAfterN(idx) } + + /** @note Making foreach run as fast as a while loop is a challenge. + * The key elements which I can observe making a difference are: + * + * - the inner loop should be as small as possible + * - the inner loop should be monomorphic + * - the inner loop should perform no boxing and no avoidable tests + * + * This is achieved by: + * + * - keeping initialization logic out of the inner loop + * - dispatching to custom variations based on initial conditions + * - tricking the compiler into always calling Function1#apply$mcVI$sp + * + * The last one is important and less than obvious. Even when foreach + * was specialized on Unit, only Int => Unit arguments benefited from it. + * Other function types would be accepted, but in the absence of full + * specialization the integer argument was boxed on every call. For example: + * + class A { + final def f(x: Int): Int = x + 1 + // Calls Range.foreach, which calls Function1.apply + def g1 = 1 until 100 foreach { x => f(x) } + // Calls Range.foreach$mVc$sp, which calls Function1.apply$mcVI$sp + def g2 = 1 until 100 foreach { x => f(x) ; () } + } + * + * However! Since the result of the closure is always discarded, we + * simply cast it to Int => Unit, thereby executing the fast version. + * The seemingly looming ClassCastException can never arrive. + */ + @inline final override def foreach[U](f: Int => U) { + if (step < 0) { + if (isInclusive) foreachDownIn(f.asInstanceOf[Int => Unit]) + else foreachDownEx(f.asInstanceOf[Int => Unit]) + } + else { + if (isInclusive) foreachUpIn(f.asInstanceOf[Int => Unit]) + else foreachUpEx(f.asInstanceOf[Int => Unit]) + } + } + + /** !!! These methods must be public or they will not be inlined. + * But they are certainly not intended to be part of the API. + * This collision between inlining requirements and access semantics + * is highly unfortunate and must be resolved. + * + * Proposed band-aid: an @internal annotation. + */ + @inline final def foreachDownIn(f: Int => Unit) { + var i = start + while (i >= end) { + f(i) + i += step + } + } + @inline final def foreachUpIn(f: Int => Unit) { + var i = start + while (i <= end) { + f(i) + i += step + } + } + @inline final def foreachDownEx(f: Int => Unit) { + var i = start + while (i > end) { + f(i) + i += step + } + } + @inline final def foreachUpEx(f: Int => Unit) { + var i = start + while (i < end) { + f(i) + i += step + } + } /** Creates a new range containing the first `n` elements of this range. * diff --git a/src/library/scala/collection/parallel/immutable/ParRange.scala b/src/library/scala/collection/parallel/immutable/ParRange.scala index 2a10458457..350e64739f 100644 --- a/src/library/scala/collection/parallel/immutable/ParRange.scala +++ b/src/library/scala/collection/parallel/immutable/ParRange.scala @@ -88,7 +88,7 @@ self => /* accessors */ override def foreach[U](f: Int => U): Unit = { - rangeleft.foreach(f) + rangeleft.foreach(f.asInstanceOf[Int => Unit]) ind = len } |