From f7f15007686e355a2d8668bf890603be90810e29 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 19 May 2003 11:12:09 +0000 Subject: *** empty log message *** --- sources/scala/$colon$colon.scala | 2 +- sources/scala/Array.java | 5 - sources/scala/List.scala | 8 +- sources/scala/Predef.scala | 11 ++ sources/scala/Stream.scala | 74 +++++++----- sources/scala/runtime/RunTime.java | 22 ++-- sources/scalac/symtab/Symbol.java | 3 +- sources/scalac/symtab/Type.java | 146 +++++++++++++++++++++++- sources/scalac/transformer/LambdaLift.java | 7 +- sources/scalac/transformer/LambdaLiftPhase.java | 27 ++++- sources/scalac/typechecker/Analyzer.java | 76 ++++-------- 11 files changed, 267 insertions(+), 114 deletions(-) (limited to 'sources') diff --git a/sources/scala/$colon$colon.scala b/sources/scala/$colon$colon.scala index 16ad50f31a..cb08998724 100644 --- a/sources/scala/$colon$colon.scala +++ b/sources/scala/$colon$colon.scala @@ -3,7 +3,7 @@ package scala { /* A non empty list. * */ - final case class ::[b, c <: b](hd: b, tl: List[c]) extends List[b] { + final case class ::[b](hd: b, tl: List[b]) extends List[b] { def isEmpty: boolean = false; def head: b = hd; def tail: List[b] = tl; diff --git a/sources/scala/Array.java b/sources/scala/Array.java index 657210603e..b8b1ae1c30 100644 --- a/sources/scala/Array.java +++ b/sources/scala/Array.java @@ -15,11 +15,6 @@ package scala; */ public abstract class Array implements Function1 { - /** @meta constr (scala.Int); - */ - public Array(int n) { - } - public boolean[] asBooleanArray() { throw new ClassCastException(); } diff --git a/sources/scala/List.scala b/sources/scala/List.scala index 29a512a3b1..79d182bff2 100644 --- a/sources/scala/List.scala +++ b/sources/scala/List.scala @@ -35,7 +35,7 @@ trait List[+a] extends Seq[a] { * @return the list with x appended at the beginning. */ def ::[b >: a](x: b): List[b] = - new scala.::[b, a](x, this); + new scala.::(x, this); /** Returns a list resulting from the concatenation of the given * list prefix and this list. @@ -255,8 +255,8 @@ trait List[+a] extends Seq[a] { * @return the given array xs filled with this list. * @throws error if the list is empty. */ - def copyToArray[b >: a](xs: Array[b], start: Int): Array[b] = match { - case Nil => xs + def copyToArray[b >: a](xs: Array[b], start: Int): int = match { + case Nil => start case y :: ys => xs(start) = y; ys.copyToArray(xs, start + 1) } @@ -275,7 +275,7 @@ trait List[+a] extends Seq[a] { */ def mkString(start: String, sep: String, end: String): String = start + - (if (isEmpty) end + (if (isEmpty) end else if (tail.isEmpty) head.toString() + end else head.toString().concat(sep).concat(tail.mkString("", sep, end))); diff --git a/sources/scala/Predef.scala b/sources/scala/Predef.scala index 6ead2be1c1..6f69c4453e 100644 --- a/sources/scala/Predef.scala +++ b/sources/scala/Predef.scala @@ -15,6 +15,17 @@ object Predef { def List[a](x: a*): List[a] = x as List[a]; val List = scala.List; + def Array[a <: AnyRef](classname: String)(x: a*): Array[a] = { + System.out.println("array1"); + val xs0: Array[java.lang.Object] = runtime.RunTime.oarray(x.length, classname); + val xs: Array[a] = xs0 as Array[a]; + System.out.println("array2"); + val elems = x.elements; + var i = 0; + while (elems.hasNext) { xs(i) = elems.next; System.out.println(xs(i)) } + xs + } + def error(x: String): All = new java.lang.RuntimeException(x).throw; def try[a](def block: a): Except[a] = diff --git a/sources/scala/Stream.scala b/sources/scala/Stream.scala index 183940e009..7be860553b 100644 --- a/sources/scala/Stream.scala +++ b/sources/scala/Stream.scala @@ -1,17 +1,23 @@ package scala; -trait Stream[+a] { +trait Stream[+a] extends Seq[a] { def isEmpty: Boolean; def head: a; def tail: Stream[a]; - def length: Int = if (isEmpty) 0 else tail.length + 1; + def length: int = if (isEmpty) 0 else tail.length + 1; - def append(def rest: Stream[a]): Stream[a] = + def append[b >: a](def rest: Stream[b]): Stream[b] = if (isEmpty) rest else Stream.cons(head, tail.append(rest)); + def elements: Iterator[a] = new Iterator[a] { + var current = Stream.this; + def hasNext: boolean = !current.isEmpty; + def next: a = { val result = current.head; current = current.tail; result } + } + def init: Stream[a] = if (isEmpty) error("Stream.empty.init") else if (tail.isEmpty) Stream.empty @@ -22,6 +28,17 @@ trait Stream[+a] { else if (tail.isEmpty) head else tail.last; + def take(n: int): Stream[a] = + if (n == 0) Stream.empty + else Stream.cons(head, tail.take(n-1)); + + def drop(n: int): Stream[a] = + if (n == 0) this + else tail.drop(n-1); + + def apply(n: int) = drop(n).head; + def at(n: int) = drop(n).head; + def takeWhile(p: a => Boolean): Stream[a] = if (isEmpty || !p(head)) Stream.empty else Stream.cons(head, tail.takeWhile(p)); @@ -30,21 +47,11 @@ trait Stream[+a] { if (isEmpty || !p(head)) this else tail.dropWhile(p); - def take(n: Int): Stream[a] = - if (n == 0) Stream.empty - else Stream.cons(head, tail.take(n-1)); - - def drop(n: Int): Stream[a] = - if (n == 0) this - else tail.drop(n-1); - - def at(n: Int) = drop(n).head; - def map[b](f: a => b): Stream[b] = if (isEmpty) Stream.empty else Stream.cons(f(head), tail.map(f)); - def foreach(f: a => Unit): Unit = + def foreach(f: a => unit): unit = if (isEmpty) {} else { f(head); tail.foreach(f) } @@ -83,10 +90,8 @@ trait Stream[+a] { if (isEmpty) Stream.empty else f(head).append(tail.flatMap(f)); - def reverse: Stream[a] = { - def snoc(xs: Stream[a], x: a): Stream[a] = Stream.cons(x, xs); - foldLeft(Stream.empty: Stream[a])(snoc) - } + def reverse: Stream[a] = + foldLeft(Stream.empty: Stream[a])((xs, x) => Stream.cons(x, xs)); // The following method is not compilable without run-time type // information. It should therefore be left commented-out for @@ -97,22 +102,26 @@ trait Stream[+a] { // xs // } - def copyToArray[b >: a](xs: Array[b], start: Int): Int = { - xs(start) = head; - tail.copyToArray(xs, start + 1) - } + def copyToArray[b >: a](xs: Array[b], start: int): int = + if (isEmpty) start + else { xs(start) = head; tail.copyToArray(xs, start + 1) } def zip[b](that: Stream[b]): Stream[Tuple2[a, b]] = if (this.isEmpty || that.isEmpty) Stream.empty else Stream.cons(Tuple2(this.head, that.head), this.tail.zip(that.tail)); - def print: Unit = + def print: unit = if (isEmpty) System.out.println("Stream.empty") else { System.out.print(head as java.lang.Object); System.out.print(", "); tail.print } + + override def toString() = + "Stream(" + printElems(new StringBuffer(), "") + ")"; + + def printElems(buf: StringBuffer, prefix: String): StringBuffer; } object Stream { @@ -121,19 +130,22 @@ object Stream { def isEmpty = true; def head: All = error("head of empty stream"); def tail: Stream[All] = error("tail of empty stream"); - override def toString(): String = "Stream.empty"; + def printElems(buf: StringBuffer, prefix: String): StringBuffer = buf; } - def cons[b](hd: b, def tl: Stream[b]): Stream[b] = new Stream[b] { + def cons[a](hd: a, def tl: Stream[a]) = new Stream[a] { def isEmpty = false; def head = hd; - private var tlVal: Stream[b] = _; - private var tlDefined: Boolean = false; - def tail: Stream[b] = { + private var tlVal: Stream[a] = _; + private var tlDefined = false; + def tail: Stream[a] = { if (!tlDefined) { tlVal = tl; tlDefined = true; } tlVal } - override def toString(): String = "ConsStream(" + hd + ", ?)"; + def printElems(buf: StringBuffer, prefix: String): StringBuffer = { + val buf1 = buf.append(prefix).append(hd as java.lang.Object); + if (tlDefined) printElems(buf1, ", ") else buf1 append ", ?"; + } } def concat[a](xs: Seq[Stream[a]]): Stream[a] = concat(xs.elements); @@ -142,4 +154,8 @@ object Stream { if (xs.hasNext) xs.next append concat(xs) else empty; } + + def range(start: int, end: int): Stream[int] = + if (start >= end) empty + else cons(start, range(start + 1, end)); } diff --git a/sources/scala/runtime/RunTime.java b/sources/scala/runtime/RunTime.java index d9f02392d3..9766085243 100644 --- a/sources/scala/runtime/RunTime.java +++ b/sources/scala/runtime/RunTime.java @@ -351,7 +351,7 @@ public abstract class RunTime { } public static Array box(final boolean[] xs) { - return new Array(0) { + return new Array() { public boolean[] asBooleanArray() { return xs; } public Object apply(int i) { return box(xs[i]); } public void update(int i, Object x) { xs[i] = ((Boolean)x).asBoolean(); } @@ -361,7 +361,7 @@ public abstract class RunTime { } public static Array box(final byte[] xs) { - return new Array(0) { + return new Array() { public byte[] asByteArray() { return xs; } public Object apply(int i) { return box(xs[i]); } public void update(int i, Object x) { xs[i] = ((Byte)x).asByte(); } @@ -371,7 +371,7 @@ public abstract class RunTime { } public static Array box(final short[] xs) { - return new Array(0) { + return new Array() { public short[] asShortArray() { return xs; } public Object apply(int i) { return box(xs[i]); } public void update(int i, Object x) { xs[i] = ((Short)x).asShort(); } @@ -381,7 +381,7 @@ public abstract class RunTime { } public static Array box(final char[] xs) { - return new Array(0) { + return new Array() { public char[] asCharArray() { return xs; } public Object apply(int i) { return box(xs[i]); } public void update(int i, Object x) { xs[i] = ((Char)x).asChar(); } @@ -391,7 +391,7 @@ public abstract class RunTime { } public static Array box(final int[] xs) { - return new Array(0) { + return new Array() { public int[] asIntArray() { return xs; } public Object apply(int i) { return box(xs[i]); } public void update(int i, Object x) { xs[i] = ((Int)x).asInt(); } @@ -401,7 +401,7 @@ public abstract class RunTime { } public static Array box(final long[] xs) { - return new Array(0) { + return new Array() { public long[] asLongArray() { return xs; } public Object apply(int i) { return box(xs[i]); } public void update(int i, Object x) { xs[i] = ((Long)x).asLong(); } @@ -411,7 +411,7 @@ public abstract class RunTime { } public static Array box(final float[] xs) { - return new Array(0) { + return new Array() { public float[] asFloatArray() { return xs; } public Object apply(int i) { return box(xs[i]); } public void update(int i, Object x) { xs[i] = ((Float)x).asFloat(); } @@ -421,7 +421,7 @@ public abstract class RunTime { } public static Array box(final double[] xs) { - return new Array(0) { + return new Array() { public double[] asDoubleArray() { return xs; } public Object apply(int i) { return box(xs[i]); } public void update(int i, Object x) { xs[i] = ((Double)x).asDouble(); } @@ -431,7 +431,7 @@ public abstract class RunTime { } public static Array box(final Object[] xs) { - return new Array(0) { + return new Array() { public Object[] asObjectArray() { return xs; } public Object apply(int i) { return xs[i]; } public void update(int i, Object x) { xs[i] = x; } @@ -472,10 +472,10 @@ public abstract class RunTime { return new double[length]; } - public static Object oarray(int length, String classname) { + public static Object[] oarray(int length, String classname) { try { Class clasz = Class.forName(classname, false, loader); - return java.lang.reflect.Array.newInstance(clasz, length); + return (Object[]) java.lang.reflect.Array.newInstance(clasz, length); } catch (ClassNotFoundException exception) { throw new Error(exception.toString()); } diff --git a/sources/scalac/symtab/Symbol.java b/sources/scalac/symtab/Symbol.java index 3bb3f76e87..a259e0d62f 100644 --- a/sources/scalac/symtab/Symbol.java +++ b/sources/scalac/symtab/Symbol.java @@ -748,7 +748,8 @@ public abstract class Symbol implements Modifiers, Kinds { /** String representation of location. */ public String locationString() { - if (owner.kind == CLASS && !owner.isAnonymousClass()) + if (owner.kind == CLASS && !owner.isAnonymousClass() || + Global.instance.debug) return " in " + owner; else return ""; diff --git a/sources/scalac/symtab/Type.java b/sources/scalac/symtab/Type.java index 110a0f80bc..15c3d47649 100644 --- a/sources/scalac/symtab/Type.java +++ b/sources/scalac/symtab/Type.java @@ -141,6 +141,7 @@ public class Type implements Modifiers, Kinds, TypeTags { public Type widen() { return type().widen(); } + /** If this type is a singleton type whose type is another, the end of the chain, * otherwise the type itself. */ @@ -235,6 +236,25 @@ public class Type implements Modifiers, Kinds, TypeTags { return this; } + /** The lower approximation of this type (which must be a typeref) + */ + public Type loBound() { + switch (unalias()) { + case TypeRef(Type pre, Symbol sym, Type[] args): + Type lb = Global.instance.definitions.ANY_TYPE; + if (sym.kind == TYPE) { + lb = sym.loBound().asSeenFrom(pre, sym.owner()); + } + if (lb.isSameAs(Global.instance.definitions.ANY_TYPE) && + this.isSubType(Global.instance.definitions.ANYREF_TYPE)) { + lb = Global.instance.definitions.ANYREF_TYPE; + } + return lb; + default: + throw new ApplicationError(); + } + } + /** The thistype or singleton type corresponding to values of this type. */ public Type narrow() { @@ -1306,9 +1326,7 @@ public class Type implements Modifiers, Kinds, TypeTags { case TypeRef(_, Symbol sym, _): switch (that) { case TypeRef(Type pre1, Symbol sym1, _): - if (sym1.kind == TYPE && - this.isSubType( - sym1.loBound().asSeenFrom(pre1, sym1.owner()))) + if (sym1.kind == TYPE && this.isSubType(that.loBound())) return true; } if (sym.kind == ALIAS) @@ -1826,7 +1844,6 @@ public class Type implements Modifiers, Kinds, TypeTags { } /** Return the least upper bound of non-empty array of types `tps'. - * todo: treat types with refinements */ public static Type lub(Type[] tps) { //System.out.println("lub" + ArrayApply.toString(tps));//DEBUG @@ -1922,11 +1939,130 @@ public class Type implements Modifiers, Kinds, TypeTags { } private static Type glb(Type[] tps) { + // step one: eliminate redunandant types; return if one one is left tps = elimRedundant(tps, false); if (tps.length == 1) return tps[0]; - else return NoType; + + // step two: build arrays of all typerefs and all refinements + Type.List treftl = Type.List.EMPTY; + Type.List comptl = Type.List.EMPTY; + for (int i = 0; i < tps.length; i++) { + switch (tps[i]) { + case TypeRef(_, _, _): + treftl = new Type.List(tps[i], treftl); + break; + case CompoundType(Type[] parents, Scope members): + if (members.elems != Scope.Entry.NONE) + comptl = new Type.List(tps[i], comptl); + for (int j = 0; j < parents.length; j++) + treftl = new Type.List(parents[i], treftl); + break; + case ThisType(_): + case SingleType(_, _): + return Global.instance.definitions.ALL_TYPE; + } + } + + CompoundType glbType = compoundType(Type.EMPTY_ARRAY, new Scope()); + Type glbThisType = glbType.narrow(); + + // step 3: compute glb of all refinements. + Scope members = Scope.EMPTY; + if (comptl != List.EMPTY) { + Type[] comptypes = comptl.toArrayReverse(); + Scope[] refinements = new Scope[comptypes.length]; + for (int i = 0; i < comptypes.length; i++) + refinements[i] = comptypes[i].members(); + if (!setGlb(glbType.members, refinements, glbThisType)) { + // refinements don't have lower bound, so approximate + // by AllRef + glbType.members = Scope.EMPTY; + treftl = new Type.List( + Global.instance.definitions.ALLREF_TYPE, treftl); + } + } + + // eliminate redudant typerefs + Type[] treftypes = elimRedundant(treftl.toArrayReverse(), false); + if (treftypes.length != 1 || glbType.members.elems != Scope.Entry.NONE) { + // step 4: replace all abstract types by their lower bounds. + boolean hasAbstract = false; + for (int i = 0; i < treftypes.length; i++) { + if (treftypes[i].unalias().symbol().kind == TYPE) + hasAbstract = true; + } + if (hasAbstract) { + treftl = Type.List.EMPTY; + for (int i = 0; i < treftypes.length; i++) { + if (treftypes[i].unalias().symbol().kind == TYPE) + treftl = new Type.List(treftypes[i].loBound(), treftl); + else + treftl = new Type.List(treftypes[i], treftl); + } + treftypes = elimRedundant(treftl.toArrayReverse(), false); + } + } + + if (treftypes.length != 1) { + // step 5: if there are conflicting instantiations of same + // class, replace them by lower bound. + Type lb = NoType; + for (int i = 0; + i < treftypes.length && + lb != Global.instance.definitions.ALL_TYPE; + i++) { + for (int j = 0; j < i; j++) { + if (treftypes[j].symbol() == treftypes[i].symbol()) + lb = treftypes[i].loBound(); + } + } + if (lb != NoType) return lb; + } + + if (treftypes.length == 1 && glbType.members.elems == Scope.Entry.NONE) { + return treftypes[0]; + } else { + glbType.parts = treftypes; + return glbType; + } + } + + private static boolean setGlb(Scope result, Scope[] ss, Type glbThisType) { + for (int i = 0; i < ss.length; i++) + for (Scope.Entry e = ss[i].elems; e != Scope.Entry.NONE; e = e.next) + if (!addMember(result, e.sym, glbThisType)) return false; + return true; } + private static boolean addMember(Scope s, Symbol sym, Type glbThisType) { + Type syminfo = sym.info().substThis(sym.owner(), glbThisType); + Scope.Entry e = s.lookupEntry(sym.name); + if (e == Scope.Entry.NONE) { + Symbol sym1 = sym.cloneSymbol(); + sym1.setOwner(glbThisType.symbol()); + sym1.setInfo(syminfo); + s.enter(sym1); + return true; + } else { + Type einfo = e.sym.info(); + if (einfo.isSameAs(syminfo)) { + return true; + } else if (einfo.isSubType(syminfo) && sym.kind != ALIAS) { + return true; + } else if (syminfo.isSubType(einfo) && e.sym.kind != ALIAS) { + e.sym.setInfo(syminfo); + return true; + } else if (sym.kind == VAL && e.sym.kind == VAL || + sym.kind == TYPE && e.sym.kind == TYPE) { + e.sym.setInfo(glb(new Type[]{einfo, syminfo})); + return true; + } else { + return false; + } + } + } + + // Erasure -------------------------------------------------------------------------- public static Map erasureMap = new MapOnlyTypes() { diff --git a/sources/scalac/transformer/LambdaLift.java b/sources/scalac/transformer/LambdaLift.java index e6d2fc902b..fd89c3c260 100644 --- a/sources/scalac/transformer/LambdaLift.java +++ b/sources/scalac/transformer/LambdaLift.java @@ -310,7 +310,9 @@ public class LambdaLift extends OwnerTransformer public Tree transform(Tree tree) { //global.debugPrinter.print("lifting ").print(tree).println().end();//DEBUG + //System.out.print(tree.type + " --> ");//DEBUG tree.type = descr.transform(tree.type, currentOwner); + //System.out.println(tree.type);//DEBUG switch (tree) { case ClassDef(_, _, TypeDef[] tparams, ValDef[][] vparams, Tree tpe, Template impl): Symbol sym = tree.symbol(); @@ -403,7 +405,7 @@ public class LambdaLift extends OwnerTransformer return copy.Apply( tree, fn1, addFreeArgs(tree.pos, get(free.fvs, fsym), args1)); - case Ident(_): + case Ident(Name name): Symbol sym = tree.symbol(); if (sym.isLocal() && (sym.kind == TYPE || (sym.kind == VAL && !sym.isMethod()))) { @@ -411,6 +413,7 @@ public class LambdaLift extends OwnerTransformer } Tree tree1 = copy.Ident(tree, sym).setType( sym.typeAt(descr.nextPhase)); + if (name != sym.name) ((Ident)tree1).name = sym.name; if ((sym.flags & CAPTURED) != 0) return gen.Select(tree1, Names.elem); else return tree1; @@ -563,7 +566,7 @@ public class LambdaLift extends OwnerTransformer gen.mkRef( pos, global.definitions.getClass(Names.scala_COLONCOLON).constructor()), - new Tree[]{gen.mkType(pos, elemtpe), gen.mkType(pos, elemtpe)}), + new Tree[]{gen.mkType(pos, elemtpe)}), new Tree[]{hd, tl})); } } diff --git a/sources/scalac/transformer/LambdaLiftPhase.java b/sources/scalac/transformer/LambdaLiftPhase.java index 11141db9b2..df31745da5 100644 --- a/sources/scalac/transformer/LambdaLiftPhase.java +++ b/sources/scalac/transformer/LambdaLiftPhase.java @@ -13,6 +13,7 @@ import scalac.util.*; import scalac.parser.*; import scalac.symtab.*; import scalac.checkers.*; +import java.util.ArrayList; public class LambdaLiftPhase extends PhaseDescriptor implements Kinds, Modifiers { @@ -43,7 +44,7 @@ public class LambdaLiftPhase extends PhaseDescriptor implements Kinds, Modifiers public Type transformInfo(Symbol sym, Type tp) { if (global.debug) - global.log("transform info for " + sym + sym.locationString()); + global.log("transform info for " + sym + ":" + tp + sym.locationString()); Type tp1 = tp; if (sym != Symbol.NONE) { switch (tp) { @@ -53,7 +54,7 @@ public class LambdaLiftPhase extends PhaseDescriptor implements Kinds, Modifiers break; default: if (sym.kind == CLASS) - tp = transform(tp, sym); + tp1 = transform(tp, sym); else tp1 = transform(tp, sym.owner()); } @@ -70,6 +71,7 @@ public class LambdaLiftPhase extends PhaseDescriptor implements Kinds, Modifiers private class TransformTypeMap extends Type.MapOnlyTypes { Symbol owner; +// ArrayList/**/ excluded = new ArrayList(); Type.Map setOwner(Symbol owner) { this.owner = owner; return this; } public Type apply(Type tp) { @@ -95,9 +97,24 @@ public class LambdaLiftPhase extends PhaseDescriptor implements Kinds, Modifiers } return Type.TypeRef(pre, sym, targs1); } + } else if (sym.isLocal()) { + assert targs.length == 0; + return proxy(sym, owner).type(); } } break; +/* + case PolyType(Symbol[] tparams, _): + if (tparams.length != 0) { + int len = excluded.size(); + for (int i = 0; i < tparams.length; i++) + excluded.add(tparams[i]); + Type tp1 = map(tp); + for (int i = 0; i < tparams.length; i++) + excluded.remove(excluded.size() - 1); + return tp1; + } +*/ } return map(tp); } @@ -116,7 +133,7 @@ public class LambdaLiftPhase extends PhaseDescriptor implements Kinds, Modifiers */ Symbol proxy(Symbol fv, Symbol owner) { if (global.debug) - global.log("proxy " + fv + " in " + LambdaLift.asFunction(owner)); + global.log("proxy " + fv + " of " + fv.owner() + " in " + LambdaLift.asFunction(owner)); Symbol o = owner; while (o.kind != NONE) { if (global.debug) @@ -134,9 +151,9 @@ public class LambdaLiftPhase extends PhaseDescriptor implements Kinds, Modifiers } assert o.owner() != o; o = o.owner(); - } - throw new ApplicationError("proxy " + fv + " in " + owner); + return fv; + //throw new ApplicationError("proxy " + fv + " in " + owner); } /** The type scala.Ref[tp] diff --git a/sources/scalac/typechecker/Analyzer.java b/sources/scalac/typechecker/Analyzer.java index f4d2ed8fa0..2bec0ab167 100644 --- a/sources/scalac/typechecker/Analyzer.java +++ b/sources/scalac/typechecker/Analyzer.java @@ -380,39 +380,38 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { */ void validateBaseTypes(Symbol clazz) { validateBaseTypes(clazz, clazz.type().parents(), - new boolean[clazz.closure().length], 0); + new Type[clazz.closure().length], 0); } //where - void validateBaseTypes(Symbol clazz, Type[] tps, boolean[] seen, int start) { + void validateBaseTypes(Symbol clazz, Type[] tps, Type[] seen, int start) { for (int i = tps.length - 1; i >= start; i--) { validateBaseTypes(clazz, tps[i].unalias(), seen, i == 0 ? 0 : 1); } } - void validateBaseTypes(Symbol clazz, Type tp, boolean[] seen, int start) { + void validateBaseTypes(Symbol clazz, Type tp, Type[] seen, int start) { Symbol baseclazz = tp.symbol(); if (baseclazz.kind == CLASS) { int index = clazz.closurePos(baseclazz); if (index < 0) return; - if (seen[index]) { + if (seen[index] != null) { // check that only uniform classes are inherited several times. if (!clazz.isCompoundSym() && !baseclazz.isTrait()) { error(clazz.pos, "illegal inheritance;\n" + clazz + " inherits " + baseclazz + " twice"); } - // check no two different type instances of same class - // are inherited. - Type tp1 = clazz.closure()[index]; - if (!tp1.isSameAs(tp)) { + // if there are two different type instances of same class + // check that second is a subtype of first. + if (!seen[index].isSubType(tp)) { if (clazz.isCompoundSym()) error(clazz.pos, "illegal combination;\n " + "compound type " + " combines different type instances of " + - baseclazz + ":\n" + tp + " and " + tp1); + baseclazz + ":\n" + tp + " and " + seen[index]); else error(clazz.pos, "illegal inheritance;\n " + clazz + " inherits different type instances of " + - baseclazz + ":\n" + tp + " and " + tp1); + baseclazz + ":\n" + tp + " and " + seen[index]); } } // check that case classes do not inherit from case classes @@ -420,7 +419,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { error(clazz.pos, "illegal inheritance;\n " + "case " + clazz + " inherits from other case " + baseclazz); - seen[index] = true; + seen[index] = tp; validateBaseTypes(clazz, tp.parents(), seen, start); } } @@ -468,8 +467,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { checkNonCyclic( pos, pre.memberInfo(sym).subst(sym.typeParams(), args)); if (sym.kind == TYPE) - checkNonCyclic( - pos, sym.loBound().asSeenFrom(pre, sym.owner())); + checkNonCyclic(pos, tp.loBound()); sym.flags &= ~LOCKED; } break; @@ -755,7 +753,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { void validateVariance(Symbol base, Type all, Type[] tps, int variance, Symbol[] tparams) { for (int i = 0; i < tps.length; i++) - if (tps[i] != tparams[i].type()) +// if (tps[i] != tparams[i].type()) validateVariance(base, all, tps[i], variance * tparams[i].variance()); } @@ -825,12 +823,16 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { if (clazz.isLocalClass()) unit.mangler.setMangledName(clazz); enterSym(tree, clazz.constructor()); - if ((mods & (ABSTRACTCLASS | CASE)) == CASE) { - // enter case constructor method. - enterInScope( - new TermSymbol( - tree.pos, name.toTermName(), owner, mods & (ACCESSFLAGS | CASE)) - .setInfo(new LazyConstrMethodType(tree))); + if ((mods & CASE) != 0) { + if (vparams.length == 0) { + error(tree.pos, "case class needs () parameter section"); + } else if ((mods & ABSTRACTCLASS) == 0) { + // enter case constructor method. + enterInScope( + new TermSymbol( + tree.pos, name.toTermName(), owner, mods & (ACCESSFLAGS | CASE)) + .setInfo(new LazyConstrMethodType(tree))); + } } return enterSym(tree, clazz); @@ -1755,30 +1757,11 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { return tree; } else { Symbol sym = tree.symbol(); - // convert nullary case methods to types - // check that other idents or selects are stable. + // check that idents or selects are stable. switch (tree) { case Ident(_): - if (sym != null && isNullaryMethod(sym) && (sym.flags & CASE) != 0) - return transform( - make.Apply( - tree.pos, - copy.Ident(tree, sym.type().resultType().symbol()), - Tree.EMPTY_ARRAY), - mode, pt); - else - checkStable(tree); - break; - case Select(Tree qual, _): - if (sym != null && isNullaryMethod(sym) && (sym.flags & CASE) != 0) - return transform( - make.Apply( - tree.pos, - copy.Select(tree, sym.type().resultType().symbol(), qual), - Tree.EMPTY_ARRAY), - mode, pt); - else - checkStable(tree); + case Select(_, _): + checkStable(tree); } } } else if ((mode & EXPRmode) != 0) { @@ -1815,15 +1798,6 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { return tree; } //where - boolean isNullaryMethod(Symbol sym) { - switch (sym.type()) { - case PolyType(_, Type restpe): - return !(restpe instanceof Type.MethodType); - default: - return false; - } - } - Type seqConstructorType(Type paramtp, Type resulttp) { Symbol constr = resulttp.symbol().constructor(); Symbol param = new TermSymbol( -- cgit v1.2.3