summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPavel Pavlov <pavel.e.pavlov@gmail.com>2012-01-16 07:57:09 +0700
committerAdriaan Moors <adriaan.moors@epfl.ch>2012-03-30 09:19:03 +0200
commit66b47e1a8c11196d648ed5a98f934a1c65203a65 (patch)
tree69d808bc33be23f35ffc06755bce492a5463f779 /src
parent71392585dc56950287135ac2582b516d7971bfbc (diff)
downloadscala-66b47e1a8c11196d648ed5a98f934a1c65203a65.tar.gz
scala-66b47e1a8c11196d648ed5a98f934a1c65203a65.tar.bz2
scala-66b47e1a8c11196d648ed5a98f934a1c65203a65.zip
a fast, functional PartialFunction implementation
runtime.AbstractPartialFunction provides a default implementation for the new-style partial function. In principle this class is only subclassed by compiler-generated partial functions arising from matches. Either - the apply method (old-style partialfun) or - the applyOrElse method (current scheme) must be overridden, and the isDefinedAt method implemented. The applyOrElse method implementation is provided to ease the transition from the old scheme, since starr still generates old-style PartialFunctions, but locker's library has the new AbstractPartialFunction. Thus, this implementation is intended as a drop-in replacement for the old partial function, and does not require changes to the compiler. (compiler patches, both for old and new-style pattern matching, follow) - runtime.AbstractPartialFunction is based on PartialFunction.WithDefault Original version of FunctionWithDefault by Odersky (http://article.gmane.org/gmane.comp.lang.scala.internals/4032) - better performance for OrElse#applyOrElse, OrElse#lift, PF.cond - new combinator methods: PF#run, PF#runWith, PF.apply authored by @pavelpavlov, refactored by @adriaanm, review by @paulp
Diffstat (limited to 'src')
-rw-r--r--src/actors/scala/actors/Actor.scala8
-rw-r--r--src/actors/scala/actors/Future.scala4
-rw-r--r--src/actors/scala/actors/Reactor.scala4
-rw-r--r--src/compiler/scala/tools/cmd/FromString.scala12
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala4
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala1
-rw-r--r--src/library/scala/Function.scala7
-rw-r--r--src/library/scala/PartialFunction.scala134
-rw-r--r--src/library/scala/runtime/AbstractPartialFunction.scala84
-rw-r--r--src/library/scala/util/control/Exception.scala5
11 files changed, 174 insertions, 93 deletions
diff --git a/src/actors/scala/actors/Actor.scala b/src/actors/scala/actors/Actor.scala
index aab533ae8d..bc9bbc6ef0 100644
--- a/src/actors/scala/actors/Actor.scala
+++ b/src/actors/scala/actors/Actor.scala
@@ -1,3 +1,5 @@
+
+
/* __ *\
** ________ ___ / / ___ Scala API **
** / __/ __// _ | / / / _ | (c) 2005-2011, LAMP/EPFL **
@@ -246,8 +248,8 @@ object Actor extends Combinators {
rawSelf.react(new RecursiveProxyHandler(rawSelf, f))
private class RecursiveProxyHandler(a: InternalReplyReactor, f: PartialFunction[Any, Unit])
- extends scala.runtime.AbstractPartialFunction[Any, Unit] {
- def _isDefinedAt(m: Any): Boolean =
+ extends PartialFunction[Any, Unit] {
+ def isDefinedAt(m: Any): Boolean =
true // events are immediately removed from the mailbox
def apply(m: Any) {
if (f.isDefinedAt(m)) f(m)
@@ -404,5 +406,5 @@ trait Actor extends InternalActor with ReplyReactor {
this
}
-}
+ }
diff --git a/src/actors/scala/actors/Future.scala b/src/actors/scala/actors/Future.scala
index eec43013d3..735c13190b 100644
--- a/src/actors/scala/actors/Future.scala
+++ b/src/actors/scala/actors/Future.scala
@@ -200,8 +200,8 @@ object Futures {
Actor.timer.schedule(timerTask, timeout)
def awaitWith(partFuns: Seq[PartialFunction[Any, Pair[Int, Any]]]) {
- val reaction: PartialFunction[Any, Unit] = new scala.runtime.AbstractPartialFunction[Any, Unit] {
- def _isDefinedAt(msg: Any) = msg match {
+ val reaction: PartialFunction[Any, Unit] = new PartialFunction[Any, Unit] {
+ def isDefinedAt(msg: Any) = msg match {
case TIMEOUT => true
case _ => partFuns exists (_ isDefinedAt msg)
}
diff --git a/src/actors/scala/actors/Reactor.scala b/src/actors/scala/actors/Reactor.scala
index 8fc7578344..206a97d97c 100644
--- a/src/actors/scala/actors/Reactor.scala
+++ b/src/actors/scala/actors/Reactor.scala
@@ -38,8 +38,8 @@ private[actors] object Reactor {
}
}
- val waitingForNone: PartialFunction[Any, Unit] = new scala.runtime.AbstractPartialFunction[Any, Unit] {
- def _isDefinedAt(x: Any) = false
+ val waitingForNone: PartialFunction[Any, Unit] = new PartialFunction[Any, Unit] {
+ def isDefinedAt(x: Any) = false
def apply(x: Any) {}
}
}
diff --git a/src/compiler/scala/tools/cmd/FromString.scala b/src/compiler/scala/tools/cmd/FromString.scala
index e4504702d4..3792c26c34 100644
--- a/src/compiler/scala/tools/cmd/FromString.scala
+++ b/src/compiler/scala/tools/cmd/FromString.scala
@@ -14,9 +14,9 @@ import scala.reflect.OptManifest
* example instances are in the companion object, but in general
* either IntFromString will suffice or you'll want custom transformers.
*/
-abstract class FromString[+T](implicit m: OptManifest[T]) extends scala.runtime.AbstractPartialFunction[String, T] {
+abstract class FromString[+T](implicit m: OptManifest[T]) extends PartialFunction[String, T] {
def apply(s: String): T
- def _isDefinedAt(s: String): Boolean = true
+ def isDefinedAt(s: String): Boolean = true
def zero: T = apply("")
def targetString: String = m.toString
@@ -30,20 +30,20 @@ object FromString {
/** Path related stringifiers.
*/
val ExistingFile: FromString[File] = new FromString[File] {
- override def _isDefinedAt(s: String) = toFile(s).isFile
+ override def isDefinedAt(s: String) = toFile(s).isFile
def apply(s: String): File =
if (isDefinedAt(s)) toFile(s)
else cmd.runAndExit(println("'%s' is not an existing file." format s))
}
val ExistingDir: FromString[Directory] = new FromString[Directory] {
- override def _isDefinedAt(s: String) = toDir(s).isDirectory
+ override def isDefinedAt(s: String) = toDir(s).isDirectory
def apply(s: String): Directory =
if (isDefinedAt(s)) toDir(s)
else cmd.runAndExit(println("'%s' is not an existing directory." format s))
}
def ExistingDirRelativeTo(root: Directory) = new FromString[Directory] {
private def resolve(s: String) = toDir(s) toAbsoluteWithRoot root toDirectory
- override def _isDefinedAt(s: String) = resolve(s).isDirectory
+ override def isDefinedAt(s: String) = resolve(s).isDirectory
def apply(s: String): Directory =
if (isDefinedAt(s)) resolve(s)
else cmd.runAndExit(println("'%s' is not an existing directory." format resolve(s)))
@@ -65,7 +65,7 @@ object FromString {
/** Implicit as the most likely to be useful as-is.
*/
implicit val IntFromString: FromString[Int] = new FromString[Int] {
- override def _isDefinedAt(s: String) = safeToInt(s).isDefined
+ override def isDefinedAt(s: String) = safeToInt(s).isDefined
def apply(s: String) = safeToInt(s).get
def safeToInt(s: String): Option[Int] = try Some(java.lang.Integer.parseInt(s)) catch { case _: NumberFormatException => None }
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala b/src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala
index 33ef4a432d..2f47685757 100644
--- a/src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala
@@ -6,8 +6,8 @@
package scala.tools.nsc
package interpreter
-class AbstractOrMissingHandler[T](onError: String => Unit, value: T) extends scala.runtime.AbstractPartialFunction[Throwable, T] {
- def _isDefinedAt(t: Throwable) = t match {
+class AbstractOrMissingHandler[T](onError: String => Unit, value: T) extends PartialFunction[Throwable, T] {
+ def isDefinedAt(t: Throwable) = t match {
case _: AbstractMethodError => true
case _: NoSuchMethodError => true
case _: MissingRequirementError => true
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index be5a9907b8..43aad9f591 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -425,7 +425,7 @@ trait ParallelMatching extends ast.TreeDSL
// Should the given pattern join the expanded pivot in the success matrix? If so,
// this partial function will be defined for the pattern, and the result of the apply
// is the expanded sequence of new patterns.
- lazy val successMatrixFn = new scala.runtime.AbstractPartialFunction[Pattern, List[Pattern]] {
+ lazy val successMatrixFn = new PartialFunction[Pattern, List[Pattern]] {
private def seqIsDefinedAt(x: SequenceLikePattern) = (hasStar, x.hasStar) match {
case (true, true) => true
case (true, false) => pivotLen <= x.nonStarLength
@@ -433,7 +433,7 @@ trait ParallelMatching extends ast.TreeDSL
case (false, false) => pivotLen == x.nonStarLength
}
- def _isDefinedAt(pat: Pattern) = pat match {
+ def isDefinedAt(pat: Pattern) = pat match {
case x: SequenceLikePattern => seqIsDefinedAt(x)
case WildcardPattern() => true
case _ => false
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index e54e0289bb..0d39c040f7 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -210,6 +210,7 @@ abstract class UnCurry extends InfoTransform
* body = expr match { case P_i if G_i => E_i }_i=1..n
* to:
*
+ //TODO: correct code template below
* class $anon() extends AbstractPartialFunction[T, R] with Serializable {
* def apply(x: T): R = (expr: @unchecked) match {
* case P_1 if G_1 => E_1
diff --git a/src/library/scala/Function.scala b/src/library/scala/Function.scala
index 4a10b65735..9fa56a332f 100644
--- a/src/library/scala/Function.scala
+++ b/src/library/scala/Function.scala
@@ -29,6 +29,7 @@ object Function {
/** Turns a function `A => Option[B]` into a `PartialFunction[A, B]`.
*
+ * TODO: check if the paragraph below is still correct
* '''Important note''': this transformation implies the original function
* will be called 2 or more times on each logical invocation, because the
* only way to supply an implementation of `isDefinedAt` is to call the
@@ -39,11 +40,7 @@ object Function {
* f returns `Some(_)` and undefined where `f` returns `None`.
* @see [[scala.PartialFunction#lift]]
*/
- def unlift[T, R](f: T => Option[R]): PartialFunction[T, R] = new runtime.AbstractPartialFunction[T, R] {
- def apply(x: T): R = f(x).get
- def _isDefinedAt(x: T): Boolean = f(x).isDefined
- override def lift: T => Option[R] = f
- }
+ def unlift[T, R](f: T => Option[R]): PartialFunction[T, R] = PartialFunction.unlifted(f)
/** Uncurrying for functions of arity 2. This transforms a unary function
* returning another unary function into a function of arity 2.
diff --git a/src/library/scala/PartialFunction.scala b/src/library/scala/PartialFunction.scala
index 3c5d6d0d23..7154b8da34 100644
--- a/src/library/scala/PartialFunction.scala
+++ b/src/library/scala/PartialFunction.scala
@@ -8,6 +8,7 @@
package scala
+
/** A partial function of type `PartialFunction[A, B]` is a unary function
* where the domain does not necessarily include all values of type `A`.
* The function `isDefinedAt` allows to test dynamically if a value is in
@@ -43,10 +44,11 @@ package scala
* }}}
*
*
- * @author Martin Odersky
+ * @author Martin Odersky, Pavel Pavlov, Adriaan Moors
* @version 1.0, 16/07/2003
*/
-trait PartialFunction[-A, +B] extends (A => B) {
+trait PartialFunction[-A, +B] extends (A => B) { self =>
+ import PartialFunction._
/** Checks if a value is contained in the function's domain.
*
@@ -55,10 +57,6 @@ trait PartialFunction[-A, +B] extends (A => B) {
*/
def isDefinedAt(x: A): Boolean
- //protected def missingCase[A1 <: A, B1 >: B]: PartialFunction[A1, B1] = PartialFunction.empty
-
- protected def missingCase(x: A): B = throw new MatchError(x)
-
/** Composes this partial function with a fallback partial function which
* gets applied where this partial function is not defined.
*
@@ -70,16 +68,8 @@ trait PartialFunction[-A, +B] extends (A => B) {
* takes `x` to `this(x)` where `this` is defined, and to `that(x)` where it is not.
*/
def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] =
- new runtime.AbstractPartialFunction[A1, B1] {
- def _isDefinedAt(x: A1): Boolean =
- PartialFunction.this.isDefinedAt(x) || that.isDefinedAt(x)
- def apply(x: A1): B1 =
- if (PartialFunction.this.isDefinedAt(x)) PartialFunction.this.apply(x)
- else that.apply(x)
- }
-
- def orElseFast[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] =
- orElse(that)
+ new OrElse[A1, B1] (this, that)
+ //TODO: why not overload it with orElse(that: F1): F1?
/** Composes this partial function with a transformation function that
* gets applied to results of this partial function.
@@ -88,9 +78,9 @@ trait PartialFunction[-A, +B] extends (A => B) {
* @return a partial function with the same domain as this partial function, which maps
* arguments `x` to `k(this(x))`.
*/
- override def andThen[C](k: B => C) : PartialFunction[A, C] = new runtime.AbstractPartialFunction[A, C] {
- def _isDefinedAt(x: A): Boolean = PartialFunction.this.isDefinedAt(x)
- def apply(x: A): C = k(PartialFunction.this.apply(x))
+ override def andThen[C](k: B => C) : PartialFunction[A, C] = new PartialFunction[A, C] {
+ def isDefinedAt(x: A): Boolean = self isDefinedAt x
+ def apply(x: A): C = k(self(x))
}
/** Turns this partial function into an plain function returning an `Option` result.
@@ -98,9 +88,30 @@ trait PartialFunction[-A, +B] extends (A => B) {
* @return a function that takes an argument `x` to `Some(this(x))` if `this`
* is defined for `x`, and to `None` otherwise.
*/
- def lift: A => Option[B] = new (A => Option[B]) {
- def apply(x: A): Option[B] = if (isDefinedAt(x)) Some(PartialFunction.this.apply(x)) else None
- }
+ def lift: A => Option[B] = new Lifted(this)
+
+ /**
+ * TODO: comment
+ * @since 2.10
+ */
+ def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 =
+ if (isDefinedAt(x)) apply(x) else default(x)
+
+ /**
+ * TODO: comment
+ * @since 2.10
+ */
+ def run[U](x: A)(action: B => U): Boolean =
+ applyOrElse(x, fallbackToken) match {
+ case FallbackToken => false
+ case z => action(z); true
+ }
+
+ /**
+ * TODO: comment
+ * @since 2.10
+ */
+ def runWith[U](action: B => U): A => Boolean = { x => run(x)(action) }
}
/** A few handy operations which leverage the extra bit of information
@@ -119,14 +130,73 @@ trait PartialFunction[-A, +B] extends (A => B) {
* @since 2.8
*/
object PartialFunction {
- private[this] final val empty_pf: PartialFunction[Any, Nothing] = new runtime.AbstractPartialFunction[Any, Nothing] {
- def _isDefinedAt(x: Any) = false
- override def isDefinedAt(x: Any) = false
- def apply(x: Any): Nothing = throw new MatchError(x)
- override def orElse[A1, B1](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] = that
- override def orElseFast[A1, B1](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] = that
- override def lift = (x: Any) => None
+ /** Composite function produced by `PartialFunction#orElse` method
+ */
+ private final class OrElse[-A, +B] (f1: PartialFunction[A, B], f2: PartialFunction[A, B]) extends PartialFunction[A, B] {
+ def isDefinedAt(x: A) = f1.isDefinedAt(x) || f2.isDefinedAt(x)
+
+ def apply(x: A): B = f1.applyOrElse(x, f2)
+
+ override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 =
+ f1.applyOrElse(x, fallbackToken) match {
+ case FallbackToken => f2.applyOrElse(x, default)
+ case z => z
+ }
+
+ override def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]) =
+ new OrElse[A1, B1] (f1, f2 orElse that)
+
+ override def andThen[C](k: B => C) =
+ new OrElse[A, C] (f1 andThen k, f2 andThen k)
}
+
+ private[scala] lazy val FallbackToken: PartialFunction[Any, PartialFunction[Any, Nothing]] = { case _ => FallbackToken.asInstanceOf[PartialFunction[Any, Nothing]] }
+ private[scala] final def fallbackToken[B] = FallbackToken.asInstanceOf[PartialFunction[Any, B]]
+ //TODO: check generated code for PF literal here
+
+ private[scala] final class Lifted[-A, +B] (val pf: PartialFunction[A, B])
+ extends runtime.AbstractFunction1[A, Option[B]] {
+
+ def apply(x: A): Option[B] = pf.applyOrElse(x, fallbackToken) match {
+ case FallbackToken => None
+ case z => Some(z)
+ }
+ }
+
+ private final class Unlifted[A, B] (f: A => Option[B]) extends runtime.AbstractPartialFunction[A, B] {
+ def isDefinedAt(x: A): Boolean = f(x).isDefined
+ override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 =
+ f(x) getOrElse default(x) //TODO: check generated code and inline getOrElse if needed
+ override def lift = f
+ }
+
+ private[scala] def unlifted[A, B](f: A => Option[B]): PartialFunction[A, B] = f match {
+ case lf: Lifted[A, B] => lf.pf
+ case ff => new Unlifted(ff)
+ }
+
+ /** Converts ordinary function to partial one
+ * @since 2.10
+ */
+ //TODO: check generated code for PF literal here
+ def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }
+
+ private[this] final val constFalse: Any => Boolean = { _ => false}
+
+ private[this] final val empty_pf: PartialFunction[Any, Nothing] = new PartialFunction[Any, Nothing] {
+ def isDefinedAt(x: Any) = false
+ def apply(x: Any) = throw new MatchError(x)
+ override def orElse[A1, B1](that: PartialFunction[A1, B1]) = that
+ override def andThen[C](k: Nothing => C) = this
+ override val lift = (x: Any) => None
+ override def run[U](x: Any)(action: Nothing => U) = false
+ override def runWith[U](action: Nothing => U) = constFalse
+ }
+
+ /**
+ * TODO: comment
+ * @since 2.10
+ */
def empty[A, B] : PartialFunction[A, B] = empty_pf
/** Creates a Boolean test based on a value and a partial function.
@@ -137,8 +207,7 @@ object PartialFunction {
* @param pf the partial function
* @return true, iff `x` is in the domain of `pf` and `pf(x) == true`.
*/
- def cond[T](x: T)(pf: PartialFunction[T, Boolean]): Boolean =
- (pf isDefinedAt x) && pf(x)
+ def cond[T](x: T)(pf: PartialFunction[T, Boolean]): Boolean = pf.applyOrElse(x, constFalse)
/** Transforms a PartialFunction[T, U] `pf` into Function1[T, Option[U]] `f`
* whose result is `Some(x)` if the argument is in `pf`'s domain and `None`
@@ -150,6 +219,5 @@ object PartialFunction {
* @param pf the PartialFunction[T, U]
* @return `Some(pf(x))` if `pf isDefinedAt x`, `None` otherwise.
*/
- def condOpt[T,U](x: T)(pf: PartialFunction[T, U]): Option[U] =
- if (pf isDefinedAt x) Some(pf(x)) else None
+ def condOpt[T,U](x: T)(pf: PartialFunction[T, U]): Option[U] = pf.lift(x)
}
diff --git a/src/library/scala/runtime/AbstractPartialFunction.scala b/src/library/scala/runtime/AbstractPartialFunction.scala
index cbe778f09b..2e435d8a7e 100644
--- a/src/library/scala/runtime/AbstractPartialFunction.scala
+++ b/src/library/scala/runtime/AbstractPartialFunction.scala
@@ -8,45 +8,61 @@
package scala.runtime
-import scala.annotation.unchecked.uncheckedVariance
-
-/** This class provides a default implementation of partial functions
- * that is used for all partial function literals.
- * It contains an optimized `orElse` method which supports
- * chained `orElse` in linear time, and with no slow-down
- * if the `orElse` part is not needed.
- * The implementation of `orElse` works by cloning the abstract function object
- * and modifying a private `fallBack` variable that encodes the `getorElse` part.
+/** `AbstractPartialFunction` reformulates all operations of its supertrait `PartialFunction` in terms of `isDefinedAt` and `applyOrElse`.
+ *
+ * This allows more efficient implementations in many cases:
+ * - optimized `orElse` method supports chained `orElse` in linear time,
+ * and with no slow-down if the `orElse` part is not needed.
+ * - optimized `lift` method helps to avoid double evaluation of pattern matchers & guards
+ * of partial function literals.
+ *
+ * This trait is used as a basis for implementation of all partial function literals
+ * with non-exhaustive matchers.
+ *
+ * Use of `AbstractPartialFunction` instead of `PartialFunction` as a base trait for
+ * user-defined partial functions may result in better performance
+ * and more predictable behavior w.r.t. side effects.
+ *
+ * @author Pavel Pavlov
+ * @since 2.10
*/
-abstract class AbstractPartialFunction[-T1, +R]
- extends AbstractFunction1[T1, R]
- with PartialFunction[T1, R]
- with Cloneable {
-
- private var fallBackField: PartialFunction[T1 @uncheckedVariance, R @uncheckedVariance] = _
+abstract class AbstractPartialFunction[@specialized(scala.Int, scala.Long, scala.Float, scala.Double, scala.AnyRef) -T1, @specialized(scala.Unit, scala.Boolean, scala.Int, scala.Float, scala.Long, scala.Double, scala.AnyRef) +R] extends Function1[T1, R] with PartialFunction[T1, R] { self =>
+ // this method must be overridden for better performance,
+ // for backwards compatibility, fall back to the one inherited from PartialFunction
+ // this assumes the old-school partial functions override the apply method, though
+ // override def applyOrElse[A1 <: T1, B1 >: R](x: A1, default: A1 => B1): B1 = ???
- def fallBack: PartialFunction[T1, R] = synchronized {
- if (fallBackField eq null) fallBackField = PartialFunction.empty
- fallBackField
- }
+ // probably okay to make final since classes compiled before have overridden against the old version of AbstractPartialFunction
+ // let's not make it final so as not to confuse anyone
+ /*final*/ def apply(x: T1): R = applyOrElse(x, PartialFunction.empty)
- override protected def missingCase(x: T1): R = fallBack(x)
-
- // Question: Need to ensure that fallBack is overwritten before any access
- // Is the `synchronized` here the right thing to achieve this?
- // Is there a cheaper way?
- override def orElse[A1 <: T1, B1 >: R](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] = {
- val result = this.clone.asInstanceOf[AbstractPartialFunction[A1, B1]]
- result.synchronized {
- result.fallBackField = if (this.fallBackField eq null) that else this.fallBackField orElse that
- result
+ override final def andThen[C](k: R => C) : PartialFunction[T1, C] =
+ new AbstractPartialFunction[T1, C] {
+ def isDefinedAt(x: T1): Boolean = self.isDefinedAt(x)
+ override def applyOrElse[A1 <: T1, C1 >: C](x: A1, default: A1 => C1): C1 =
+ self.applyOrElse(x, PartialFunction.fallbackToken) match {
+ case PartialFunction.FallbackToken => default(x)
+ case z => k(z)
+ }
}
- }
-
- def isDefinedAt(x: T1): scala.Boolean = _isDefinedAt(x) || fallBack.isDefinedAt(x)
- def _isDefinedAt(x: T1): scala.Boolean
+ // TODO: remove
+ protected def missingCase(x: T1): R = throw new MatchError(x)
}
-
+/** `AbstractTotalFunction` is a partial function whose `isDefinedAt` method always returns `true`.
+ *
+ * This class is used as base class for partial function literals with
+ * certainly exhaustive pattern matchers.
+ *
+ * @author Pavel Pavlov
+ * @since 2.10
+ */
+abstract class AbstractTotalFunction[@specialized(scala.Int, scala.Long, scala.Float, scala.Double, scala.AnyRef) -T1, @specialized(scala.Unit, scala.Boolean, scala.Int, scala.Float, scala.Long, scala.Double, scala.AnyRef) +R] extends Function1[T1, R] with PartialFunction[T1, R] {
+ final def isDefinedAt(x: T1): Boolean = true
+ override final def applyOrElse[A1 <: T1, B1 >: R](x: A1, default: A1 => B1): B1 = apply(x)
+ override final def orElse[A1 <: T1, B1 >: R](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] = this
+ //TODO: check generated code for PF literal here
+ override final def andThen[C](k: R => C): PartialFunction[T1, C] = { case x => k(apply(x)) }
+}
diff --git a/src/library/scala/util/control/Exception.scala b/src/library/scala/util/control/Exception.scala
index 5e3f8b6451..20a179a884 100644
--- a/src/library/scala/util/control/Exception.scala
+++ b/src/library/scala/util/control/Exception.scala
@@ -230,8 +230,5 @@ object Exception {
classes exists (_ isAssignableFrom x.getClass)
private def pfFromExceptions(exceptions: Class[_]*): PartialFunction[Throwable, Nothing] =
- new scala.runtime.AbstractPartialFunction[Throwable, Nothing] {
- def apply(x: Throwable) = throw x
- def _isDefinedAt(x: Throwable) = wouldMatch(x, exceptions)
- }
+ { case x if wouldMatch(x, exceptions) => throw x }
}