summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-03-30 20:54:05 -0700
committerPaul Phillips <paulp@improving.org>2012-03-30 20:54:05 -0700
commit03aca2c5bc293f8fd79e99b2aaac79cdc043c1da (patch)
treeea832b582e355f1a6687b286266b59b8108188c6 /src
parentdc8b431f1c38ff805d660c44b19ee5ecc91bddb2 (diff)
parent1890a4175dc6c436b37ddc8c6b74e036b9c6328c (diff)
downloadscala-03aca2c5bc293f8fd79e99b2aaac79cdc043c1da.tar.gz
scala-03aca2c5bc293f8fd79e99b2aaac79cdc043c1da.tar.bz2
scala-03aca2c5bc293f8fd79e99b2aaac79cdc043c1da.zip
Merge remote-tracking branch 'adriaanm/topic/partialfun' into develop
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/reflect/internal/StdNames.scala3
-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.scala207
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Duplicators.scala16
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala71
-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
14 files changed, 339 insertions, 224 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/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala
index 9fb7b5b747..e2c253628c 100644
--- a/src/compiler/scala/reflect/internal/StdNames.scala
+++ b/src/compiler/scala/reflect/internal/StdNames.scala
@@ -283,13 +283,13 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val TYPE_ : NameType = "TYPE"
val TypeTree: NameType = "TypeTree"
val UNIT : NameType = "UNIT"
- val _isDefinedAt: NameType = "_isDefinedAt"
val add_ : NameType = "add"
val annotation: NameType = "annotation"
val anyValClass: NameType = "anyValClass"
val append: NameType = "append"
val apply: NameType = "apply"
val applyDynamic: NameType = "applyDynamic"
+ val applyOrElse: NameType = "applyOrElse"
val args : NameType = "args"
val argv : NameType = "argv"
val arrayValue: NameType = "arrayValue"
@@ -357,7 +357,6 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val main: NameType = "main"
val map: NameType = "map"
val mirror : NameType = "mirror"
- val missingCase: NameType = "missingCase"
val ne: NameType = "ne"
val newArray: NameType = "newArray"
val newScopeWith: NameType = "newScopeWith"
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..0efdd9ab9f 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -210,14 +210,15 @@ 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 {
+ * def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = (expr: @unchecked) match {
* case P_1 if G_1 => E_1
* ...
- * case P_n if G_n => true
- * case _ => this.missingCase(expr)
+ * case P_n if G_n => E_n
+ * case _ => default(expr)
* }
- * def _isDefinedAt(x: T): boolean = (x: @unchecked) match {
+ * def isDefinedAt(x: T): boolean = (x: @unchecked) match {
* case P_1 if G_1 => true
* ...
* case P_n if G_n => true
@@ -231,127 +232,107 @@ abstract class UnCurry extends InfoTransform
*
* def isDefinedAtCurrent(x: T): boolean = true
*/
- def transformFunction(fun: Function): Tree = {
- val fun1 = deEta(fun)
- def owner = fun.symbol.owner
- def targs = fun.tpe.typeArgs
- def isPartial = fun.tpe.typeSymbol == PartialFunctionClass
-
- // if the function was eta-expanded, it's not a match without a selector
- if (fun1 ne fun) fun1
- else {
- assert(!(opt.virtPatmat && isPartial)) // empty-selector matches have already been translated into instantiations of anonymous (partial) functions
- val (formals, restpe) = (targs.init, targs.last)
- val anonClass = owner.newAnonymousFunctionClass(fun.pos, inConstructorFlag)
- def parents =
- if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe)
- else if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe)
- else List(ObjectClass.tpe, fun.tpe, SerializableClass.tpe)
-
- anonClass setInfo ClassInfoType(parents, newScope, anonClass)
- val applyMethod = anonClass.newMethod(nme.apply, fun.pos, FINAL)
- applyMethod setInfoAndEnter MethodType(applyMethod newSyntheticValueParams formals, restpe)
- anonClass addAnnotation serialVersionUIDAnnotation
-
- fun.vparams foreach (_.symbol.owner = applyMethod)
- fun.body.changeOwner(fun.symbol -> applyMethod)
-
- def missingCaseCall(scrutinee: Tree): Tree = Apply(Select(This(anonClass), nme.missingCase), List(scrutinee))
-
- def applyMethodDef() = {
- val body = localTyper.typedPos(fun.pos) {
- if (isPartial) gen.mkUncheckedMatch(gen.withDefaultCase(fun.body, missingCaseCall))
- else fun.body
- }
- // Have to repack the type to avoid mismatches when existentials
- // appear in the result - see SI-4869.
- val applyResultType = localTyper.packedType(body, applyMethod)
- DefDef(Modifiers(FINAL), nme.apply, Nil, List(fun.vparams), TypeTree(applyResultType), body) setSymbol applyMethod
- }
- def isDefinedAtMethodDef() = {
- val isDefinedAtName = {
- if (anonClass.info.member(nme._isDefinedAt) != NoSymbol) nme._isDefinedAt
- else nme.isDefinedAt
- }
- val m = anonClass.newMethod(isDefinedAtName, fun.pos, FINAL)
- val params = m newSyntheticValueParams formals
- m setInfoAndEnter MethodType(params, BooleanClass.tpe)
+ def transformFunction(fun: Function): Tree =
+ deEta(fun) match {
+ // nullary or parameterless
+ case fun1 if fun1 ne fun => fun1
+ case _ =>
+ def owner = fun.symbol.owner
+ def targs = fun.tpe.typeArgs
+ def isPartial = fun.tpe.typeSymbol == PartialFunctionClass
+ assert(!(opt.virtPatmat && isPartial)) // empty-selector matches have already been translated into instantiations of anonymous (partial) functions
- val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), params)
- def substTree[T <: Tree](t: T): T = substParam(resetLocalAttrs(t))
+ def parents =
+ if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe)
+ else if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe)
+ else List(ObjectClass.tpe, fun.tpe, SerializableClass.tpe)
- object isDefinedAtTransformer extends gen.MatchMatcher {
- // TODO: optimize duplication, but make sure ValDef's introduced by wrap are treated correctly
- override def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = {
- def transformCase(cdef: CaseDef): CaseDef =
- CaseDef(cdef.pat, cdef.guard, Literal(Constant(true)))
+ val anonClass = owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation serialVersionUIDAnnotation
+ anonClass setInfo ClassInfoType(parents, newScope, anonClass)
- def defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false)))
+ val (formals, restpe) = (targs.init, targs.last)
-// val casesNoSynthCatchAll = dropSyntheticCatchAll(cases)
+ def applyMethodDef = {
+ val methSym = anonClass.newMethod(nme.apply, fun.pos, FINAL)
+ methSym setInfoAndEnter MethodType(methSym newSyntheticValueParams formals, restpe)
- gen.mkUncheckedMatch(
- if (cases exists treeInfo.isDefaultCase) Literal(Constant(true))
- else substTree(wrap(Match(selector, (cases map transformCase) :+ defaultCase)).duplicate)
- )
+ fun.vparams foreach (_.symbol.owner = methSym)
+ fun.body changeOwner (fun.symbol -> methSym)
+
+ val body = localTyper.typedPos(fun.pos)(fun.body)
+ val methDef = DefDef(methSym, List(fun.vparams), body)
+
+ // Have to repack the type to avoid mismatches when existentials
+ // appear in the result - see SI-4869.
+ methDef.tpt setType localTyper.packedType(body, methSym)
+ methDef
+ }
+
+ // def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 =
+ def applyOrElseMethodDef = {
+ val methSym = anonClass.newMethod(fun.pos, nme.applyOrElse) setFlag (FINAL | OVERRIDE)
+
+ val List(argtpe) = formals
+ val A1 = methSym newTypeParameter(newTypeName("A1")) setInfo TypeBounds.upper(argtpe)
+ val B1 = methSym newTypeParameter(newTypeName("B1")) setInfo TypeBounds.lower(restpe)
+ val methFormals = List(A1.tpe, functionType(List(A1.tpe), B1.tpe))
+ val params@List(x, default) = methSym newSyntheticValueParams methFormals
+ methSym setInfoAndEnter polyType(List(A1, B1), MethodType(params, B1.tpe))
+
+ val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), List(x))
+ val body = localTyper.typedPos(fun.pos) { import CODE._
+ gen.mkUncheckedMatch(gen.withDefaultCase(substParam(fun.body), scrut => REF(default) APPLY (REF(x))))
}
+ body.changeOwner(fun.symbol -> methSym)
+
+ val methDef = DefDef(methSym, body)
- override def caseVirtualizedMatch(orig: Tree, _match: Tree, targs: List[Tree], scrut: Tree, matcher: Tree): Tree = {assert(false); orig}
- // {
- // object noOne extends Transformer {
- // override val treeCopy = newStrictTreeCopier // must duplicate everything
- // val one = _match.tpe member newTermName("one")
- // override def transform(tree: Tree): Tree = tree match {
- // case Apply(fun, List(a)) if fun.symbol == one =>
- // // blow one's argument away since all we want to know is whether the match succeeds or not
- // // (the alternative, making `one` CBN, would entail moving away from Option)
- // Apply(fun.duplicate, List(gen.mkZeroContravariantAfterTyper(a.tpe)))
- // case _ =>
- // super.transform(tree)
- // }
- // }
- // substTree(Apply(Apply(TypeApply(Select(_match.duplicate, _match.tpe.member(newTermName("isSuccess"))), targs map (_.duplicate)), List(scrut.duplicate)), List(noOne.transform(matcher))))
- // }
-
- override def caseVirtualizedMatchOpt(orig: Tree, zero: ValDef, x: ValDef, matchRes: ValDef, keepGoing: ValDef, stats: List[Tree], epilogue: Tree, wrap: Tree => Tree) = {assert(false); orig}
- // {
- // object dropMatchResAssign extends Transformer {
- // // override val treeCopy = newStrictTreeCopier // will duplicate below
- // override def transform(tree: Tree): Tree = tree match {
- // // don't compute the result of the match -- remove the block for the RHS (emitted by pmgen.one), except for the assignment to keepGoing
- // case gen.VirtualCaseDef(assignKeepGoing, matchRes, zero) if assignKeepGoing.lhs.symbol eq keepGoing.symbol =>
- // Block(List(assignKeepGoing), zero)
- // case _ =>
- // super.transform(tree)
- // }
- // }
- // val statsNoMatchRes: List[Tree] = stats map (dropMatchResAssign.transform) toList
- // val idaBlock = wrap(Block(
- // zero ::
- // x ::
- // /* drop matchRes def */
- // keepGoing ::
- // statsNoMatchRes,
- // NOT(REF(keepGoing.symbol)) // replace `if (keepGoing) throw new MatchError(...) else matchRes` epilogue by `!keepGoing`
- // ))
- // substTree(idaBlock.duplicate) // duplicate on block as a whole to ensure valdefs are properly cloned and substed
- // }
+ // Have to repack the type to avoid mismatches when existentials
+ // appear in the result - see SI-4869.
+ methDef.tpt setType localTyper.packedType(body, methSym)
+ methDef
}
- DefDef(m, isDefinedAtTransformer(fun.body))
- }
+ // duplicate before applyOrElseMethodDef is run so we start with the same symbols as applyOrElseMethodDef
+ // otherwise `TreeSymSubstituter(fun.vparams map (_.symbol), params)` won't work as the subst has been run already
+ val bodyForIDA = fun.body.duplicate
+ def isDefinedAtMethodDef = {
+ val methSym = anonClass.newMethod(nme.isDefinedAt, fun.pos, FINAL)
+ val params = methSym newSyntheticValueParams formals
+ methSym setInfoAndEnter MethodType(params, BooleanClass.tpe)
+
+ val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), params)
+ def doSubst(x: Tree) = substParam(resetLocalAttrs(x)) // see pos/t1761 for why `resetLocalAttrs`
+ object isDefinedAtTransformer extends gen.MatchMatcher {
+ // TODO: optimize duplication, but make sure ValDef's introduced by wrap are treated correctly
+ override def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = { import CODE._
+ gen.mkUncheckedMatch(
+ if (cases exists treeInfo.isDefaultCase) TRUE_typed
+ else
+ doSubst(wrap(
+ Match(selector,
+ (cases map (c => deriveCaseDef(c)(x => TRUE_typed))) :+ (
+ DEFAULT ==> FALSE_typed)
+ )))
+ )
+ }
+ }
+ val body = isDefinedAtTransformer(bodyForIDA)
+ body.changeOwner(fun.symbol -> methSym)
- val members =
- if (isPartial) List(applyMethodDef, isDefinedAtMethodDef)
- else List(applyMethodDef)
+ DefDef(methSym, body)
+ }
+
+ val members =
+ if (isPartial) List(applyOrElseMethodDef, isDefinedAtMethodDef)
+ else List(applyMethodDef)
- localTyper.typedPos(fun.pos) {
- Block(
- List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, fun.pos)),
- Typed(New(anonClass.tpe), TypeTree(fun.tpe)))
+ localTyper.typedPos(fun.pos) {
+ Block(
+ List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, fun.pos)),
+ Typed(New(anonClass.tpe), TypeTree(fun.tpe)))
+ }
}
- }
- }
def transformArgs(pos: Position, fun: Symbol, args: List[Tree], formals: List[Type]) = {
val isJava = fun.isJavaDefined
diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
index eb0d489901..f6d1e42c32 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
@@ -79,7 +79,17 @@ abstract class Duplicators extends Analyzer {
override def mapOver(tpe: Type): Type = tpe match {
case TypeRef(NoPrefix, sym, args) if sym.isTypeParameterOrSkolem =>
- val sym1 = context.scope.lookup(sym.name)
+ var sym1 = context.scope.lookup(sym.name)
+ if (sym1 eq NoSymbol) {
+ // try harder (look in outer scopes)
+ // with virtpatmat, this can happen when the sym is referenced in the scope of a LabelDef but is defined in the scope of an outer DefDef (e.g., in AbstractPartialFunction's andThen)
+ BodyDuplicator.super.silent(_.typedType(Ident(sym.name))) match {
+ case SilentResultValue(t) =>
+ sym1 = t.symbol
+ debuglog("fixed by trying harder: "+(sym, sym1, context))
+ case _ =>
+ }
+ }
// assert(sym1 ne NoSymbol, tpe)
if ((sym1 ne NoSymbol) && (sym1 ne sym)) {
debuglog("fixing " + sym + " -> " + sym1)
@@ -255,7 +265,10 @@ abstract class Duplicators extends Analyzer {
case ldef @ LabelDef(name, params, rhs) =>
// log("label def: " + ldef)
+ // in case the rhs contains any definitions -- TODO: is this necessary?
+ invalidate(rhs)
ldef.tpe = null
+
// since typer does not create the symbols for a LabelDef's params,
// we do that manually here -- we should really refactor LabelDef to be a subclass of DefDef
def newParam(p: Tree): Ident = {
@@ -265,6 +278,7 @@ abstract class Duplicators extends Analyzer {
val params1 = params map newParam
val rhs1 = (new TreeSubstituter(params map (_.symbol), params1) transform rhs) // TODO: duplicate?
rhs1.tpe = null
+
super.typed(treeCopy.LabelDef(tree, name, params1, rhs1), mode, pt)
case Bind(name, _) =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 06a7311f79..7d2e587b3f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2186,17 +2186,24 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
anonClass addAnnotation serialVersionUIDAnnotation
- def mkParams(methodSym: Symbol) = {
+ def deriveFormals =
+ selOverride match {
+ case None if targs.isEmpty => Nil
+ case None => targs.init // is there anything we can do if targs.isEmpty??
+ case Some((vparams, _)) =>
+ vparams map {p => if(p.tpt.tpe == null) typedType(p.tpt).tpe else p.tpt.tpe}
+ }
+
+ def mkParams(methodSym: Symbol, formals: List[Type] = deriveFormals) = {
selOverride match {
case None if targs.isEmpty => MissingParameterTypeAnonMatchError(tree, pt); (Nil, EmptyTree)
case None =>
- val ps = methodSym newSyntheticValueParams targs.init // is there anything we can do if targs.isEmpty??
+ val ps = methodSym newSyntheticValueParams formals // is there anything we can do if targs.isEmpty??
val ids = ps map (p => Ident(p.name))
val sel = atPos(tree.pos.focusStart) { if (arity == 1) ids.head else gen.mkTuple(ids) }
(ps, sel)
case Some((vparams, sel)) =>
- val newParamSyms = vparams map {p =>
- val tp = if(p.tpt.tpe == null) typedType(p.tpt).tpe else p.tpt.tpe
+ val newParamSyms = (vparams, formals).zipped map {(p, tp) =>
methodSym.newValueParameter(p.name, focusPos(p.pos), SYNTHETIC) setInfo tp
}
@@ -2209,7 +2216,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// need to duplicate the cases before typing them to generate the apply method, or the symbols will be all messed up
val casesTrue = if (isPartial) cases map (c => deriveCaseDef(c)(x => TRUE_typed).duplicate) else Nil
- val applyMethod = {
+ def applyMethod = {
// rig the show so we can get started typing the method body -- later we'll correct the infos...
anonClass setInfo ClassInfoType(List(ObjectClass.tpe, pt, SerializableClass.tpe), newScope, anonClass)
val methodSym = anonClass.newMethod(nme.apply, tree.pos, FINAL)
@@ -2224,25 +2231,59 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, cases, mode, ptRes)
- val formalTypes = paramSyms map (_.tpe)
- val parents =
- if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, List(formalTypes.head, resTp)), SerializableClass.tpe)
- else List(appliedType(AbstractFunctionClass(arity).typeConstructor, formalTypes :+ resTp), SerializableClass.tpe)
+ val methFormals = paramSyms map (_.tpe)
+ val parents = List(appliedType(AbstractFunctionClass(arity).typeConstructor, methFormals :+ resTp), SerializableClass.tpe)
anonClass setInfo ClassInfoType(parents, newScope, anonClass)
methodSym setInfoAndEnter MethodType(paramSyms, resTp)
- // use apply's parameter since the scrut's type has been widened
- def missingCase(scrut_ignored: Tree) = (funThis DOT nme.missingCase) (REF(paramSyms.head))
+ DefDef(methodSym, methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation))
+ }
+ }
+
+ // def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 =
+ def applyOrElseMethodDef = {
+ // rig the show so we can get started typing the method body -- later we'll correct the infos...
+ // targs were type arguments for PartialFunction, so we know they will work for AbstractPartialFunction as well
+ def parents(targs: List[Type]) = List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe)
+
+ anonClass setInfo ClassInfoType(parents(targs), newScope, anonClass)
+ val methodSym = anonClass.newMethod(nme.applyOrElse, tree.pos, FINAL | OVERRIDE)
+
+ // create the parameter that corresponds to the function's parameter
+ val List(argTp) = deriveFormals
+ val A1 = methodSym newTypeParameter(newTypeName("A1")) setInfo TypeBounds.upper(argTp)
+ val (List(x), selector) = mkParams(methodSym, List(A1.tpe))
+
+ if (selector eq EmptyTree) EmptyTree
+ else {
+ // applyOrElse's default parameter:
+ val B1 = methodSym newTypeParameter(newTypeName("B1")) setInfo TypeBounds.empty //lower(resTp)
+ val default = methodSym newValueParameter(newTermName("default"), focusPos(tree.pos), SYNTHETIC) setInfo functionType(List(A1.tpe), B1.tpe)
+
+ val paramSyms = List(x, default)
+ methodSym setInfoAndEnter polyType(List(A1, B1), MethodType(paramSyms, B1.tpe))
+
+ val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it)
+ paramSyms foreach (methodBodyTyper.context.scope enter _)
+
+ val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, cases, mode, ptRes)
+
+ anonClass setInfo ClassInfoType(parents(List(argTp, resTp)), newScope, anonClass)
+ B1 setInfo TypeBounds.lower(resTp)
+ anonClass.info.decls enter methodSym // methodSym's info need not change (B1's bound has been updated instead)
+
+ // use applyOrElse's first parameter since the scrut's type has been widened
+ def doDefault(scrut_ignored: Tree) = REF(default) APPLY (REF(x))
- val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, if (isPartial) Some(missingCase) else None)
+ val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, B1.tpe, doTranslation, Some(doDefault))
DefDef(methodSym, body)
}
}
def isDefinedAtMethod = {
- val methodSym = anonClass.newMethod(nme._isDefinedAt, tree.pos, FINAL)
+ val methodSym = anonClass.newMethod(nme.isDefinedAt, tree.pos, FINAL)
val (paramSyms, selector) = mkParams(methodSym)
if (selector eq EmptyTree) EmptyTree
else {
@@ -2257,7 +2298,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
}
- val members = if (!isPartial) List(applyMethod) else List(applyMethod, isDefinedAtMethod)
+ val members = if (!isPartial) List(applyMethod) else List(applyOrElseMethodDef, isDefinedAtMethod)
if (members.head eq EmptyTree) setError(tree)
else typed(Block(List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, tree.pos)), New(anonClass.tpe)), mode, pt)
}
@@ -4142,7 +4183,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
var defEntry: ScopeEntry = null // the scope entry of defSym, if defined in a local scope
var cx = startingIdentContext
- while (defSym == NoSymbol && cx != NoContext) {
+ while (defSym == NoSymbol && cx != NoContext && (cx.scope ne null)) { // cx.scope eq null arises during FixInvalidSyms in Duplicators
// !!! Shouldn't the argument to compileSourceFor be cx, not context?
// I can't tell because those methods do nothing in the standard compiler,
// presumably they are overridden in the IDE.
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 }
}