From 0bcc8f8f92bbee772924813d00512f3765d4beee Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 27 Feb 2012 21:58:26 -0800 Subject: Specialized NonLocalReturnControl. From the extempore archive of already implemented things. --- src/compiler/scala/reflect/internal/StdNames.scala | 1 + src/compiler/scala/reflect/internal/Trees.scala | 13 +++--- src/compiler/scala/tools/nsc/ast/TreeDSL.scala | 8 ++-- src/compiler/scala/tools/nsc/ast/TreeGen.scala | 17 +++++-- .../scala/tools/nsc/javac/JavaParsers.scala | 2 +- .../scala/tools/nsc/transform/CleanUp.scala | 8 +++- .../scala/tools/nsc/transform/Constructors.scala | 4 +- .../scala/tools/nsc/transform/LambdaLift.scala | 2 +- .../scala/tools/nsc/transform/UnCurry.scala | 53 ++++++++-------------- src/library/scala/reflect/api/Trees.scala | 4 ++ .../scala/runtime/NonLocalReturnControl.scala | 4 +- 11 files changed, 60 insertions(+), 56 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala index 3c181e39c6..bcd3fc8b14 100644 --- a/src/compiler/scala/reflect/internal/StdNames.scala +++ b/src/compiler/scala/reflect/internal/StdNames.scala @@ -347,6 +347,7 @@ trait StdNames extends NameManglers { self: SymbolTable => val isInstanceOf_ : NameType = "isInstanceOf" val isInstanceOf_Ob : NameType = "$isInstanceOf" val java: NameType = "java" + val key: NameType = "key" val lang: NameType = "lang" val length: NameType = "length" val lengthCompare: NameType = "lengthCompare" diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala index 610c6dc493..3782b24c02 100644 --- a/src/compiler/scala/reflect/internal/Trees.scala +++ b/src/compiler/scala/reflect/internal/Trees.scala @@ -230,17 +230,18 @@ trait Trees extends api.Trees { self: SymbolTable => def Bind(sym: Symbol, body: Tree): Bind = Bind(sym.name, body) setSymbol sym - /** 0-1 argument list new, based on a symbol or type. - */ - def New(sym: Symbol, args: Tree*): Tree = - New(sym.tpe, args: _*) + def Try(body: Tree, cases: (Tree, Tree)*): Try = + Try(body, cases.toList map { case (pat, rhs) => CaseDef(pat, EmptyTree, rhs) }, EmptyTree) - def New(tpe: Type, args: Tree*): Tree = - New(TypeTree(tpe), List(args.toList)) + def Throw(tpe: Type, args: Tree*): Throw = + Throw(New(tpe, args: _*)) def Apply(sym: Symbol, args: Tree*): Tree = Apply(Ident(sym), args.toList) + def New(sym: Symbol, args: Tree*): Tree = + New(sym.tpe, args: _*) + def Super(sym: Symbol, mix: TypeName): Tree = Super(This(sym), mix) /** Block factory that flattens directly nested blocks. diff --git a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala index f361d45018..0d19b781e2 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala @@ -253,13 +253,11 @@ trait TreeDSL { } /** Top level accessible. */ - def MATCHERROR(arg: Tree) = Throw(New(MatchErrorClass, arg)) - /** !!! should generalize null guard from match error here. */ - def THROW(sym: Symbol): Throw = Throw(New(sym)) - def THROW(sym: Symbol, msg: Tree): Throw = Throw(New(sym, msg.TOSTRING())) + def MATCHERROR(arg: Tree) = Throw(MatchErrorClass.tpe, arg) + def THROW(sym: Symbol, msg: Tree): Throw = Throw(sym.tpe, msg.TOSTRING()) def NEW(tpt: Tree, args: Tree*): Tree = New(tpt, List(args.toList)) - def NEW(sym: Symbol, args: Tree*): Tree = New(sym, args: _*) + def NEW(sym: Symbol, args: Tree*): Tree = New(sym.tpe, args: _*) def DEF(name: Name, tp: Type): DefTreeStart = DEF(name) withType tp def DEF(name: Name): DefTreeStart = new DefTreeStart(name) diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index c7414bf34b..a94154e0ff 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -51,9 +51,8 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL { } // wrap the given expression in a SoftReference so it can be gc-ed - def mkSoftRef(expr: Tree): Tree = atPos(expr.pos) { - New(SoftReferenceClass, expr) - } + def mkSoftRef(expr: Tree): Tree = atPos(expr.pos)(New(SoftReferenceClass.tpe, expr)) + // annotate the expression with @unchecked def mkUnchecked(expr: Tree): Tree = atPos(expr.pos) { // This can't be "Annotated(New(UncheckedClass), expr)" because annotations @@ -220,6 +219,18 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL { def mkSynchronized(monitor: Tree, body: Tree): Tree = Apply(Select(monitor, Object_synchronized), List(body)) + def mkAppliedTypeForCase(clazz: Symbol): Tree = { + val numParams = clazz.typeParams.size + if (clazz.typeParams.isEmpty) Ident(clazz) + else AppliedTypeTree(Ident(clazz), 1 to numParams map (_ => Bind(tpnme.WILDCARD, EmptyTree)) toList) + } + def mkBindForCase(patVar: Symbol, clazz: Symbol, targs: List[Type]): Tree = { + Bind(patVar, Typed(Ident(nme.WILDCARD), + if (targs.isEmpty) mkAppliedTypeForCase(clazz) + else AppliedTypeTree(Ident(clazz), targs map TypeTree) + )) + } + def wildcardStar(tree: Tree) = atPos(tree.pos) { Typed(tree, Ident(tpnme.WILDCARD_STAR)) } diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 4d94ed68fc..06b06c50a6 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -393,7 +393,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { // assumed true unless we see public/private/protected var isPackageAccess = true var annots: List[Tree] = Nil - def addAnnot(sym: Symbol) = annots :+= New(sym) + def addAnnot(sym: Symbol) = annots :+= New(sym.tpe) while (true) { in.token match { diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 2c024fe6fa..a6ecb16b43 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -85,6 +85,11 @@ abstract class CleanUp extends Transform with ast.TreeDSL { case "poly-cache" => POLY_CACHE } + def shouldRewriteTry(tree: Try) = { + val sym = tree.tpe.typeSymbol + forMSIL && (sym != UnitClass) && (sym != NothingClass) + } + private def typedWithPos(pos: Position)(tree: Tree) = localTyper.typedPos(pos)(tree) @@ -560,8 +565,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { * Hence, we here rewrite all try blocks with a result != {Unit, All} such that they * store their result in a local variable. The catch blocks are adjusted as well. * The try tree is subsituted by a block whose result expression is read of that variable. */ - case theTry @ Try(block, catches, finalizer) - if theTry.tpe.typeSymbol != definitions.UnitClass && theTry.tpe.typeSymbol != definitions.NothingClass => + case theTry @ Try(block, catches, finalizer) if shouldRewriteTry(theTry) => val tpe = theTry.tpe.widen val tempVar = currentOwner.newVariable(mkTerm(nme.EXCEPTION_RESULT_PREFIX), theTry.pos).setInfo(tpe) def assignBlock(rhs: Tree) = super.transform(BLOCK(Ident(tempVar) === transform(rhs))) diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index 804c15a350..d8f19f85c0 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -126,7 +126,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { if (from.name != nme.OUTER) result else localTyper.typedPos(to.pos) { - IF (from OBJ_EQ NULL) THEN THROW(NullPointerExceptionClass) ELSE result + IF (from OBJ_EQ NULL) THEN Throw(NullPointerExceptionClass.tpe) ELSE result } } @@ -515,7 +515,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { } def delayedInitCall(closure: Tree) = localTyper.typedPos(impl.pos) { - gen.mkMethodCall(This(clazz), delayedInitMethod, Nil, List(New(closure.symbol, This(clazz)))) + gen.mkMethodCall(This(clazz), delayedInitMethod, Nil, List(New(closure.symbol.tpe, This(clazz)))) } /** Return a pair consisting of (all statements up to and including superclass and trait constr calls, rest) */ diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index f2c3402d21..dafce76d45 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -420,7 +420,7 @@ abstract class LambdaLift extends InfoTransform { case Try(block, catches, finalizer) => Try(refConstr(block), catches map refConstrCase, finalizer) case _ => - New(sym, expr) + New(sym.tpe, expr) } def refConstrCase(cdef: CaseDef): CaseDef = CaseDef(cdef.pat, cdef.guard, refConstr(cdef.body)) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index f49c340bec..b9b115b7c8 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -144,13 +144,13 @@ abstract class UnCurry extends InfoTransform * todo: maybe clone a pre-existing exception instead? * (but what to do about exceptions that miss their targets?) */ - private def nonLocalReturnThrow(expr: Tree, meth: Symbol) = - localTyper.typed { - Throw( - New( - TypeTree(nonLocalReturnExceptionType(expr.tpe)), - List(List(Ident(nonLocalReturnKey(meth)), expr)))) - } + private def nonLocalReturnThrow(expr: Tree, meth: Symbol) = localTyper typed { + Throw( + nonLocalReturnExceptionType(expr.tpe.widen), + Ident(nonLocalReturnKey(meth)), + expr + ) + } /** Transform (body, key) to: * @@ -166,31 +166,18 @@ abstract class UnCurry extends InfoTransform * } */ private def nonLocalReturnTry(body: Tree, key: Symbol, meth: Symbol) = { - localTyper.typed { - val extpe = nonLocalReturnExceptionType(meth.tpe.finalResultType) - val ex = meth.newValue(nme.ex, body.pos) setInfo extpe - val pat = Bind(ex, - Typed(Ident(nme.WILDCARD), - AppliedTypeTree(Ident(NonLocalReturnControlClass), - List(Bind(tpnme.WILDCARD, - EmptyTree))))) - val rhs = - If( - Apply( - Select( - Apply(Select(Ident(ex), "key"), List()), - Object_eq), - List(Ident(key))), - Apply( - TypeApply( - Select( - Apply(Select(Ident(ex), "value"), List()), - Any_asInstanceOf), - List(TypeTree(meth.tpe.finalResultType))), - List()), - Throw(Ident(ex))) - val keyDef = ValDef(key, New(ObjectClass)) - val tryCatch = Try(body, List(CaseDef(pat, EmptyTree, rhs)), EmptyTree) + localTyper typed { + val extpe = nonLocalReturnExceptionType(meth.tpe.finalResultType) + val ex = meth.newValue(body.pos, nme.ex) setInfo extpe + val pat = gen.mkBindForCase(ex, NonLocalReturnControlClass, List(meth.tpe.finalResultType)) + val rhs = ( + IF ((ex DOT nme.key)() OBJ_EQ Ident(key)) + THEN ((ex DOT nme.value)()) + ELSE (Throw(Ident(ex))) + ) + val keyDef = ValDef(key, New(ObjectClass.tpe)) + val tryCatch = Try(body, pat -> rhs) + Block(List(keyDef), tryCatch) } } @@ -357,7 +344,7 @@ abstract class UnCurry extends InfoTransform localTyper.typedPos(fun.pos) { Block( List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, fun.pos)), - Typed(New(anonClass), TypeTree(fun.tpe))) + Typed(New(anonClass.tpe), TypeTree(fun.tpe))) } } } diff --git a/src/library/scala/reflect/api/Trees.scala b/src/library/scala/reflect/api/Trees.scala index bf427df09a..181ce85dac 100644 --- a/src/library/scala/reflect/api/Trees.scala +++ b/src/library/scala/reflect/api/Trees.scala @@ -491,6 +491,10 @@ trait Trees { self: Universe => if (argss.isEmpty) Apply(superRef, Nil) else (superRef /: argss) (Apply) } + /** 0-1 argument list new, based on a type. + */ + def New(tpe: Type, args: Tree*): Tree = + New(TypeTree(tpe), List(args.toList)) /** Type annotation, eliminated by explicit outer */ case class Typed(expr: Tree, tpt: Tree) diff --git a/src/library/scala/runtime/NonLocalReturnControl.scala b/src/library/scala/runtime/NonLocalReturnControl.scala index 8be2745086..216e3e664b 100644 --- a/src/library/scala/runtime/NonLocalReturnControl.scala +++ b/src/library/scala/runtime/NonLocalReturnControl.scala @@ -6,12 +6,10 @@ ** |/ ** \* */ - - package scala.runtime import scala.util.control.ControlThrowable -class NonLocalReturnControl[T](val key: AnyRef, val value: T) extends ControlThrowable { +class NonLocalReturnControl[@specialized T](val key: AnyRef, val value: T) extends ControlThrowable { final override def fillInStackTrace(): Throwable = this } -- cgit v1.2.3