From 322068fb8a1eb871280b19199505c30d8a25848b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 18 Mar 2006 19:43:30 +0000 Subject: 1. Added a range method to Array.scala 2. Enabled extended implicit conversions 3. Implemented non-local returns --- src/compiler/scala/tools/nsc/Global.scala | 2 +- .../scala/tools/nsc/backend/icode/GenICode.scala | 11 ++- .../scala/tools/nsc/symtab/Definitions.scala | 2 + src/compiler/scala/tools/nsc/symtab/StdNames.scala | 1 + .../scala/tools/nsc/symtab/classfile/Pickler.scala | 2 + .../scala/tools/nsc/transform/LambdaLift.scala | 2 +- .../scala/tools/nsc/transform/UnCurry.scala | 88 +++++++++++++++++++++- .../scala/tools/nsc/typechecker/Namers.scala | 7 +- .../scala/tools/nsc/typechecker/Typers.scala | 23 +++++- 9 files changed, 125 insertions(+), 13 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 12c99ba127..7777a89cfa 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -216,7 +216,7 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable val global: Global.this.type = Global.this } - object analyzer extends AnyRef with Analyzer { + object analyzer extends Analyzer { val global: Global.this.type = Global.this; } diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 655a2ca1ef..497ed3d5d7 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -736,9 +736,14 @@ abstract class GenICode extends SubComponent { ctx.bb.emit(LOAD_MODULE(tree.symbol), tree.pos); generatedType = toTypeKind(tree.symbol.info); } else { - val Some(l) = ctx.method.lookupLocal(tree.symbol); - ctx.bb.emit(LOAD_LOCAL(l, tree.symbol.isValueParameter), tree.pos); - generatedType = l.kind; + try { + val Some(l) = ctx.method.lookupLocal(tree.symbol); + ctx.bb.emit(LOAD_LOCAL(l, tree.symbol.isValueParameter), tree.pos); + generatedType = l.kind; + } catch { + case ex: MatchError => + throw new Error("symbol "+tree.symbol+" does not exist in "+ctx.method) + } } } ctx diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index 81a9448ddd..2bd81054b1 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -38,6 +38,7 @@ trait Definitions requires SymbolTable { var StringClass: Symbol = _; var ThrowableClass: Symbol = _; var NullPointerExceptionClass: Symbol = _; + var NonLocalReturnExceptionClass: Symbol = _; // the scala value classes var UnitClass: Symbol = _; @@ -326,6 +327,7 @@ trait Definitions requires SymbolTable { StringClass = getClass("java.lang.String"); ThrowableClass = getClass("java.lang.Throwable"); NullPointerExceptionClass = getClass("java.lang.NullPointerException"); + NonLocalReturnExceptionClass = getClass("scala.runtime.NonLocalReturnException"); // the scala value classes UnitClass = getValueClass("Unit", 'V'); diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index 17f94dee33..67c17c54d1 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -233,6 +233,7 @@ trait StdNames requires SymbolTable { val elements = newTermName("elements"); val eq = newTermName("eq"); val equals_ = newTermName("equals"); + val ex = newTermName("ex"); val fail = newTermName("fail"); val report = newTermName("report"); val false_ = newTermName("false"); diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index 0119f2b491..58bd438d1b 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -251,6 +251,8 @@ abstract class Pickler extends SubComponent { if (settings.debug.value) log("" + ep + " entries");//debug for (val i <- Iterator.range(0, ep)) writeEntry(entries(i)); } + + override def toString() = "" + rootName + " in " + rootOwner; } } diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index 22057d7854..c76493b9ea 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -305,7 +305,7 @@ abstract class LambdaLift extends InfoTransform { copy.ValDef(tree, mods, name, tpt1, rhs1) } else tree case Return(Block(stats, value)) => - Block(stats, copy.Return(tree, value)) setType tree.tpe setPos tree.pos; + Block(stats, copy.Return(tree, value)) setType tree.tpe setPos tree.pos case Return(expr) => if (sym != currentOwner.enclMethod) { System.out.println(sym);//debug diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 82521b7568..88e911de37 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -6,6 +6,7 @@ package scala.tools.nsc.transform; import symtab.Flags._; +import scala.collection.mutable.HashMap /**/ /** - uncurry all symbol and tree types (@see UnCurryPhase) @@ -25,6 +26,7 @@ import symtab.Flags._; * (a_1:_*) => (a_1)g * - convert implicit method types to method types * - convert non-trivial catches in try statements to matches + * - convert non-local returns to throws with enclosing try statements. */ /**/ abstract class UnCurry extends InfoTransform { @@ -36,6 +38,8 @@ abstract class UnCurry extends InfoTransform { def newTransformer(unit: CompilationUnit): Transformer = new UnCurryTransformer(unit); override def changesBaseClasses = false; +// ------ Type transformation -------------------------------------------------------- + private val uncurry = new TypeMap { def apply(tp: Type): Type = tp match { case MethodType(formals, MethodType(formals1, restpe)) => @@ -74,7 +78,7 @@ abstract class UnCurry extends InfoTransform { } catch { case ex: Throwable => System.out.println("exception when traversing " + tree); - throw ex + throw ex } /* Is tree a reference `x' to a call by name parameter that neeeds to be converted to @@ -97,6 +101,75 @@ abstract class UnCurry extends InfoTransform { uncurry(tp) } +// ------- Handling non-local returns ------------------------------------------------- + + /** The type of a non-local return expression for given method */ + private def nonLocalReturnExceptionType(meth: Symbol) = + appliedType( + NonLocalReturnExceptionClass.typeConstructor, + List(meth.tpe.finalResultType)) + + /** A hashmap from method symbols to non-local return keys */ + private val nonLocalReturnKeys = new HashMap[Symbol, Symbol]; + + /** Return non-local return key for given method */ + private def nonLocalReturnKey(meth: Symbol) = nonLocalReturnKeys.get(meth) match { + case Some(k) => k + case None => + val k = meth.newValue(meth.pos, unit.fresh.newName("nonLocalReturnKey")) + .setFlag(SYNTHETIC).setInfo(ObjectClass.tpe) + nonLocalReturnKeys(meth) = k + k + } + + /** Generate a non-local return throw with given return expression from given method. + * I.e. for the method's non-local return key, generate: + * + * throw new NonLocalReturnException(key, expr) + */ + private def nonLocalReturnThrow(expr: Tree, meth: Symbol) = + localTyper.atOwner(currentOwner).typed { + Throw( + New( + TypeTree(nonLocalReturnExceptionType(meth)), + List(List(Ident(nonLocalReturnKey(meth)), expr)))) + } + + /** Transform (body, key) to: + * + * { + * val key = new Object() + * try { + * body + * } catch { + * case ex: NonLocalReturnException => + * if (ex.key().eq(key)) ex.value() + * else throw ex + * } + * } + */ + private def nonLocalReturnTry(body: Tree, key: Symbol, meth: Symbol) = { + localTyper.atOwner(currentOwner).typed { + val extpe = nonLocalReturnExceptionType(meth); + val ex = meth.newValue(body.pos, nme.ex) setInfo extpe; + val pat = Bind(ex, Typed(Ident(nme.WILDCARD), TypeTree(extpe))); + val rhs = + If( + Apply( + Select( + Apply(Select(Ident(ex), "key"), List()), + Object_eq), + List(Ident(key))), + Apply(Select(Ident(ex), "value"), List()), + Throw(Ident(ex))); + val keyDef = ValDef(key, New(TypeTree(ObjectClass.tpe), List(List()))) + val tryCatch = Try(body, List(CaseDef(pat, EmptyTree, rhs)), EmptyTree) + Block(List(keyDef), tryCatch) + } + } + +// ------ Transforming anonymous functions and by-name-arguments ---------------- + /* Transform a function node (x_1,...,x_n) => body of type FunctionN[T_1, .., T_N, R] to * * class $anon() extends Object() with FunctionN[T_1, .., T_N, R] with ScalaObject { @@ -200,6 +273,8 @@ abstract class UnCurry extends InfoTransform { } } +// ------ The tree transformers -------------------------------------------------------- + def mainTransform(tree: Tree): Tree = { def withNeedLift(needLift: Boolean)(f: => Tree): Tree = { @@ -327,7 +402,11 @@ abstract class UnCurry extends InfoTransform { } tree match { case DefDef(mods, name, tparams, vparamss, tpt, rhs) => - copy.DefDef(tree, mods, name, tparams, List(List.flatten(vparamss)), tpt, rhs); + val rhs1 = nonLocalReturnKeys.get(tree.symbol) match { + case None => rhs + case Some(k) => atPos(rhs.pos)(nonLocalReturnTry(rhs, k, tree.symbol)) + } + copy.DefDef(tree, mods, name, tparams, List(List.flatten(vparamss)), tpt, rhs1); case Try(body, catches, finalizer) => if (catches forall treeInfo.isCatchCase) tree else { @@ -343,7 +422,7 @@ abstract class UnCurry extends InfoTransform { Match(Ident(exname), cases)) } if (settings.debug.value) log("rewrote try: " + catches + " ==> " + catchall); - val catches1 = typer.atOwner(currentOwner).typedCases( + val catches1 = localTyper.atOwner(currentOwner).typedCases( tree, List(catchall), ThrowableClass.tpe, WildcardType); copy.Try(tree, body, catches1, finalizer) } @@ -357,6 +436,9 @@ abstract class UnCurry extends InfoTransform { applyUnary(tree) case TypeApply(_, _) => applyUnary(tree) + case Return(expr) if (tree.symbol != currentOwner.enclMethod) => + if (settings.debug.value) log("non local return in "+tree.symbol+" from "+currentOwner.enclMethod) + atPos(tree.pos)(nonLocalReturnThrow(expr, tree.symbol)) case _ => tree } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 1b191da676..da9918c317 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -56,7 +56,9 @@ trait Namers requires Analyzer { sym.flags = flags | lockedFlag; if (sym.isModule && sym.moduleClass != NoSymbol) updatePosFlags(sym.moduleClass, pos, (flags & ModuleToClassFlags) | MODULE | FINAL); - if (sym.owner.isPackageClass && sym.linkedSym.rawInfo.isInstanceOf[loaders.SymbolLoader]) + if (sym.owner.isPackageClass && + (sym.linkedSym.rawInfo.isInstanceOf[loaders.SymbolLoader] || + sym.linkedSym.rawInfo.isComplete && sym.validForRun != currentRun)) // pre-set linked symbol to NoType, in case it is not loaded together with this symbol. sym.linkedSym.setInfo(NoType); sym @@ -149,6 +151,7 @@ trait Namers requires Analyzer { private def enterModuleSymbol(pos: int, flags: int, name: Name): Symbol = { var m: Symbol = context.scope.lookup(name); if (m.isModule && !m.isPackage && !currentRun.compiles(m) && (context.scope == m.owner.info.decls)) { + updatePosFlags(m, pos, flags) } else { if (m.isTerm && !m.isPackage && !currentRun.compiles(m) && (context.scope == m.owner.info.decls)) @@ -307,7 +310,6 @@ trait Namers requires Analyzer { if (settings.debug.value) log("defining " + sym); val tp = typeSig(tree); sym.setInfo(tp); - if (settings.Xgadt.value) System.out.println("" + sym + ":" + tp); if (settings.debug.value) log("defined " + sym); validate(sym); } @@ -384,7 +386,6 @@ trait Namers requires Analyzer { val clazz = context.owner; val parents = typer.parentTypes(templ) map (p => if (p.tpe.isError) AnyRefClass.tpe else p.tpe); val decls = new Scope(); - log("members of " + clazz + "=" + decls.hashCode());//debug new Namer(context.make(templ, clazz, decls)).enterSyms(templ.body); ClassInfoType(parents, decls, clazz) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 78197a0ab3..b9e435c7b6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -107,6 +107,8 @@ trait Typers requires Analyzer { // time. In that case functions may no longer be // be coerced with implicit views. + val LHSmode = 0x400; // Set for the left-hand side of an assignment + private val stickyModes: int = EXPRmode | PATTERNmode | TYPEmode /** Report a type error. @@ -355,7 +357,7 @@ trait Typers requires Analyzer { TypeTree(tparam.tpe) setOriginal tree /* setPos tree.pos */)) setPos tree.pos context.undetparams = context.undetparams ::: tparams1 adapt(tree1 setType restpe.substSym(tparams, tparams1), mode, pt) - case mt: ImplicitMethodType if ((mode & (EXPRmode | FUNmode)) == EXPRmode) => // (4.1) + case mt: ImplicitMethodType if ((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) => // (4.1) val tree1 = if (!context.undetparams.isEmpty & (mode & POLYmode) == 0) { // (9) val tparams = context.undetparams @@ -1046,6 +1048,22 @@ trait Typers requires Analyzer { errorTree(tree, ""+fun+" does not take parameters") } + def tryTypedArgs(args: List[Tree]) = { + val reportGeneralErrors = context.reportGeneralErrors + val reportAmbiguousErrors = context.reportAmbiguousErrors + try { + context.reportGeneralErrors = false + context.reportAmbiguousErrors = false + typedArgs(args) + } catch { + case ex: TypeError => + null + } finally { + context.reportGeneralErrors = reportGeneralErrors + context.reportAmbiguousErrors = reportAmbiguousErrors + } + } + def tryTypedApply(fun: Tree, args: List[Tree]): Tree = { val reportGeneralErrors = context.reportGeneralErrors val reportAmbiguousErrors = context.reportAmbiguousErrors @@ -1321,9 +1339,10 @@ trait Typers requires Analyzer { case Assign(lhs, rhs) => def isGetter(sym: Symbol) = sym.info match { case PolyType(List(), _) => sym.owner.isClass && !sym.isStable + case _: ImplicitMethodType => sym.owner.isClass && !sym.isStable case _ => false } - val lhs1 = typed(lhs) + val lhs1 = typed(lhs, EXPRmode | LHSmode, WildcardType) val varsym = lhs1.symbol if (varsym != null && isGetter(varsym)) { lhs1 match { -- cgit v1.2.3