summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2006-03-18 19:43:30 +0000
committerMartin Odersky <odersky@gmail.com>2006-03-18 19:43:30 +0000
commit322068fb8a1eb871280b19199505c30d8a25848b (patch)
tree490d0c0f69c5306bb0591df66947c11796530796 /src/compiler
parent578b9226a6a755f89d14be1fb0138fc02a6ca6b7 (diff)
downloadscala-322068fb8a1eb871280b19199505c30d8a25848b.tar.gz
scala-322068fb8a1eb871280b19199505c30d8a25848b.tar.bz2
scala-322068fb8a1eb871280b19199505c30d8a25848b.zip
1. Added a range method to Array.scala
2. Enabled extended implicit conversions 3. Implemented non-local returns
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala11
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/StdNames.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala88
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala7
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala23
9 files changed, 125 insertions, 13 deletions
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
/*<export>*/
/** - 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.
*/
/*</export>*/
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 {