summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sources/scala/tools/scalac/CompilerPhases.scala2
-rw-r--r--sources/scala/tools/scalac/transformer/UnCurry.scala393
-rw-r--r--sources/scala/tools/scalac/transformer/UnCurryPhase.scala101
-rw-r--r--sources/scalac/CompilerPhases.java4
4 files changed, 498 insertions, 2 deletions
diff --git a/sources/scala/tools/scalac/CompilerPhases.scala b/sources/scala/tools/scalac/CompilerPhases.scala
index 4f236a1f93..3990e425ac 100644
--- a/sources/scala/tools/scalac/CompilerPhases.scala
+++ b/sources/scala/tools/scalac/CompilerPhases.scala
@@ -22,6 +22,8 @@ class CompilerPhases extends scalac_CompilerPhases {
Class.forName("scala.tools.scalac.typechecker.AnalyzerPhase$class");
protected override def REFCHECK_PHASE(): Class =
Class.forName("scala.tools.scalac.typechecker.RefCheckPhase$class");
+ protected override def UNCURRY_PHASE(): Class =
+ Class.forName("scala.tools.scalac.transformer.UnCurryPhase$class");
protected override def TRANSMATCH_PHASE(): Class =
Class.forName("scala.tools.scalac.transformer.TransMatchPhase$class");
protected override def WHOLEPROG_PHASE(): Class =
diff --git a/sources/scala/tools/scalac/transformer/UnCurry.scala b/sources/scala/tools/scalac/transformer/UnCurry.scala
new file mode 100644
index 0000000000..d7f71f1c42
--- /dev/null
+++ b/sources/scala/tools/scalac/transformer/UnCurry.scala
@@ -0,0 +1,393 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id: UnCurry.scala
+
+import scalac.{CompilationUnit, ApplicationError};
+import scalac.{Global => scalac_Global};
+import scalac.util._;
+import scalac.ast._;
+import scalac.symtab._;
+import Tree._;
+import scalac.transformer.OwnerTransformer;
+
+package scala.tools.scalac.transformer {
+
+import scalac.util.NewArray;
+
+/** - uncurry all symbol and tree types (@see UnCurryPhase)
+ * - for every curried parameter list: (ps_1) ... (ps_n) ==> (ps_1, ..., ps_n)
+ * - for every curried application: f(args_1)...(args_n) ==> f(args_1, ..., args_n)
+ * - for every type application: f[Ts] ==> f[Ts]() unless followed by parameters
+ * - for every use of a parameterless function: f ==> f() and q.f ==> q.f()
+ * - for every def-parameter: def x: T ==> x: () => T
+ * - for every use of a def-parameter: x ==> x.apply()
+ * - for every argument to a def parameter `def x: T':
+ * if argument is not a reference to a def parameter:
+ * convert argument `e' to (expansion of) `() => e'
+ * - for every argument list that corresponds to a repeated parameter
+ * (a_1, ..., a_n) => (Sequence(a_1, ..., a_n))
+ * - for every argument list that is an escaped sequence
+ * (a_1:_*) => (a_1)
+ */
+class UnCurry(global: scalac_Global, descr: UnCurryPhase) extends OwnerTransformer(global) {
+
+ import Modifiers._;
+
+ private var unit: CompilationUnit = _;
+ private var inPattern: boolean = false;
+ private var inArray: boolean = false;
+
+ override def apply(unit: CompilationUnit): unit = {
+ this.unit = unit;
+ super.apply(unit);
+ }
+
+ /** (ps_1) ... (ps_n) => (ps_1, ..., ps_n)
+ */
+ private def uncurry(params: Array[Array[ValDef]]): Array[Array[ValDef]] = {
+ var n = 0;
+ { var i = 0; while (i < params.length) {
+ n = n + params(i).length;
+ i = i + 1
+ }}
+ val ps = new Array[ValDef](n);
+ var j = 0;
+ var i = 0; while (i < params.length) {
+ System.arraycopy(params(i), 0, ps, j, params(i).length);
+ j = j + params(i).length;
+ i = i + 1
+ }
+ NewArray.ValDefArray(ps)
+ }
+
+ /** tree of non-method type T ==> same tree with method type ()T
+ */
+ private def asMethod(tree: Tree): Tree = tree.getType() match {
+ case Type$MethodType(_, _) =>
+ tree
+ case _ =>
+ tree.setType(
+ new Type.MethodType(Symbol.EMPTY_ARRAY, tree.getType().widen()))
+ }
+
+ /** apply parameterless functions and def parameters
+ */
+ private def applyDef(tree: Tree): Tree = {
+ assert(tree.symbol() != null, tree);
+ tree.symbol().getType() match {
+ case Type$PolyType(tparams, restp) =>
+ if (tparams.length > 0 || (restp.isInstanceOf[Type$MethodType])) tree
+ else gen.Apply(asMethod(tree), Tree.EMPTY_ARRAY)
+ case _ =>
+ if (tree.symbol().isDefParameter()) {
+ tree.setType(global.definitions.FUNCTION_TYPE(
+ Type.EMPTY_ARRAY, tree.getType().widen()));
+ gen.Apply(gen.Select(tree, global.definitions.FUNCTION_APPLY(0)));
+ } else tree
+ }
+ }
+
+ /** - uncurry all symbol and tree types (@see UnCurryPhase)
+ * - for every curried parameter list: (ps_1) ... (ps_n) ==> (ps_1, ..., ps_n)
+ * - for every curried application: f(args_1)...(args_n) ==> f(args_1, ..., args_n)
+ * - for every type application: f[Ts] ==> f[Ts]() unless followed by parameters
+ * - for every use of a parameterless function: f ==> f() and q.f ==> q.f()
+ * - for every def-parameter: def x: T ==> x: () => T
+ * - for every use of a def-parameter: x ==> x.apply()
+ * - for every argument to a def parameter `def x: T':
+ * if argument is not a reference to a def parameter =>
+ * convert argument `e' to (expansion of) `() => e'
+ * - for every argument list that corresponds to a repeated parameter
+ * (a_1, ..., a_n) => (Sequence(a_1, ..., a_n))
+ */
+ override def transform(tree: Tree): Tree = {
+ var prevtype: Type = tree.getType();
+ if (prevtype != null) {
+ if (prevtype.isInstanceOf[Type$OverloadedType]) {
+ assert(tree.symbol() != null);
+ prevtype = tree.symbol().removeInheritedOverloaded(prevtype);
+ }
+ tree.setType(descr.uncurry(prevtype));
+ }
+ tree match {
+ case Tree$ClassDef(_, _, tparams, vparams, tpe, impl) =>
+ val clazz: Symbol = tree.symbol();
+ val it = clazz.members().iterator();
+ while (it.hasNext()) checkNoDoubleDef(clazz, it.next());
+ copy.ClassDef(
+ tree, clazz, tparams,
+ uncurry(transform(vparams, clazz)),
+ tpe,
+ transform(impl, clazz));
+
+ case Tree$DefDef(_, _, tparams, vparams, tpe, rhs) =>
+ val sym: Symbol = tree.symbol();
+ if (descr.isUnaccessedConstant(sym)) gen.mkUnitLit(tree.pos)
+ else {
+ val rhs1: Tree = transform(rhs, sym);
+ copy.DefDef(
+ tree, sym, tparams, uncurry(transform(vparams, sym)), tpe, rhs1)
+ }
+
+ case Tree$ValDef(_, _, tpe, rhs) =>
+ val sym: Symbol = tree.symbol();
+ if (descr.isUnaccessedConstant(sym)) gen.mkUnitLit(tree.pos)
+ else if (sym.isDefParameter()) {
+ val newtype: Type = global.definitions.FUNCTION_TYPE(Type.EMPTY_ARRAY, tpe.getType());
+ val tpe1: Tree = gen.mkType(tpe.pos, newtype);
+ copy.ValDef(tree, tpe1, rhs).setType(newtype)
+ } else
+ super.transform(tree)
+
+ case Tree$TypeApply(fn, args) =>
+ val tree1: Tree = asMethod(super.transform(tree));
+ gen.Apply(tree1, new Array[Tree](0))
+
+ case Tree$Apply(fn, args) =>
+ // f(x)(y) ==> f(x, y)
+ // argument to parameterless function e => ( => e)
+ val ftype: Type = fn.getType();
+ val fn1: Tree = transform(fn);
+ val myInArray: boolean = TreeInfo.methSymbol(fn1) == global.definitions.PREDEF_ARRAY();
+ inArray = myInArray;
+ val args1 = transformArgs(tree.pos, args, ftype);
+ if (myInArray)
+ fn1 match {
+ case Tree$Apply(TypeApply(Select(fn2, _), targs), _) =>
+ return gen.mkBlock(args1(0).pos, fn2, args1(0))
+ case _ =>
+ assert(false, "dead")
+ }
+ if (TreeInfo.methSymbol(fn1) == global.definitions.ANY_MATCH && !(args1(0).isInstanceOf[Tree.Visitor])) {
+ TreeInfo.methPart(fn1) match {
+ case Tree$Select(qual, name) =>
+ assert(name == Names._match);
+ gen.postfixApply(qual, args1(0), currentOwner)
+ case _ =>
+ throw new ApplicationError("illegal prefix for match: " + tree);
+ }
+ } else {
+ fn1 match {
+ case Tree$Apply(fn2, args2) =>
+ val newargs = new Array[Tree](args1.length + args2.length);
+ System.arraycopy(args2, 0, newargs, 0, args2.length);
+ System.arraycopy(args1, 0, newargs, args2.length, args1.length);
+ copy.Apply(tree, fn2, newargs);
+ case _ =>
+ copy.Apply(tree, fn1, args1);
+ }
+ }
+
+ case Tree$Select(_, _) =>
+ applyDef(super.transform(tree))
+
+ case Tree$Ident(name) =>
+ if (name == TypeNames.WILDCARD_STAR) {
+ unit.error(tree.pos, " argument does not correspond to `*'-parameter");
+ tree
+ } else if (tree.symbol() == global.definitions.PATTERN_WILDCARD) {
+ tree
+ } else {
+ applyDef(super.transform(tree))
+ }
+
+ case Tree$CaseDef(pat, guard, body) =>
+ inPattern = true;
+ val pat1: Tree = transform( pat );
+ inPattern = false;
+ val guard1: Tree = transform( guard );
+ val body1: Tree = transform( body );
+ copy.CaseDef(tree, pat1, guard1, body1)
+
+ case _ =>
+ super.transform(tree)
+ }
+ }
+
+ /** Transform arguments `args' to method with type `methtype'.
+ */
+ private def transformArgs(pos: int, args: Array[Tree], methtype: Type): Array[Tree] = {
+ methtype match {
+ case Type$MethodType(params, _) =>
+ val args0 =
+ if (params.length > 0 && (params(params.length-1).flags & REPEATED) != 0)
+ toSequence(pos, params, args)
+ else args;
+ var args1 = args0;
+ var i = 0; while (i < args0.length) {
+ val arg: Tree = args0(i);
+ val arg1: Tree = transformArg(arg, params(i));
+ if (arg1 != arg && args1 == args0) {
+ args1 = new Array[Tree](args0.length);
+ System.arraycopy(args0, 0, args1, 0, i);
+ }
+ args1(i) = arg1;
+ i = i + 1
+ }
+ args1;
+ case Type$PolyType(_, restp) =>
+ transformArgs(pos, args, restp)
+ case _ =>
+ if (args.length == 0) args; // could be arguments of nullary case pattern
+ else throw new ApplicationError(methtype);
+ }
+ }
+
+ /** converts `a_1,...,a_n' to Seq(a_1,...,a_n)
+ * if a_n is an escaped sequence x:_*, takes care of escaping
+ *
+ * precondition: params[params.length-1].flags & REPEATED != 0
+ */
+ private def toSequence(pos: int, params: Array[Symbol], args: Array[Tree]): Array[Tree] = {
+ val result = new Array[Tree](params.length);
+ System.arraycopy(args, 0, result, 0, params.length - 1);
+ assert(args.length != params.length
+ || !(args(params.length-1).isInstanceOf[Tree.Sequence])
+ || TreeInfo.isSequenceValued(args(params.length-1)));
+ if (args.length == params.length) {
+ args(params.length-1) match {
+ case Tree$Typed(arg, Ident(TypeNames.WILDCARD_STAR)) => // seq:_* escape
+ result(params.length-1) = arg;
+ return result;
+ case _ =>
+ }
+ }
+ var args1 = args;
+ if (params.length != 1) {
+ args1 = new Array[Tree](args.length - (params.length - 1));
+ System.arraycopy(args, params.length - 1, args1, 0, args1.length);
+ }
+ val theType: Type = params(params.length-1).getType();
+ result(params.length-1) =
+ if (inPattern)
+ make.Sequence(pos, args1).setType(theType)
+ else if (inArray)
+ gen.mkNewArray(pos, theType.typeArgs()(0), args1, currentOwner)
+ else
+ gen.mkNewList(pos, theType.typeArgs()(0), args1);
+ result
+ }
+
+ /** for every argument to a def parameter `def x: T':
+ * if argument is not a reference to a def parameter =>
+ * convert argument `e' to (expansion of) `() => e'
+ */
+ private def transformArg(arg: Tree, formal: Symbol): Tree =
+ if ((formal.flags & DEF) == 0)
+ transform(arg)
+ else {
+ val sym: Symbol = arg.symbol();
+ if (sym == null || (sym.flags & DEF) == 0)
+ transform(
+ gen.mkUnitFunction(arg, descr.uncurry(arg.getType().widen()), currentOwner))
+ else {
+ val arg1: Tree = transform(arg);
+ arg1 match {
+ case Tree$Apply(Select(qual, name), args1) =>
+ assert(name == Names.apply && args1.length == 0);
+ qual
+ case _ =>
+ System.err.println(arg1);//debug
+ throw new ApplicationError();
+ }
+ }
+ }
+
+// Double Definition Checking -----------------------------------------------
+
+ private def checkNoDoubleDef(clazz: Symbol, sym: Symbol): unit = {
+
+ def checkNoDoubleDef(sym1: Symbol, sym2: Symbol, type1: Type, type2: Type): unit = {
+
+ def conflictError(phase: String): unit = {
+ if (sym1.owner() == clazz && sym2.owner() == clazz)
+ unit.error(sym2.pos,
+ "Double declaration:\n" +
+ sym1 + ": " + type1 + " and\n" +
+ sym2 + ": " + type2 + " have same types after " + phase);
+ else if (sym1.owner() == clazz)
+ unit.error(sym1.pos,
+ "Accidental override:\n" +
+ sym1 + ": " + type1 + " has same type after " + phase + " as\n" +
+ sym2 + ": " + type2 + " which is inherited from " + sym2.owner());
+ else if (sym2.owner() == clazz)
+ unit.error(sym2.pos,
+ "Accidental override:\n" +
+ sym2 + ": " + type2 + " has same type after " + phase + " as\n" +
+ sym1 + ": " + type1 + " which is inherited from " + sym1.owner());
+ else
+ unit.error(clazz.pos,
+ "Inheritance conflict: inherited members\n" +
+ sym1 + ": " + type1 + sym1.locationString() + " and\n" +
+ sym2 + ": " + type2 + sym2.locationString() + " have same types after " + phase);
+ }
+
+ val newtype1: Type = descr.uncurry(type1);
+ val newtype2: Type = descr.uncurry(type2);
+ if (sym1.owner() != sym2.owner() &&
+ (newtype1.overrides(newtype2) || newtype2.overrides(newtype1)))
+ conflictError("uncurry")
+ else if (erasureConflict(newtype1, newtype2))
+ conflictError("erasure")
+ }
+
+ sym.getType() match {
+ case Type$OverloadedType(alts, alttypes) =>
+ var i = 0; while (i < alttypes.length) {
+ var j = i + 1; while (j < alttypes.length) {
+ checkNoDoubleDef(alts(i), alts(j), alttypes(i), alttypes(j));
+ j = j + 1
+ }
+ i = i + 1
+ }
+ case _ =>
+ }
+ }
+
+ private def erasureConflict(type1: Type, type2: Type): boolean = type1 match {
+ case Type$PolyType(_, restype1) =>
+ erasureConflict(restype1, type2)
+
+ case Type$MethodType(params1, restype1) =>
+ type2 match {
+ case Type$PolyType(_, restype2) =>
+ erasureConflict(type1, restype2)
+
+ case Type$MethodType(params2, restype2) =>
+ if (params1.length != params2.length) return false;
+ var i = 0; while (i < params1.length) {
+ if (!params1(i).nextInfo().erasure().isSameAs(
+ params2(i).nextInfo().erasure())) return false;
+ i = i + 1
+ }
+ restype1.erasure().isSameAs(restype2.erasure())
+
+ case _ =>
+ false
+ }
+
+ case _ =>
+ type2 match {
+ case Type$PolyType(_, _) | Type$MethodType(_, _) =>
+ erasureConflict(type2, type1);
+ case _ =>
+ true
+ }
+ }
+
+ override def transform(templ: Tree$Template, sym: Symbol): Tree$Template =
+ super.transform(templ, sym);
+
+ override def transform(tree: Tree, sym: Symbol): Tree =
+ super.transform(tree, sym);
+
+ override def transform(trees: Array[Array[Tree$ValDef]], sym: Symbol): Array[Array[Tree$ValDef]] =
+ super.transform(trees, sym);
+
+
+}
+}
diff --git a/sources/scala/tools/scalac/transformer/UnCurryPhase.scala b/sources/scala/tools/scalac/transformer/UnCurryPhase.scala
new file mode 100644
index 0000000000..1ff6a9f946
--- /dev/null
+++ b/sources/scala/tools/scalac/transformer/UnCurryPhase.scala
@@ -0,0 +1,101 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id: UnCurryPhase.scala
+
+import scalac.{Global => scalac_Global, _};
+import scalac.symtab._;
+import scalac.checkers._;
+
+package scala.tools.scalac.transformer {
+
+import scalac.util.NewArray;
+
+class UnCurryPhase(global: scalac_Global, descriptor: PhaseDescriptor) extends Phase(global, descriptor) {
+
+ import Modifiers._;
+
+ /** Applies this phase to the given compilation units. */
+ override def apply(units: Array[CompilationUnit]) = {
+ var i = 0; while (i < units.length) {
+ new UnCurry(global, this).apply(units(i));
+ i = i + 1
+ }
+ }
+
+ /** - return symbol's transformed type,
+ * - if symbol is a def parameter with transformed type T, return () => T
+ */
+ override def transformInfo(sym: Symbol, tp0: Type): Type = {
+ val tp1 = uncurry(tp0);
+ if (sym.isDefParameter()) global.definitions.FUNCTION_TYPE(Type.EMPTY_ARRAY, tp1);
+ else tp1
+ }
+
+ /** - (ps_1)...(ps_n)T ==> (ps_1,...,ps_n)T
+ */
+ def uncurry(tp: Type): Type = tp match {
+ case Type$MethodType(params, tp1) =>
+ uncurry(tp1) match {
+ case Type$MethodType(params1, tp2) =>
+ val newparams = new Array[Symbol](params.length + params1.length);
+ System.arraycopy(params, 0, newparams, 0, params.length);
+ System.arraycopy(params1, 0, newparams, params.length, params1.length);
+ new Type.MethodType(newparams, tp2);
+ case newtp1 =>
+ if (newtp1 == tp1) tp;
+ else new Type.MethodType(params, newtp1);
+ }
+ case Type$PolyType(tparams, tp1) =>
+ uncurry(tp1) match {
+ case newtp1 @ Type$MethodType(_, _) =>
+ if (newtp1 == tp1) tp
+ else new Type.PolyType(tparams, newtp1)
+ case newtp1 =>
+ val newtp2 = Type.MethodType(Symbol.EMPTY_ARRAY, newtp1);
+ if (tparams.length == 0) newtp2;
+ else Type.PolyType(tparams, newtp2)
+ }
+ case Type$OverloadedType(_, _) =>
+ new Type$Map() {
+ override def apply(t: Type) = uncurry(t)
+ }.map(tp);
+ case Type$ConstantType(base, _) =>
+ base
+ case Type$CompoundType(parents, scope) =>
+ val symbol = tp.symbol();
+ if (!symbol.isClass() || symbol.isCompoundSym()) tp
+ else {
+ val clone = new Scope();
+ val it = scope.iterator(true);
+ while (it.hasNext()) {
+ val member = it.next();
+ if (!isUnaccessedConstant(member) &&
+ (!member.isCaseFactory() || member.isModule()))
+ clone.enterOrOverload(member);
+ }
+ Type.compoundType(parents, clone, symbol)
+ }
+ case _ =>
+ tp
+ }
+
+ def isUnaccessedConstant(symbol: Symbol): boolean =
+ symbol.isTerm() &&
+ (symbol.flags & ACCESSED) == 0 &&
+ (symbol.getType() match {
+ case Type$PolyType(params, Type$ConstantType(_, _)) =>
+ params.length == 0
+ case Type$ConstantType(_, _) =>
+ true
+ case _ =>
+ false
+ });
+
+ override def postCheckers(global: scalac_Global): Array[Checker] =
+ NewArray.Checker(new CheckSymbols(global), new CheckTypes(global));
+}
+}
diff --git a/sources/scalac/CompilerPhases.java b/sources/scalac/CompilerPhases.java
index c65eb93957..cc99184363 100644
--- a/sources/scalac/CompilerPhases.java
+++ b/sources/scalac/CompilerPhases.java
@@ -55,8 +55,8 @@ public abstract class CompilerPhases {
protected abstract Class PARSER_PHASE();
protected abstract Class ANALYZER_PHASE();
protected abstract Class REFCHECK_PHASE();
- protected Class UNCURRY_PHASE() { return scalac.transformer.UnCurryPhase.class; }
- protected abstract Class TRANSMATCH_PHASE() ;
+ protected abstract Class UNCURRY_PHASE();
+ protected abstract Class TRANSMATCH_PHASE();
protected Class LAMBDALIFT_PHASE() { return scalac.transformer.LambdaLiftPhase.class; }
protected Class EXPLICITOUTER_PHASE() { return scalac.transformer.ExplicitOuterClassesPhase.class; }
protected Class ADDACCESSORS_PHASE() { return scalac.transformer.AddAccessorsPhase.class; }