summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala31
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala26
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Names.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala4
-rw-r--r--test/files/run/pf-catch.check4
-rw-r--r--test/files/run/pf-catch.scala34
6 files changed, 86 insertions, 14 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 1ffb29809a..cc3910fdf3 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -1123,18 +1123,27 @@ self =>
}
case TRY =>
atPos(in.skipToken()) {
- val body =
- if (in.token == LBRACE) surround(LBRACE, RBRACE)(block(), Literal(()))
- else if (in.token == LPAREN) surround(LPAREN, RPAREN)(expr(), Literal(()))
- else expr()
- val catches =
- if (in.token == CATCH) {
+ val body = in.token match {
+ case LBRACE => surround(LBRACE, RBRACE)(block(), Literal(()))
+ case LPAREN => surround(LPAREN, RPAREN)(expr(), Literal(()))
+ case _ => expr()
+ }
+ def catchFromExpr() = List(makeCatchFromExpr(expr()))
+ val catches: List[CaseDef] =
+ if (in.token != CATCH) Nil
+ else {
in.nextToken()
- surround(LBRACE, RBRACE)(caseClauses(), Nil)
- } else Nil
- val finalizer =
- if (in.token == FINALLY) { in.nextToken(); expr() }
- else EmptyTree
+ if (in.token == LBRACE)
+ surround(LBRACE, RBRACE)(
+ if (in.token == CASE) caseClauses() else catchFromExpr(),
+ Nil
+ )
+ else catchFromExpr()
+ }
+ val finalizer = in.token match {
+ case FINALLY => in.nextToken() ; expr()
+ case _ => EmptyTree
+ }
Try(body, catches, finalizer)
}
case WHILE =>
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index 01cfc440c5..afb9999db8 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -17,8 +17,10 @@ abstract class TreeBuilder {
val global: Global
import global._
- def freshName(prefix: String): Name
def freshName(): Name = freshName("x$")
+ def freshName(prefix: String): Name
+ def freshTermName(prefix: String): TermName
+ def freshTypeName(prefix: String): TypeName
def o2p(offset: Int): Position
def r2p(start: Int, point: Int, end: Int): Position
@@ -467,6 +469,28 @@ abstract class TreeBuilder {
def makeCaseDef(pat: Tree, guard: Tree, rhs: Tree): CaseDef =
CaseDef(patvarTransformer.transform(pat), guard, rhs)
+ /** Creates tree representing:
+ * { case x: Throwable =>
+ * val catchFn = catchExpr
+ * if (catchFn isDefinedAt x) catchFn(x) else throw x
+ * }
+ */
+ def makeCatchFromExpr(catchExpr: Tree): CaseDef = {
+ val binder = freshTermName("x")
+ val pat = atPos(catchExpr.pos)(Bind(binder, Typed(Ident(nme.WILDCARD), Ident(tpnme.Throwable))))
+ val catchDef = ValDef(NoMods, freshTermName("catchExpr"), TypeTree(), catchExpr)
+ val catchFn = Ident(catchDef.name)
+ val body = Block(
+ List(catchDef),
+ If(
+ Apply(Select(catchFn, nme.isDefinedAt), List(Ident(binder))),
+ Apply(Select(catchFn, nme.apply), List(Ident(binder))),
+ Throw(Ident(binder))
+ )
+ )
+ makeCaseDef(pat, EmptyTree, body)
+ }
+
/** Create tree for pattern definition <val pat0 = rhs> */
def makePatDef(pat: Tree, rhs: Tree): List[Tree] =
makePatDef(Modifiers(0), pat, rhs)
diff --git a/src/compiler/scala/tools/nsc/symtab/Names.scala b/src/compiler/scala/tools/nsc/symtab/Names.scala
index 04cd8a8d84..1e4ff419ea 100644
--- a/src/compiler/scala/tools/nsc/symtab/Names.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Names.scala
@@ -176,6 +176,7 @@ trait Names extends reflect.generic.Names {
def isTypeName: Boolean
def toTermName: TermName
def toTypeName: TypeName
+ def bothNames: List[Name] = List(toTermName, toTypeName)
/** Copy bytes of this name to buffer cs, starting at position `offset`.
*/
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index e1a8daf6c8..072bda9097 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -1195,8 +1195,8 @@ trait Namers { self: Analyzer =>
}
def isValidSelector(from: Name)(fun : => Unit) {
- if (base.nonLocalMember(from) == NoSymbol &&
- base.nonLocalMember(from.toTypeName) == NoSymbol) fun
+ if (from.bothNames forall (x => (base nonLocalMember x) == NoSymbol))
+ fun
}
def checkSelectors(selectors: List[ImportSelector]): Unit = selectors match {
diff --git a/test/files/run/pf-catch.check b/test/files/run/pf-catch.check
new file mode 100644
index 0000000000..faee9566af
--- /dev/null
+++ b/test/files/run/pf-catch.check
@@ -0,0 +1,4 @@
+NoSuchElementException
+NullPointerException slipped by.
+NoSuchElementException
+DEBUG: NullPointerException
diff --git a/test/files/run/pf-catch.scala b/test/files/run/pf-catch.scala
new file mode 100644
index 0000000000..f0b8baeeb3
--- /dev/null
+++ b/test/files/run/pf-catch.scala
@@ -0,0 +1,34 @@
+object Test {
+ def shortName(x: AnyRef) = x.getClass.getName split '.' last
+ type Handler[+T] = PartialFunction[Throwable, T]
+
+ val standardHandler: Handler[String] = {
+ case x: java.util.NoSuchElementException => shortName(x)
+ case x: java.lang.IllegalArgumentException => shortName(x)
+ }
+
+ def fn[T: Handler](body: => T): T = {
+ try body
+ catch implicitly[Handler[T]]
+ }
+
+ def f1 = {
+ implicit val myHandler = standardHandler
+ println(fn(Nil.head))
+ println(fn(null.toString))
+ }
+ def f2 = {
+ implicit val myHandler: Handler[String] = standardHandler orElse {
+ case x => "DEBUG: " + shortName(x)
+ }
+ println(fn(Nil.head))
+ println(fn(null.toString))
+ }
+
+ def main(args: Array[String]): Unit = {
+ try f1
+ catch { case x => println(shortName(x) + " slipped by.") }
+
+ f2
+ }
+}