diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 31 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala | 26 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Names.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Namers.scala | 4 | ||||
-rw-r--r-- | test/files/run/pf-catch.check | 4 | ||||
-rw-r--r-- | test/files/run/pf-catch.scala | 34 |
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 + } +} |