diff options
Diffstat (limited to 'src')
606 files changed, 12335 insertions, 17841 deletions
diff --git a/src/actors/scala/actors/Future.scala b/src/actors/scala/actors/Future.scala index 3037f82141..1abd7b160e 100644 --- a/src/actors/scala/actors/Future.scala +++ b/src/actors/scala/actors/Future.scala @@ -174,7 +174,7 @@ object Futures { * or timeout + `System.currentTimeMillis()` is negative. */ def awaitAll(timeout: Long, fts: Future[Any]*): List[Option[Any]] = { - var resultsMap: scala.collection.mutable.Map[Int, Option[Any]] = new scala.collection.mutable.HashMap[Int, Option[Any]] + val resultsMap: scala.collection.mutable.Map[Int, Option[Any]] = new scala.collection.mutable.HashMap[Int, Option[Any]] var cnt = 0 val mappedFts = fts.map(ft => diff --git a/src/asm/scala/tools/asm/AnnotationVisitor.java b/src/asm/scala/tools/asm/AnnotationVisitor.java index b96e730a73..c806ca71e8 100644 --- a/src/asm/scala/tools/asm/AnnotationVisitor.java +++ b/src/asm/scala/tools/asm/AnnotationVisitor.java @@ -54,8 +54,9 @@ public abstract class AnnotationVisitor { /** * Constructs a new {@link AnnotationVisitor}. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. */ public AnnotationVisitor(final int api) { this(api, null); @@ -64,15 +65,17 @@ public abstract class AnnotationVisitor { /** * Constructs a new {@link AnnotationVisitor}. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. - * @param av the annotation visitor to which this visitor must delegate - * method calls. May be null. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param av + * the annotation visitor to which this visitor must delegate + * method calls. May be null. */ public AnnotationVisitor(final int api, final AnnotationVisitor av) { - /*if (api != Opcodes.ASM4) { + if (api != Opcodes.ASM4) { throw new IllegalArgumentException(); - }*/ + } this.api = api; this.av = av; } @@ -80,14 +83,17 @@ public abstract class AnnotationVisitor { /** * Visits a primitive value of the annotation. * - * @param name the value name. - * @param value the actual value, whose type must be {@link Byte}, - * {@link Boolean}, {@link Character}, {@link Short}, {@link Integer} - * , {@link Long}, {@link Float}, {@link Double}, {@link String} or - * {@link Type} or OBJECT or ARRAY sort. This value can also be an - * array of byte, boolean, short, char, int, long, float or double - * values (this is equivalent to using {@link #visitArray visitArray} - * and visiting each array element in turn, but is more convenient). + * @param name + * the value name. + * @param value + * the actual value, whose type must be {@link Byte}, + * {@link Boolean}, {@link Character}, {@link Short}, + * {@link Integer} , {@link Long}, {@link Float}, {@link Double}, + * {@link String} or {@link Type} or OBJECT or ARRAY sort. This + * value can also be an array of byte, boolean, short, char, int, + * long, float or double values (this is equivalent to using + * {@link #visitArray visitArray} and visiting each array element + * in turn, but is more convenient). */ public void visit(String name, Object value) { if (av != null) { @@ -98,9 +104,12 @@ public abstract class AnnotationVisitor { /** * Visits an enumeration value of the annotation. * - * @param name the value name. - * @param desc the class descriptor of the enumeration class. - * @param value the actual enumeration value. + * @param name + * the value name. + * @param desc + * the class descriptor of the enumeration class. + * @param value + * the actual enumeration value. */ public void visitEnum(String name, String desc, String value) { if (av != null) { @@ -111,12 +120,14 @@ public abstract class AnnotationVisitor { /** * Visits a nested annotation value of the annotation. * - * @param name the value name. - * @param desc the class descriptor of the nested annotation class. + * @param name + * the value name. + * @param desc + * the class descriptor of the nested annotation class. * @return a visitor to visit the actual nested annotation value, or - * <tt>null</tt> if this visitor is not interested in visiting - * this nested annotation. <i>The nested annotation value must be - * fully visited before calling other methods on this annotation + * <tt>null</tt> if this visitor is not interested in visiting this + * nested annotation. <i>The nested annotation value must be fully + * visited before calling other methods on this annotation * visitor</i>. */ public AnnotationVisitor visitAnnotation(String name, String desc) { @@ -132,10 +143,11 @@ public abstract class AnnotationVisitor { * can be passed as value to {@link #visit visit}. This is what * {@link ClassReader} does. * - * @param name the value name. + * @param name + * the value name. * @return a visitor to visit the actual array value elements, or - * <tt>null</tt> if this visitor is not interested in visiting - * these values. The 'name' parameters passed to the methods of this + * <tt>null</tt> if this visitor is not interested in visiting these + * values. The 'name' parameters passed to the methods of this * visitor are ignored. <i>All the array values must be visited * before calling other methods on this annotation visitor</i>. */ diff --git a/src/asm/scala/tools/asm/AnnotationWriter.java b/src/asm/scala/tools/asm/AnnotationWriter.java index e530780249..8eb5b2ef48 100644 --- a/src/asm/scala/tools/asm/AnnotationWriter.java +++ b/src/asm/scala/tools/asm/AnnotationWriter.java @@ -90,20 +90,20 @@ final class AnnotationWriter extends AnnotationVisitor { /** * Constructs a new {@link AnnotationWriter}. * - * @param cw the class writer to which this annotation must be added. - * @param named <tt>true<tt> if values are named, <tt>false</tt> otherwise. - * @param bv where the annotation values must be stored. - * @param parent where the number of annotation values must be stored. - * @param offset where in <tt>parent</tt> the number of annotation values must - * be stored. + * @param cw + * the class writer to which this annotation must be added. + * @param named + * <tt>true<tt> if values are named, <tt>false</tt> otherwise. + * @param bv + * where the annotation values must be stored. + * @param parent + * where the number of annotation values must be stored. + * @param offset + * where in <tt>parent</tt> the number of annotation values must + * be stored. */ - AnnotationWriter( - final ClassWriter cw, - final boolean named, - final ByteVector bv, - final ByteVector parent, - final int offset) - { + AnnotationWriter(final ClassWriter cw, final boolean named, + final ByteVector bv, final ByteVector parent, final int offset) { super(Opcodes.ASM4); this.cw = cw; this.named = named; @@ -190,11 +190,8 @@ final class AnnotationWriter extends AnnotationVisitor { } @Override - public void visitEnum( - final String name, - final String desc, - final String value) - { + public void visitEnum(final String name, final String desc, + final String value) { ++size; if (named) { bv.putShort(cw.newUTF8(name)); @@ -203,10 +200,8 @@ final class AnnotationWriter extends AnnotationVisitor { } @Override - public AnnotationVisitor visitAnnotation( - final String name, - final String desc) - { + public AnnotationVisitor visitAnnotation(final String name, + final String desc) { ++size; if (named) { bv.putShort(cw.newUTF8(name)); @@ -259,7 +254,8 @@ final class AnnotationWriter extends AnnotationVisitor { * Puts the annotations of this annotation writer list into the given byte * vector. * - * @param out where the annotations must be put. + * @param out + * where the annotations must be put. */ void put(final ByteVector out) { int n = 0; @@ -286,15 +282,15 @@ final class AnnotationWriter extends AnnotationVisitor { /** * Puts the given annotation lists into the given byte vector. * - * @param panns an array of annotation writer lists. - * @param off index of the first annotation to be written. - * @param out where the annotations must be put. + * @param panns + * an array of annotation writer lists. + * @param off + * index of the first annotation to be written. + * @param out + * where the annotations must be put. */ - static void put( - final AnnotationWriter[] panns, - final int off, - final ByteVector out) - { + static void put(final AnnotationWriter[] panns, final int off, + final ByteVector out) { int size = 1 + 2 * (panns.length - off); for (int i = off; i < panns.length; ++i) { size += panns[i] == null ? 0 : panns[i].getSize(); diff --git a/src/asm/scala/tools/asm/Attribute.java b/src/asm/scala/tools/asm/Attribute.java index 408f21ce1e..ac40a758a2 100644 --- a/src/asm/scala/tools/asm/Attribute.java +++ b/src/asm/scala/tools/asm/Attribute.java @@ -55,7 +55,8 @@ public class Attribute { /** * Constructs a new empty attribute. * - * @param type the type of the attribute. + * @param type + * the type of the attribute. */ protected Attribute(final String type) { this.type = type; @@ -91,39 +92,39 @@ public class Attribute { } /** - * Reads a {@link #type type} attribute. This method must return a <i>new</i> - * {@link Attribute} object, of type {@link #type type}, corresponding to - * the <tt>len</tt> bytes starting at the given offset, in the given class - * reader. + * Reads a {@link #type type} attribute. This method must return a + * <i>new</i> {@link Attribute} object, of type {@link #type type}, + * corresponding to the <tt>len</tt> bytes starting at the given offset, in + * the given class reader. * - * @param cr the class that contains the attribute to be read. - * @param off index of the first byte of the attribute's content in {@link - * ClassReader#b cr.b}. The 6 attribute header bytes, containing the - * type and the length of the attribute, are not taken into account - * here. - * @param len the length of the attribute's content. - * @param buf buffer to be used to call - * {@link ClassReader#readUTF8 readUTF8}, - * {@link ClassReader#readClass(int,char[]) readClass} or - * {@link ClassReader#readConst readConst}. - * @param codeOff index of the first byte of code's attribute content in - * {@link ClassReader#b cr.b}, or -1 if the attribute to be read is - * not a code attribute. The 6 attribute header bytes, containing the - * type and the length of the attribute, are not taken into account - * here. - * @param labels the labels of the method's code, or <tt>null</tt> if the - * attribute to be read is not a code attribute. + * @param cr + * the class that contains the attribute to be read. + * @param off + * index of the first byte of the attribute's content in + * {@link ClassReader#b cr.b}. The 6 attribute header bytes, + * containing the type and the length of the attribute, are not + * taken into account here. + * @param len + * the length of the attribute's content. + * @param buf + * buffer to be used to call {@link ClassReader#readUTF8 + * readUTF8}, {@link ClassReader#readClass(int,char[]) readClass} + * or {@link ClassReader#readConst readConst}. + * @param codeOff + * index of the first byte of code's attribute content in + * {@link ClassReader#b cr.b}, or -1 if the attribute to be read + * is not a code attribute. The 6 attribute header bytes, + * containing the type and the length of the attribute, are not + * taken into account here. + * @param labels + * the labels of the method's code, or <tt>null</tt> if the + * attribute to be read is not a code attribute. * @return a <i>new</i> {@link Attribute} object corresponding to the given * bytes. */ - protected Attribute read( - final ClassReader cr, - final int off, - final int len, - final char[] buf, - final int codeOff, - final Label[] labels) - { + protected Attribute read(final ClassReader cr, final int off, + final int len, final char[] buf, final int codeOff, + final Label[] labels) { Attribute attr = new Attribute(type); attr.value = new byte[len]; System.arraycopy(cr.b, off, attr.value, 0, len); @@ -133,30 +134,30 @@ public class Attribute { /** * Returns the byte array form of this attribute. * - * @param cw the class to which this attribute must be added. This parameter - * can be used to add to the constant pool of this class the items - * that corresponds to this attribute. - * @param code the bytecode of the method corresponding to this code - * attribute, or <tt>null</tt> if this attribute is not a code - * attributes. - * @param len the length of the bytecode of the method corresponding to this - * code attribute, or <tt>null</tt> if this attribute is not a code - * attribute. - * @param maxStack the maximum stack size of the method corresponding to - * this code attribute, or -1 if this attribute is not a code - * attribute. - * @param maxLocals the maximum number of local variables of the method - * corresponding to this code attribute, or -1 if this attribute is - * not a code attribute. + * @param cw + * the class to which this attribute must be added. This + * parameter can be used to add to the constant pool of this + * class the items that corresponds to this attribute. + * @param code + * the bytecode of the method corresponding to this code + * attribute, or <tt>null</tt> if this attribute is not a code + * attributes. + * @param len + * the length of the bytecode of the method corresponding to this + * code attribute, or <tt>null</tt> if this attribute is not a + * code attribute. + * @param maxStack + * the maximum stack size of the method corresponding to this + * code attribute, or -1 if this attribute is not a code + * attribute. + * @param maxLocals + * the maximum number of local variables of the method + * corresponding to this code attribute, or -1 if this attribute + * is not a code attribute. * @return the byte array form of this attribute. */ - protected ByteVector write( - final ClassWriter cw, - final byte[] code, - final int len, - final int maxStack, - final int maxLocals) - { + protected ByteVector write(final ClassWriter cw, final byte[] code, + final int len, final int maxStack, final int maxLocals) { ByteVector v = new ByteVector(); v.data = value; v.length = value.length; @@ -181,30 +182,30 @@ public class Attribute { /** * Returns the size of all the attributes in this attribute list. * - * @param cw the class writer to be used to convert the attributes into byte - * arrays, with the {@link #write write} method. - * @param code the bytecode of the method corresponding to these code - * attributes, or <tt>null</tt> if these attributes are not code - * attributes. - * @param len the length of the bytecode of the method corresponding to - * these code attributes, or <tt>null</tt> if these attributes are - * not code attributes. - * @param maxStack the maximum stack size of the method corresponding to - * these code attributes, or -1 if these attributes are not code - * attributes. - * @param maxLocals the maximum number of local variables of the method - * corresponding to these code attributes, or -1 if these attributes - * are not code attributes. + * @param cw + * the class writer to be used to convert the attributes into + * byte arrays, with the {@link #write write} method. + * @param code + * the bytecode of the method corresponding to these code + * attributes, or <tt>null</tt> if these attributes are not code + * attributes. + * @param len + * the length of the bytecode of the method corresponding to + * these code attributes, or <tt>null</tt> if these attributes + * are not code attributes. + * @param maxStack + * the maximum stack size of the method corresponding to these + * code attributes, or -1 if these attributes are not code + * attributes. + * @param maxLocals + * the maximum number of local variables of the method + * corresponding to these code attributes, or -1 if these + * attributes are not code attributes. * @return the size of all the attributes in this attribute list. This size * includes the size of the attribute headers. */ - final int getSize( - final ClassWriter cw, - final byte[] code, - final int len, - final int maxStack, - final int maxLocals) - { + final int getSize(final ClassWriter cw, final byte[] code, final int len, + final int maxStack, final int maxLocals) { Attribute attr = this; int size = 0; while (attr != null) { @@ -219,30 +220,30 @@ public class Attribute { * Writes all the attributes of this attribute list in the given byte * vector. * - * @param cw the class writer to be used to convert the attributes into byte - * arrays, with the {@link #write write} method. - * @param code the bytecode of the method corresponding to these code - * attributes, or <tt>null</tt> if these attributes are not code - * attributes. - * @param len the length of the bytecode of the method corresponding to - * these code attributes, or <tt>null</tt> if these attributes are - * not code attributes. - * @param maxStack the maximum stack size of the method corresponding to - * these code attributes, or -1 if these attributes are not code - * attributes. - * @param maxLocals the maximum number of local variables of the method - * corresponding to these code attributes, or -1 if these attributes - * are not code attributes. - * @param out where the attributes must be written. + * @param cw + * the class writer to be used to convert the attributes into + * byte arrays, with the {@link #write write} method. + * @param code + * the bytecode of the method corresponding to these code + * attributes, or <tt>null</tt> if these attributes are not code + * attributes. + * @param len + * the length of the bytecode of the method corresponding to + * these code attributes, or <tt>null</tt> if these attributes + * are not code attributes. + * @param maxStack + * the maximum stack size of the method corresponding to these + * code attributes, or -1 if these attributes are not code + * attributes. + * @param maxLocals + * the maximum number of local variables of the method + * corresponding to these code attributes, or -1 if these + * attributes are not code attributes. + * @param out + * where the attributes must be written. */ - final void put( - final ClassWriter cw, - final byte[] code, - final int len, - final int maxStack, - final int maxLocals, - final ByteVector out) - { + final void put(final ClassWriter cw, final byte[] code, final int len, + final int maxStack, final int maxLocals, final ByteVector out) { Attribute attr = this; while (attr != null) { ByteVector b = attr.write(cw, code, len, maxStack, maxLocals); diff --git a/src/asm/scala/tools/asm/ByteVector.java b/src/asm/scala/tools/asm/ByteVector.java index 5081f0184b..2bc63eb384 100644 --- a/src/asm/scala/tools/asm/ByteVector.java +++ b/src/asm/scala/tools/asm/ByteVector.java @@ -59,7 +59,8 @@ public class ByteVector { * Constructs a new {@link ByteVector ByteVector} with the given initial * size. * - * @param initialSize the initial size of the byte vector to be constructed. + * @param initialSize + * the initial size of the byte vector to be constructed. */ public ByteVector(final int initialSize) { data = new byte[initialSize]; @@ -69,7 +70,8 @@ public class ByteVector { * Puts a byte into this byte vector. The byte vector is automatically * enlarged if necessary. * - * @param b a byte. + * @param b + * a byte. * @return this byte vector. */ public ByteVector putByte(final int b) { @@ -86,8 +88,10 @@ public class ByteVector { * Puts two bytes into this byte vector. The byte vector is automatically * enlarged if necessary. * - * @param b1 a byte. - * @param b2 another byte. + * @param b1 + * a byte. + * @param b2 + * another byte. * @return this byte vector. */ ByteVector put11(final int b1, final int b2) { @@ -106,7 +110,8 @@ public class ByteVector { * Puts a short into this byte vector. The byte vector is automatically * enlarged if necessary. * - * @param s a short. + * @param s + * a short. * @return this byte vector. */ public ByteVector putShort(final int s) { @@ -125,8 +130,10 @@ public class ByteVector { * Puts a byte and a short into this byte vector. The byte vector is * automatically enlarged if necessary. * - * @param b a byte. - * @param s a short. + * @param b + * a byte. + * @param s + * a short. * @return this byte vector. */ ByteVector put12(final int b, final int s) { @@ -146,7 +153,8 @@ public class ByteVector { * Puts an int into this byte vector. The byte vector is automatically * enlarged if necessary. * - * @param i an int. + * @param i + * an int. * @return this byte vector. */ public ByteVector putInt(final int i) { @@ -167,7 +175,8 @@ public class ByteVector { * Puts a long into this byte vector. The byte vector is automatically * enlarged if necessary. * - * @param l a long. + * @param l + * a long. * @return this byte vector. */ public ByteVector putLong(final long l) { @@ -194,7 +203,8 @@ public class ByteVector { * Puts an UTF8 string into this byte vector. The byte vector is * automatically enlarged if necessary. * - * @param s a String. + * @param s + * a String. * @return this byte vector. */ public ByteVector putUTF8(final String s) { @@ -259,14 +269,16 @@ public class ByteVector { * Puts an array of bytes into this byte vector. The byte vector is * automatically enlarged if necessary. * - * @param b an array of bytes. May be <tt>null</tt> to put <tt>len</tt> - * null bytes into this byte vector. - * @param off index of the fist byte of b that must be copied. - * @param len number of bytes of b that must be copied. + * @param b + * an array of bytes. May be <tt>null</tt> to put <tt>len</tt> + * null bytes into this byte vector. + * @param off + * index of the fist byte of b that must be copied. + * @param len + * number of bytes of b that must be copied. * @return this byte vector. */ - public ByteVector putByteArray(final byte[] b, final int off, final int len) - { + public ByteVector putByteArray(final byte[] b, final int off, final int len) { if (length + len > data.length) { enlarge(len); } @@ -280,8 +292,9 @@ public class ByteVector { /** * Enlarge this byte vector so that it can receive n more bytes. * - * @param size number of additional bytes that this byte vector should be - * able to receive. + * @param size + * number of additional bytes that this byte vector should be + * able to receive. */ private void enlarge(final int size) { int length1 = 2 * data.length; diff --git a/src/asm/scala/tools/asm/ClassReader.java b/src/asm/scala/tools/asm/ClassReader.java index f3287d41ae..cc655c1b62 100644 --- a/src/asm/scala/tools/asm/ClassReader.java +++ b/src/asm/scala/tools/asm/ClassReader.java @@ -112,9 +112,8 @@ public class ClassReader { public final byte[] b; /** - * The start index of each constant pool item in {@link #b b}, plus one. - * The one byte offset skips the constant pool item tag that indicates its - * type. + * The start index of each constant pool item in {@link #b b}, plus one. The + * one byte offset skips the constant pool item tag that indicates its type. */ private final int[] items; @@ -147,7 +146,8 @@ public class ClassReader { /** * Constructs a new {@link ClassReader} object. * - * @param b the bytecode of the class to be read. + * @param b + * the bytecode of the class to be read. */ public ClassReader(final byte[] b) { this(b, 0, b.length); @@ -156,14 +156,17 @@ public class ClassReader { /** * Constructs a new {@link ClassReader} object. * - * @param b the bytecode of the class to be read. - * @param off the start offset of the class data. - * @param len the length of the class data. + * @param b + * the bytecode of the class to be read. + * @param off + * the start offset of the class data. + * @param len + * the length of the class data. */ public ClassReader(final byte[] b, final int off, final int len) { this.b = b; // checks the class version - if (readShort(6) > Opcodes.V1_7) { + if (readShort(off + 6) > Opcodes.V1_7) { throw new IllegalArgumentException(); } // parses the constant pool @@ -176,35 +179,35 @@ public class ClassReader { items[i] = index + 1; int size; switch (b[index]) { - case ClassWriter.FIELD: - case ClassWriter.METH: - case ClassWriter.IMETH: - case ClassWriter.INT: - case ClassWriter.FLOAT: - case ClassWriter.NAME_TYPE: - case ClassWriter.INDY: - size = 5; - break; - case ClassWriter.LONG: - case ClassWriter.DOUBLE: - size = 9; - ++i; - break; - case ClassWriter.UTF8: - size = 3 + readUnsignedShort(index + 1); - if (size > max) { - max = size; - } - break; - case ClassWriter.HANDLE: - size = 4; - break; - // case ClassWriter.CLASS: - // case ClassWriter.STR: - // case ClassWriter.MTYPE - default: - size = 3; - break; + case ClassWriter.FIELD: + case ClassWriter.METH: + case ClassWriter.IMETH: + case ClassWriter.INT: + case ClassWriter.FLOAT: + case ClassWriter.NAME_TYPE: + case ClassWriter.INDY: + size = 5; + break; + case ClassWriter.LONG: + case ClassWriter.DOUBLE: + size = 9; + ++i; + break; + case ClassWriter.UTF8: + size = 3 + readUnsignedShort(index + 1); + if (size > max) { + max = size; + } + break; + case ClassWriter.HANDLE: + size = 4; + break; + // case ClassWriter.CLASS: + // case ClassWriter.STR: + // case ClassWriter.MTYPE + default: + size = 3; + break; } index += size; } @@ -249,8 +252,7 @@ public class ClassReader { * @see ClassVisitor#visit(int, int, String, String, String, String[]) */ public String getSuperName() { - int n = items[readUnsignedShort(header + 4)]; - return n == 0 ? null : readUTF8(n, new char[maxStringLength]); + return readClass(header + 4, new char[maxStringLength]); } /** @@ -280,7 +282,8 @@ public class ClassReader { * Copies the constant pool data into the given {@link ClassWriter}. Should * be called before the {@link #accept(ClassVisitor,int)} method. * - * @param classWriter the {@link ClassWriter} to copy constant pool into. + * @param classWriter + * the {@link ClassWriter} to copy constant pool into. */ void copyPool(final ClassWriter classWriter) { char[] buf = new char[maxStringLength]; @@ -292,82 +295,63 @@ public class ClassReader { Item item = new Item(i); int nameType; switch (tag) { - case ClassWriter.FIELD: - case ClassWriter.METH: - case ClassWriter.IMETH: - nameType = items[readUnsignedShort(index + 2)]; - item.set(tag, - readClass(index, buf), - readUTF8(nameType, buf), - readUTF8(nameType + 2, buf)); - break; - - case ClassWriter.INT: - item.set(readInt(index)); - break; - - case ClassWriter.FLOAT: - item.set(Float.intBitsToFloat(readInt(index))); - break; - - case ClassWriter.NAME_TYPE: - item.set(tag, - readUTF8(index, buf), - readUTF8(index + 2, buf), - null); - break; - - case ClassWriter.LONG: - item.set(readLong(index)); - ++i; - break; - - case ClassWriter.DOUBLE: - item.set(Double.longBitsToDouble(readLong(index))); - ++i; - break; - - case ClassWriter.UTF8: { - String s = strings[i]; - if (s == null) { - index = items[i]; - s = strings[i] = readUTF(index + 2, - readUnsignedShort(index), - buf); - } - item.set(tag, s, null, null); + case ClassWriter.FIELD: + case ClassWriter.METH: + case ClassWriter.IMETH: + nameType = items[readUnsignedShort(index + 2)]; + item.set(tag, readClass(index, buf), readUTF8(nameType, buf), + readUTF8(nameType + 2, buf)); + break; + case ClassWriter.INT: + item.set(readInt(index)); + break; + case ClassWriter.FLOAT: + item.set(Float.intBitsToFloat(readInt(index))); + break; + case ClassWriter.NAME_TYPE: + item.set(tag, readUTF8(index, buf), readUTF8(index + 2, buf), + null); + break; + case ClassWriter.LONG: + item.set(readLong(index)); + ++i; + break; + case ClassWriter.DOUBLE: + item.set(Double.longBitsToDouble(readLong(index))); + ++i; + break; + case ClassWriter.UTF8: { + String s = strings[i]; + if (s == null) { + index = items[i]; + s = strings[i] = readUTF(index + 2, + readUnsignedShort(index), buf); } - break; - - case ClassWriter.HANDLE: { - int fieldOrMethodRef = items[readUnsignedShort(index + 1)]; - nameType = items[readUnsignedShort(fieldOrMethodRef + 2)]; - item.set(ClassWriter.HANDLE_BASE + readByte(index), - readClass(fieldOrMethodRef, buf), - readUTF8(nameType, buf), - readUTF8(nameType + 2, buf)); - + item.set(tag, s, null, null); + break; + } + case ClassWriter.HANDLE: { + int fieldOrMethodRef = items[readUnsignedShort(index + 1)]; + nameType = items[readUnsignedShort(fieldOrMethodRef + 2)]; + item.set(ClassWriter.HANDLE_BASE + readByte(index), + readClass(fieldOrMethodRef, buf), + readUTF8(nameType, buf), readUTF8(nameType + 2, buf)); + break; + } + case ClassWriter.INDY: + if (classWriter.bootstrapMethods == null) { + copyBootstrapMethods(classWriter, items2, buf); } - break; - - - case ClassWriter.INDY: - if (classWriter.bootstrapMethods == null) { - copyBootstrapMethods(classWriter, items2, buf); - } - nameType = items[readUnsignedShort(index + 2)]; - item.set(readUTF8(nameType, buf), - readUTF8(nameType + 2, buf), - readUnsignedShort(index)); - break; - - - // case ClassWriter.STR: - // case ClassWriter.CLASS: - // case ClassWriter.MTYPE - default: - item.set(tag, readUTF8(index, buf), null, null); - break; + nameType = items[readUnsignedShort(index + 2)]; + item.set(readUTF8(nameType, buf), readUTF8(nameType + 2, buf), + readUnsignedShort(index)); + break; + // case ClassWriter.STR: + // case ClassWriter.CLASS: + // case ClassWriter.MTYPE + default: + item.set(tag, readUTF8(index, buf), null, null); + break; } int index2 = item.hashCode % items2.length; @@ -382,77 +366,59 @@ public class ClassReader { classWriter.index = ll; } - private void copyBootstrapMethods(ClassWriter classWriter, Item[] items2, char[] buf) { - int i, j, k, u, v; - - // skip class header - v = header; - v += 8 + (readUnsignedShort(v + 6) << 1); - - // skips fields and methods - i = readUnsignedShort(v); - v += 2; - for (; i > 0; --i) { - j = readUnsignedShort(v + 6); - v += 8; - for (; j > 0; --j) { - v += 6 + readInt(v + 2); + /** + * Copies the bootstrap method data into the given {@link ClassWriter}. + * Should be called before the {@link #accept(ClassVisitor,int)} method. + * + * @param classWriter + * the {@link ClassWriter} to copy bootstrap methods into. + */ + private void copyBootstrapMethods(final ClassWriter classWriter, + final Item[] items, final char[] c) { + // finds the "BootstrapMethods" attribute + int u = getAttributes(); + boolean found = false; + for (int i = readUnsignedShort(u); i > 0; --i) { + String attrName = readUTF8(u + 2, c); + if ("BootstrapMethods".equals(attrName)) { + found = true; + break; } + u += 6 + readInt(u + 4); } - i = readUnsignedShort(v); - v += 2; - for (; i > 0; --i) { - j = readUnsignedShort(v + 6); - v += 8; - for (; j > 0; --j) { - v += 6 + readInt(v + 2); - } + if (!found) { + return; } - - // read class attributes - i = readUnsignedShort(v); - v += 2; - for (; i > 0; --i) { - String attrName = readUTF8(v, buf); - int size = readInt(v + 2); - if ("BootstrapMethods".equals(attrName)) { - int boostrapMethodCount = readUnsignedShort(v + 6); - int x = v + 8; - for (j = 0; j < boostrapMethodCount; j++) { - int hashCode = readConst(readUnsignedShort(x), buf).hashCode(); - k = readUnsignedShort(x + 2); - u = x + 4; - for(; k > 0; --k) { - hashCode ^= readConst(readUnsignedShort(u), buf).hashCode(); - u += 2; - } - Item item = new Item(j); - item.set(x - v - 8, hashCode & 0x7FFFFFFF); - - int index2 = item.hashCode % items2.length; - item.next = items2[index2]; - items2[index2] = item; - - x = u; - } - - classWriter.bootstrapMethodsCount = boostrapMethodCount; - ByteVector bootstrapMethods = new ByteVector(size + 62); - bootstrapMethods.putByteArray(b, v + 8, size - 2); - classWriter.bootstrapMethods = bootstrapMethods; - return; + // copies the bootstrap methods in the class writer + int boostrapMethodCount = readUnsignedShort(u + 8); + for (int j = 0, v = u + 10; j < boostrapMethodCount; j++) { + int position = v - u - 10; + int hashCode = readConst(readUnsignedShort(v), c).hashCode(); + for (int k = readUnsignedShort(v + 2); k > 0; --k) { + hashCode ^= readConst(readUnsignedShort(v + 4), c).hashCode(); + v += 2; } - v += 6 + size; + v += 4; + Item item = new Item(j); + item.set(position, hashCode & 0x7FFFFFFF); + int index = item.hashCode % items.length; + item.next = items[index]; + items[index] = item; } - - // we are in trouble !!! + int attrSize = readInt(u + 4); + ByteVector bootstrapMethods = new ByteVector(attrSize + 62); + bootstrapMethods.putByteArray(b, u + 10, attrSize - 2); + classWriter.bootstrapMethodsCount = boostrapMethodCount; + classWriter.bootstrapMethods = bootstrapMethods; } /** * Constructs a new {@link ClassReader} object. * - * @param is an input stream from which to read the class. - * @throws IOException if a problem occurs during reading. + * @param is + * an input stream from which to read the class. + * @throws IOException + * if a problem occurs during reading. */ public ClassReader(final InputStream is) throws IOException { this(readClass(is, false)); @@ -461,25 +427,30 @@ public class ClassReader { /** * Constructs a new {@link ClassReader} object. * - * @param name the binary qualified name of the class to be read. - * @throws IOException if an exception occurs during reading. + * @param name + * the binary qualified name of the class to be read. + * @throws IOException + * if an exception occurs during reading. */ public ClassReader(final String name) throws IOException { - this(readClass(ClassLoader.getSystemResourceAsStream(name.replace('.', '/') - + ".class"), true)); + this(readClass( + ClassLoader.getSystemResourceAsStream(name.replace('.', '/') + + ".class"), true)); } /** * Reads the bytecode of a class. * - * @param is an input stream from which to read the class. - * @param close true to close the input stream after reading. + * @param is + * an input stream from which to read the class. + * @param close + * true to close the input stream after reading. * @return the bytecode read from the given input stream. - * @throws IOException if a problem occurs during reading. + * @throws IOException + * if a problem occurs during reading. */ private static byte[] readClass(final InputStream is, boolean close) - throws IOException - { + throws IOException { if (is == null) { throw new IOException("Class not found"); } @@ -520,14 +491,16 @@ public class ClassReader { // ------------------------------------------------------------------------ /** - * Makes the given visitor visit the Java class of this {@link ClassReader}. - * This class is the one specified in the constructor (see + * Makes the given visitor visit the Java class of this {@link ClassReader} + * . This class is the one specified in the constructor (see * {@link #ClassReader(byte[]) ClassReader}). * - * @param classVisitor the visitor that must visit this class. - * @param flags option flags that can be used to modify the default behavior - * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}, - * {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. + * @param classVisitor + * the visitor that must visit this class. + * @param flags + * option flags that can be used to modify the default behavior + * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES} + * , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. */ public void accept(final ClassVisitor classVisitor, final int flags) { accept(classVisitor, new Attribute[0], flags); @@ -538,1117 +511,923 @@ public class ClassReader { * This class is the one specified in the constructor (see * {@link #ClassReader(byte[]) ClassReader}). * - * @param classVisitor the visitor that must visit this class. - * @param attrs prototypes of the attributes that must be parsed during the - * visit of the class. Any attribute whose type is not equal to the - * type of one the prototypes will not be parsed: its byte array - * value will be passed unchanged to the ClassWriter. <i>This may - * corrupt it if this value contains references to the constant pool, - * or has syntactic or semantic links with a class element that has - * been transformed by a class adapter between the reader and the - * writer</i>. - * @param flags option flags that can be used to modify the default behavior - * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}, - * {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. + * @param classVisitor + * the visitor that must visit this class. + * @param attrs + * prototypes of the attributes that must be parsed during the + * visit of the class. Any attribute whose type is not equal to + * the type of one the prototypes will not be parsed: its byte + * array value will be passed unchanged to the ClassWriter. + * <i>This may corrupt it if this value contains references to + * the constant pool, or has syntactic or semantic links with a + * class element that has been transformed by a class adapter + * between the reader and the writer</i>. + * @param flags + * option flags that can be used to modify the default behavior + * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES} + * , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. */ - public void accept( - final ClassVisitor classVisitor, - final Attribute[] attrs, - final int flags) - { - byte[] b = this.b; // the bytecode array + public void accept(final ClassVisitor classVisitor, + final Attribute[] attrs, final int flags) { + int u = header; // current offset in the class file char[] c = new char[maxStringLength]; // buffer used to read strings - int i, j, k; // loop variables - int u, v, w; // indexes in b - Attribute attr; - - int access; - String name; - String desc; - String attrName; - String signature; - int anns = 0; - int ianns = 0; - Attribute cattrs = null; - - // visits the header - u = header; - access = readUnsignedShort(u); - name = readClass(u + 2, c); - v = items[readUnsignedShort(u + 4)]; - String superClassName = v == 0 ? null : readUTF8(v, c); - String[] implementedItfs = new String[readUnsignedShort(u + 6)]; - w = 0; + + Context context = new Context(); + context.attrs = attrs; + context.flags = flags; + context.buffer = c; + + // reads the class declaration + int access = readUnsignedShort(u); + String name = readClass(u + 2, c); + String superClass = readClass(u + 4, c); + String[] interfaces = new String[readUnsignedShort(u + 6)]; u += 8; - for (i = 0; i < implementedItfs.length; ++i) { - implementedItfs[i] = readClass(u, c); + for (int i = 0; i < interfaces.length; ++i) { + interfaces[i] = readClass(u, c); u += 2; } - boolean skipCode = (flags & SKIP_CODE) != 0; - boolean skipDebug = (flags & SKIP_DEBUG) != 0; - boolean unzip = (flags & EXPAND_FRAMES) != 0; - - // skips fields and methods - v = u; - i = readUnsignedShort(v); - v += 2; - for (; i > 0; --i) { - j = readUnsignedShort(v + 6); - v += 8; - for (; j > 0; --j) { - v += 6 + readInt(v + 2); - } - } - i = readUnsignedShort(v); - v += 2; - for (; i > 0; --i) { - j = readUnsignedShort(v + 6); - v += 8; - for (; j > 0; --j) { - v += 6 + readInt(v + 2); - } - } - // reads the class's attributes - signature = null; + // reads the class attributes + String signature = null; String sourceFile = null; String sourceDebug = null; String enclosingOwner = null; String enclosingName = null; String enclosingDesc = null; - int[] bootstrapMethods = null; // start indexed of the bsms + int anns = 0; + int ianns = 0; + int innerClasses = 0; + Attribute attributes = null; - i = readUnsignedShort(v); - v += 2; - for (; i > 0; --i) { - attrName = readUTF8(v, c); + u = getAttributes(); + for (int i = readUnsignedShort(u); i > 0; --i) { + String attrName = readUTF8(u + 2, c); // tests are sorted in decreasing frequency order // (based on frequencies observed on typical classes) if ("SourceFile".equals(attrName)) { - sourceFile = readUTF8(v + 6, c); + sourceFile = readUTF8(u + 8, c); } else if ("InnerClasses".equals(attrName)) { - w = v + 6; + innerClasses = u + 8; } else if ("EnclosingMethod".equals(attrName)) { - enclosingOwner = readClass(v + 6, c); - int item = readUnsignedShort(v + 8); + enclosingOwner = readClass(u + 8, c); + int item = readUnsignedShort(u + 10); if (item != 0) { enclosingName = readUTF8(items[item], c); enclosingDesc = readUTF8(items[item] + 2, c); } } else if (SIGNATURES && "Signature".equals(attrName)) { - signature = readUTF8(v + 6, c); - } else if (ANNOTATIONS && "RuntimeVisibleAnnotations".equals(attrName)) { - anns = v + 6; + signature = readUTF8(u + 8, c); + } else if (ANNOTATIONS + && "RuntimeVisibleAnnotations".equals(attrName)) { + anns = u + 8; } else if ("Deprecated".equals(attrName)) { access |= Opcodes.ACC_DEPRECATED; } else if ("Synthetic".equals(attrName)) { - access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; + access |= Opcodes.ACC_SYNTHETIC + | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; } else if ("SourceDebugExtension".equals(attrName)) { - int len = readInt(v + 2); - sourceDebug = readUTF(v + 6, len, new char[len]); - } else if (ANNOTATIONS && "RuntimeInvisibleAnnotations".equals(attrName)) { - ianns = v + 6; + int len = readInt(u + 4); + sourceDebug = readUTF(u + 8, len, new char[len]); + } else if (ANNOTATIONS + && "RuntimeInvisibleAnnotations".equals(attrName)) { + ianns = u + 8; } else if ("BootstrapMethods".equals(attrName)) { - int boostrapMethodCount = readUnsignedShort(v + 6); - bootstrapMethods = new int[boostrapMethodCount]; - int x = v + 8; - for (j = 0; j < boostrapMethodCount; j++) { - bootstrapMethods[j] = x; - x += 2 + readUnsignedShort(x + 2) << 1; + int[] bootstrapMethods = new int[readUnsignedShort(u + 8)]; + for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) { + bootstrapMethods[j] = v; + v += 2 + readUnsignedShort(v + 2) << 1; } + context.bootstrapMethods = bootstrapMethods; } else { - attr = readAttribute(attrs, - attrName, - v + 6, - readInt(v + 2), - c, - -1, - null); + Attribute attr = readAttribute(attrs, attrName, u + 8, + readInt(u + 4), c, -1, null); if (attr != null) { - attr.next = cattrs; - cattrs = attr; + attr.next = attributes; + attributes = attr; } } - v += 6 + readInt(v + 2); + u += 6 + readInt(u + 4); } - // calls the visit method - classVisitor.visit(readInt(4), - access, - name, - signature, - superClassName, - implementedItfs); - - // calls the visitSource method - if (!skipDebug && (sourceFile != null || sourceDebug != null)) { + + // visits the class declaration + classVisitor.visit(readInt(items[1] - 7), access, name, signature, + superClass, interfaces); + + // visits the source and debug info + if ((flags & SKIP_DEBUG) == 0 + && (sourceFile != null || sourceDebug != null)) { classVisitor.visitSource(sourceFile, sourceDebug); } - // calls the visitOuterClass method + // visits the outer class if (enclosingOwner != null) { - classVisitor.visitOuterClass(enclosingOwner, - enclosingName, + classVisitor.visitOuterClass(enclosingOwner, enclosingName, enclosingDesc); } // visits the class annotations - if (ANNOTATIONS) { - for (i = 1; i >= 0; --i) { - v = i == 0 ? ianns : anns; - if (v != 0) { - j = readUnsignedShort(v); - v += 2; - for (; j > 0; --j) { - v = readAnnotationValues(v + 2, - c, - true, - classVisitor.visitAnnotation(readUTF8(v, c), i != 0)); - } - } + if (ANNOTATIONS && anns != 0) { + for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { + v = readAnnotationValues(v + 2, c, true, + classVisitor.visitAnnotation(readUTF8(v, c), true)); + } + } + if (ANNOTATIONS && ianns != 0) { + for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { + v = readAnnotationValues(v + 2, c, true, + classVisitor.visitAnnotation(readUTF8(v, c), false)); } } - // visits the class attributes - while (cattrs != null) { - attr = cattrs.next; - cattrs.next = null; - classVisitor.visitAttribute(cattrs); - cattrs = attr; + // visits the attributes + while (attributes != null) { + Attribute attr = attributes.next; + attributes.next = null; + classVisitor.visitAttribute(attributes); + attributes = attr; } - // calls the visitInnerClass method - if (w != 0) { - i = readUnsignedShort(w); - w += 2; - for (; i > 0; --i) { - classVisitor.visitInnerClass(readUnsignedShort(w) == 0 - ? null - : readClass(w, c), readUnsignedShort(w + 2) == 0 - ? null - : readClass(w + 2, c), readUnsignedShort(w + 4) == 0 - ? null - : readUTF8(w + 4, c), readUnsignedShort(w + 6)); - w += 8; + // visits the inner classes + if (innerClasses != 0) { + int v = innerClasses + 2; + for (int i = readUnsignedShort(innerClasses); i > 0; --i) { + classVisitor.visitInnerClass(readClass(v, c), + readClass(v + 2, c), readUTF8(v + 4, c), + readUnsignedShort(v + 6)); + v += 8; } } - // visits the fields - i = readUnsignedShort(u); + // visits the fields and methods + u = header + 10 + 2 * interfaces.length; + for (int i = readUnsignedShort(u - 2); i > 0; --i) { + u = readField(classVisitor, context, u); + } u += 2; - for (; i > 0; --i) { - access = readUnsignedShort(u); - name = readUTF8(u + 2, c); - desc = readUTF8(u + 4, c); - // visits the field's attributes and looks for a ConstantValue - // attribute - int fieldValueItem = 0; - signature = null; - anns = 0; - ianns = 0; - cattrs = null; - - j = readUnsignedShort(u + 6); - u += 8; - for (; j > 0; --j) { - attrName = readUTF8(u, c); - // tests are sorted in decreasing frequency order - // (based on frequencies observed on typical classes) - if ("ConstantValue".equals(attrName)) { - fieldValueItem = readUnsignedShort(u + 6); - } else if (SIGNATURES && "Signature".equals(attrName)) { - signature = readUTF8(u + 6, c); - } else if ("Deprecated".equals(attrName)) { - access |= Opcodes.ACC_DEPRECATED; - } else if ("Synthetic".equals(attrName)) { - access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; - } else if (ANNOTATIONS && "RuntimeVisibleAnnotations".equals(attrName)) { - anns = u + 6; - } else if (ANNOTATIONS && "RuntimeInvisibleAnnotations".equals(attrName)) { - ianns = u + 6; - } else { - attr = readAttribute(attrs, - attrName, - u + 6, - readInt(u + 2), - c, - -1, - null); - if (attr != null) { - attr.next = cattrs; - cattrs = attr; - } + for (int i = readUnsignedShort(u - 2); i > 0; --i) { + u = readMethod(classVisitor, context, u); + } + + // visits the end of the class + classVisitor.visitEnd(); + } + + /** + * Reads a field and makes the given visitor visit it. + * + * @param classVisitor + * the visitor that must visit the field. + * @param context + * information about the class being parsed. + * @param u + * the start offset of the field in the class file. + * @return the offset of the first byte following the field in the class. + */ + private int readField(final ClassVisitor classVisitor, + final Context context, int u) { + // reads the field declaration + char[] c = context.buffer; + int access = readUnsignedShort(u); + String name = readUTF8(u + 2, c); + String desc = readUTF8(u + 4, c); + u += 6; + + // reads the field attributes + String signature = null; + int anns = 0; + int ianns = 0; + Object value = null; + Attribute attributes = null; + + for (int i = readUnsignedShort(u); i > 0; --i) { + String attrName = readUTF8(u + 2, c); + // tests are sorted in decreasing frequency order + // (based on frequencies observed on typical classes) + if ("ConstantValue".equals(attrName)) { + int item = readUnsignedShort(u + 8); + value = item == 0 ? null : readConst(item, c); + } else if (SIGNATURES && "Signature".equals(attrName)) { + signature = readUTF8(u + 8, c); + } else if ("Deprecated".equals(attrName)) { + access |= Opcodes.ACC_DEPRECATED; + } else if ("Synthetic".equals(attrName)) { + access |= Opcodes.ACC_SYNTHETIC + | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; + } else if (ANNOTATIONS + && "RuntimeVisibleAnnotations".equals(attrName)) { + anns = u + 8; + } else if (ANNOTATIONS + && "RuntimeInvisibleAnnotations".equals(attrName)) { + ianns = u + 8; + } else { + Attribute attr = readAttribute(context.attrs, attrName, u + 8, + readInt(u + 4), c, -1, null); + if (attr != null) { + attr.next = attributes; + attributes = attr; } - u += 6 + readInt(u + 2); } - // visits the field - FieldVisitor fv = classVisitor.visitField(access, - name, - desc, - signature, - fieldValueItem == 0 ? null : readConst(fieldValueItem, c)); - // visits the field annotations and attributes - if (fv != null) { - if (ANNOTATIONS) { - for (j = 1; j >= 0; --j) { - v = j == 0 ? ianns : anns; - if (v != 0) { - k = readUnsignedShort(v); - v += 2; - for (; k > 0; --k) { - v = readAnnotationValues(v + 2, - c, - true, - fv.visitAnnotation(readUTF8(v, c), j != 0)); - } - } - } - } - while (cattrs != null) { - attr = cattrs.next; - cattrs.next = null; - fv.visitAttribute(cattrs); - cattrs = attr; - } - fv.visitEnd(); + u += 6 + readInt(u + 4); + } + u += 2; + + // visits the field declaration + FieldVisitor fv = classVisitor.visitField(access, name, desc, + signature, value); + if (fv == null) { + return u; + } + + // visits the field annotations + if (ANNOTATIONS && anns != 0) { + for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { + v = readAnnotationValues(v + 2, c, true, + fv.visitAnnotation(readUTF8(v, c), true)); + } + } + if (ANNOTATIONS && ianns != 0) { + for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { + v = readAnnotationValues(v + 2, c, true, + fv.visitAnnotation(readUTF8(v, c), false)); } } - // visits the methods - i = readUnsignedShort(u); - u += 2; - for (; i > 0; --i) { - int u0 = u + 6; - access = readUnsignedShort(u); - name = readUTF8(u + 2, c); - desc = readUTF8(u + 4, c); - signature = null; - anns = 0; - ianns = 0; - int dann = 0; - int mpanns = 0; - int impanns = 0; - cattrs = null; - v = 0; - w = 0; - - // looks for Code and Exceptions attributes - j = readUnsignedShort(u + 6); - u += 8; - for (; j > 0; --j) { - attrName = readUTF8(u, c); - int attrSize = readInt(u + 2); - u += 6; - // tests are sorted in decreasing frequency order - // (based on frequencies observed on typical classes) - if ("Code".equals(attrName)) { - if (!skipCode) { - v = u; - } - } else if ("Exceptions".equals(attrName)) { - w = u; - } else if (SIGNATURES && "Signature".equals(attrName)) { - signature = readUTF8(u, c); - } else if ("Deprecated".equals(attrName)) { - access |= Opcodes.ACC_DEPRECATED; - } else if (ANNOTATIONS && "RuntimeVisibleAnnotations".equals(attrName)) { - anns = u; - } else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) { - dann = u; - } else if ("Synthetic".equals(attrName)) { - access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; - } else if (ANNOTATIONS && "RuntimeInvisibleAnnotations".equals(attrName)) { - ianns = u; - } else if (ANNOTATIONS && "RuntimeVisibleParameterAnnotations".equals(attrName)) - { - mpanns = u; - } else if (ANNOTATIONS && "RuntimeInvisibleParameterAnnotations".equals(attrName)) - { - impanns = u; - } else { - attr = readAttribute(attrs, - attrName, - u, - attrSize, - c, - -1, - null); - if (attr != null) { - attr.next = cattrs; - cattrs = attr; - } + // visits the field attributes + while (attributes != null) { + Attribute attr = attributes.next; + attributes.next = null; + fv.visitAttribute(attributes); + attributes = attr; + } + + // visits the end of the field + fv.visitEnd(); + + return u; + } + + /** + * Reads a method and makes the given visitor visit it. + * + * @param classVisitor + * the visitor that must visit the method. + * @param context + * information about the class being parsed. + * @param u + * the start offset of the method in the class file. + * @return the offset of the first byte following the method in the class. + */ + private int readMethod(final ClassVisitor classVisitor, + final Context context, int u) { + // reads the method declaration + char[] c = context.buffer; + int access = readUnsignedShort(u); + String name = readUTF8(u + 2, c); + String desc = readUTF8(u + 4, c); + u += 6; + + // reads the method attributes + int code = 0; + int exception = 0; + String[] exceptions = null; + String signature = null; + int anns = 0; + int ianns = 0; + int dann = 0; + int mpanns = 0; + int impanns = 0; + int firstAttribute = u; + Attribute attributes = null; + + for (int i = readUnsignedShort(u); i > 0; --i) { + String attrName = readUTF8(u + 2, c); + // tests are sorted in decreasing frequency order + // (based on frequencies observed on typical classes) + if ("Code".equals(attrName)) { + if ((context.flags & SKIP_CODE) == 0) { + code = u + 8; } - u += attrSize; - } - // reads declared exceptions - String[] exceptions; - if (w == 0) { - exceptions = null; + } else if ("Exceptions".equals(attrName)) { + exceptions = new String[readUnsignedShort(u + 8)]; + exception = u + 10; + for (int j = 0; j < exceptions.length; ++j) { + exceptions[j] = readClass(exception, c); + exception += 2; + } + } else if (SIGNATURES && "Signature".equals(attrName)) { + signature = readUTF8(u + 8, c); + } else if ("Deprecated".equals(attrName)) { + access |= Opcodes.ACC_DEPRECATED; + } else if (ANNOTATIONS + && "RuntimeVisibleAnnotations".equals(attrName)) { + anns = u + 8; + } else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) { + dann = u + 8; + } else if ("Synthetic".equals(attrName)) { + access |= Opcodes.ACC_SYNTHETIC + | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; + } else if (ANNOTATIONS + && "RuntimeInvisibleAnnotations".equals(attrName)) { + ianns = u + 8; + } else if (ANNOTATIONS + && "RuntimeVisibleParameterAnnotations".equals(attrName)) { + mpanns = u + 8; + } else if (ANNOTATIONS + && "RuntimeInvisibleParameterAnnotations".equals(attrName)) { + impanns = u + 8; } else { - exceptions = new String[readUnsignedShort(w)]; - w += 2; - for (j = 0; j < exceptions.length; ++j) { - exceptions[j] = readClass(w, c); - w += 2; + Attribute attr = readAttribute(context.attrs, attrName, u + 8, + readInt(u + 4), c, -1, null); + if (attr != null) { + attr.next = attributes; + attributes = attr; } } + u += 6 + readInt(u + 4); + } + u += 2; - // visits the method's code, if any - MethodVisitor mv = classVisitor.visitMethod(access, - name, - desc, - signature, - exceptions); + // visits the method declaration + MethodVisitor mv = classVisitor.visitMethod(access, name, desc, + signature, exceptions); + if (mv == null) { + return u; + } - if (mv != null) { - /* - * if the returned MethodVisitor is in fact a MethodWriter, it - * means there is no method adapter between the reader and the - * writer. If, in addition, the writer's constant pool was - * copied from this reader (mw.cw.cr == this), and the signature - * and exceptions of the method have not been changed, then it - * is possible to skip all visit events and just copy the - * original code of the method to the writer (the access, name - * and descriptor can have been changed, this is not important - * since they are not copied as is from the reader). - */ - if (WRITER && mv instanceof MethodWriter) { - MethodWriter mw = (MethodWriter) mv; - if (mw.cw.cr == this) { - if (signature == mw.signature) { - boolean sameExceptions = false; - if (exceptions == null) { - sameExceptions = mw.exceptionCount == 0; - } else { - if (exceptions.length == mw.exceptionCount) { - sameExceptions = true; - for (j = exceptions.length - 1; j >= 0; --j) - { - w -= 2; - if (mw.exceptions[j] != readUnsignedShort(w)) - { - sameExceptions = false; - break; - } - } - } - } - if (sameExceptions) { - /* - * we do not copy directly the code into - * MethodWriter to save a byte array copy - * operation. The real copy will be done in - * ClassWriter.toByteArray(). - */ - mw.classReaderOffset = u0; - mw.classReaderLength = u - u0; - continue; - } + /* + * if the returned MethodVisitor is in fact a MethodWriter, it means + * there is no method adapter between the reader and the writer. If, in + * addition, the writer's constant pool was copied from this reader + * (mw.cw.cr == this), and the signature and exceptions of the method + * have not been changed, then it is possible to skip all visit events + * and just copy the original code of the method to the writer (the + * access, name and descriptor can have been changed, this is not + * important since they are not copied as is from the reader). + */ + if (WRITER && mv instanceof MethodWriter) { + MethodWriter mw = (MethodWriter) mv; + if (mw.cw.cr == this && signature == mw.signature) { + boolean sameExceptions = false; + if (exceptions == null) { + sameExceptions = mw.exceptionCount == 0; + } else if (exceptions.length == mw.exceptionCount) { + sameExceptions = true; + for (int j = exceptions.length - 1; j >= 0; --j) { + exception -= 2; + if (mw.exceptions[j] != readUnsignedShort(exception)) { + sameExceptions = false; + break; } } } - - if (ANNOTATIONS && dann != 0) { - AnnotationVisitor dv = mv.visitAnnotationDefault(); - readAnnotationValue(dann, c, null, dv); - if (dv != null) { - dv.visitEnd(); - } - } - if (ANNOTATIONS) { - for (j = 1; j >= 0; --j) { - w = j == 0 ? ianns : anns; - if (w != 0) { - k = readUnsignedShort(w); - w += 2; - for (; k > 0; --k) { - w = readAnnotationValues(w + 2, - c, - true, - mv.visitAnnotation(readUTF8(w, c), j != 0)); - } - } - } + if (sameExceptions) { + /* + * we do not copy directly the code into MethodWriter to + * save a byte array copy operation. The real copy will be + * done in ClassWriter.toByteArray(). + */ + mw.classReaderOffset = firstAttribute; + mw.classReaderLength = u - firstAttribute; + return u; } - if (ANNOTATIONS && mpanns != 0) { - readParameterAnnotations(mpanns, desc, c, true, mv); + } + } + + // visits the method annotations + if (ANNOTATIONS && dann != 0) { + AnnotationVisitor dv = mv.visitAnnotationDefault(); + readAnnotationValue(dann, c, null, dv); + if (dv != null) { + dv.visitEnd(); + } + } + if (ANNOTATIONS && anns != 0) { + for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { + v = readAnnotationValues(v + 2, c, true, + mv.visitAnnotation(readUTF8(v, c), true)); + } + } + if (ANNOTATIONS && ianns != 0) { + for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { + v = readAnnotationValues(v + 2, c, true, + mv.visitAnnotation(readUTF8(v, c), false)); + } + } + if (ANNOTATIONS && mpanns != 0) { + readParameterAnnotations(mpanns, desc, c, true, mv); + } + if (ANNOTATIONS && impanns != 0) { + readParameterAnnotations(impanns, desc, c, false, mv); + } + + // visits the method attributes + while (attributes != null) { + Attribute attr = attributes.next; + attributes.next = null; + mv.visitAttribute(attributes); + attributes = attr; + } + + // visits the method code + if (code != 0) { + context.access = access; + context.name = name; + context.desc = desc; + mv.visitCode(); + readCode(mv, context, code); + } + + // visits the end of the method + mv.visitEnd(); + + return u; + } + + /** + * Reads the bytecode of a method and makes the given visitor visit it. + * + * @param mv + * the visitor that must visit the method's code. + * @param context + * information about the class being parsed. + * @param u + * the start offset of the code attribute in the class file. + */ + private void readCode(final MethodVisitor mv, final Context context, int u) { + // reads the header + byte[] b = this.b; + char[] c = context.buffer; + int maxStack = readUnsignedShort(u); + int maxLocals = readUnsignedShort(u + 2); + int codeLength = readInt(u + 4); + u += 8; + + // reads the bytecode to find the labels + int codeStart = u; + int codeEnd = u + codeLength; + Label[] labels = new Label[codeLength + 2]; + readLabel(codeLength + 1, labels); + while (u < codeEnd) { + int offset = u - codeStart; + int opcode = b[u] & 0xFF; + switch (ClassWriter.TYPE[opcode]) { + case ClassWriter.NOARG_INSN: + case ClassWriter.IMPLVAR_INSN: + u += 1; + break; + case ClassWriter.LABEL_INSN: + readLabel(offset + readShort(u + 1), labels); + u += 3; + break; + case ClassWriter.LABELW_INSN: + readLabel(offset + readInt(u + 1), labels); + u += 5; + break; + case ClassWriter.WIDE_INSN: + opcode = b[u + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + u += 6; + } else { + u += 4; } - if (ANNOTATIONS && impanns != 0) { - readParameterAnnotations(impanns, desc, c, false, mv); + break; + case ClassWriter.TABL_INSN: + // skips 0 to 3 padding bytes + u = u + 4 - (offset & 3); + // reads instruction + readLabel(offset + readInt(u), labels); + for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) { + readLabel(offset + readInt(u + 12), labels); + u += 4; } - while (cattrs != null) { - attr = cattrs.next; - cattrs.next = null; - mv.visitAttribute(cattrs); - cattrs = attr; + u += 12; + break; + case ClassWriter.LOOK_INSN: + // skips 0 to 3 padding bytes + u = u + 4 - (offset & 3); + // reads instruction + readLabel(offset + readInt(u), labels); + for (int i = readInt(u + 4); i > 0; --i) { + readLabel(offset + readInt(u + 12), labels); + u += 8; } + u += 8; + break; + case ClassWriter.VAR_INSN: + case ClassWriter.SBYTE_INSN: + case ClassWriter.LDC_INSN: + u += 2; + break; + case ClassWriter.SHORT_INSN: + case ClassWriter.LDCW_INSN: + case ClassWriter.FIELDORMETH_INSN: + case ClassWriter.TYPE_INSN: + case ClassWriter.IINC_INSN: + u += 3; + break; + case ClassWriter.ITFMETH_INSN: + case ClassWriter.INDYMETH_INSN: + u += 5; + break; + // case MANA_INSN: + default: + u += 4; + break; } + } - if (mv != null && v != 0) { - int maxStack = readUnsignedShort(v); - int maxLocals = readUnsignedShort(v + 2); - int codeLength = readInt(v + 4); - v += 8; + // reads the try catch entries to find the labels, and also visits them + for (int i = readUnsignedShort(u); i > 0; --i) { + Label start = readLabel(readUnsignedShort(u + 2), labels); + Label end = readLabel(readUnsignedShort(u + 4), labels); + Label handler = readLabel(readUnsignedShort(u + 6), labels); + String type = readUTF8(items[readUnsignedShort(u + 8)], c); + mv.visitTryCatchBlock(start, end, handler, type); + u += 8; + } + u += 2; - int codeStart = v; - int codeEnd = v + codeLength; - - mv.visitCode(); - - // 1st phase: finds the labels - int label; - Label[] labels = new Label[codeLength + 2]; - readLabel(codeLength + 1, labels); - while (v < codeEnd) { - w = v - codeStart; - int opcode = b[v] & 0xFF; - switch (ClassWriter.TYPE[opcode]) { - case ClassWriter.NOARG_INSN: - case ClassWriter.IMPLVAR_INSN: - v += 1; - break; - case ClassWriter.LABEL_INSN: - readLabel(w + readShort(v + 1), labels); - v += 3; - break; - case ClassWriter.LABELW_INSN: - readLabel(w + readInt(v + 1), labels); - v += 5; - break; - case ClassWriter.WIDE_INSN: - opcode = b[v + 1] & 0xFF; - if (opcode == Opcodes.IINC) { - v += 6; - } else { - v += 4; - } - break; - case ClassWriter.TABL_INSN: - // skips 0 to 3 padding bytes* - v = v + 4 - (w & 3); - // reads instruction - readLabel(w + readInt(v), labels); - j = readInt(v + 8) - readInt(v + 4) + 1; - v += 12; - for (; j > 0; --j) { - readLabel(w + readInt(v), labels); - v += 4; - } - break; - case ClassWriter.LOOK_INSN: - // skips 0 to 3 padding bytes* - v = v + 4 - (w & 3); - // reads instruction - readLabel(w + readInt(v), labels); - j = readInt(v + 4); - v += 8; - for (; j > 0; --j) { - readLabel(w + readInt(v + 4), labels); - v += 8; - } - break; - case ClassWriter.VAR_INSN: - case ClassWriter.SBYTE_INSN: - case ClassWriter.LDC_INSN: - v += 2; - break; - case ClassWriter.SHORT_INSN: - case ClassWriter.LDCW_INSN: - case ClassWriter.FIELDORMETH_INSN: - case ClassWriter.TYPE_INSN: - case ClassWriter.IINC_INSN: - v += 3; - break; - case ClassWriter.ITFMETH_INSN: - case ClassWriter.INDYMETH_INSN: - v += 5; - break; - // case MANA_INSN: - default: - v += 4; - break; - } - } - // parses the try catch entries - j = readUnsignedShort(v); - v += 2; - for (; j > 0; --j) { - Label start = readLabel(readUnsignedShort(v), labels); - Label end = readLabel(readUnsignedShort(v + 2), labels); - Label handler = readLabel(readUnsignedShort(v + 4), labels); - int type = readUnsignedShort(v + 6); - if (type == 0) { - mv.visitTryCatchBlock(start, end, handler, null); - } else { - mv.visitTryCatchBlock(start, - end, - handler, - readUTF8(items[type], c)); - } - v += 8; - } - // parses the local variable, line number tables, and code - // attributes - int varTable = 0; - int varTypeTable = 0; - int stackMap = 0; - int stackMapSize = 0; - int frameCount = 0; - int frameMode = 0; - int frameOffset = 0; - int frameLocalCount = 0; - int frameLocalDiff = 0; - int frameStackCount = 0; - Object[] frameLocal = null; - Object[] frameStack = null; - boolean zip = true; - cattrs = null; - j = readUnsignedShort(v); - v += 2; - for (; j > 0; --j) { - attrName = readUTF8(v, c); - if ("LocalVariableTable".equals(attrName)) { - if (!skipDebug) { - varTable = v + 6; - k = readUnsignedShort(v + 6); - w = v + 8; - for (; k > 0; --k) { - label = readUnsignedShort(w); - if (labels[label] == null) { - readLabel(label, labels).status |= Label.DEBUG; - } - label += readUnsignedShort(w + 2); - if (labels[label] == null) { - readLabel(label, labels).status |= Label.DEBUG; - } - w += 10; - } - } - } else if ("LocalVariableTypeTable".equals(attrName)) { - varTypeTable = v + 6; - } else if ("LineNumberTable".equals(attrName)) { - if (!skipDebug) { - k = readUnsignedShort(v + 6); - w = v + 8; - for (; k > 0; --k) { - label = readUnsignedShort(w); - if (labels[label] == null) { - readLabel(label, labels).status |= Label.DEBUG; - } - labels[label].line = readUnsignedShort(w + 2); - w += 4; - } - } - } else if (FRAMES && "StackMapTable".equals(attrName)) { - if ((flags & SKIP_FRAMES) == 0) { - stackMap = v + 8; - stackMapSize = readInt(v + 2); - frameCount = readUnsignedShort(v + 6); + // reads the code attributes + int varTable = 0; + int varTypeTable = 0; + boolean zip = true; + boolean unzip = (context.flags & EXPAND_FRAMES) != 0; + int stackMap = 0; + int stackMapSize = 0; + int frameCount = 0; + Context frame = null; + Attribute attributes = null; + + for (int i = readUnsignedShort(u); i > 0; --i) { + String attrName = readUTF8(u + 2, c); + if ("LocalVariableTable".equals(attrName)) { + if ((context.flags & SKIP_DEBUG) == 0) { + varTable = u + 8; + for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { + int label = readUnsignedShort(v + 10); + if (labels[label] == null) { + readLabel(label, labels).status |= Label.DEBUG; } - /* - * here we do not extract the labels corresponding to - * the attribute content. This would require a full - * parsing of the attribute, which would need to be - * repeated in the second phase (see below). Instead the - * content of the attribute is read one frame at a time - * (i.e. after a frame has been visited, the next frame - * is read), and the labels it contains are also - * extracted one frame at a time. Thanks to the ordering - * of frames, having only a "one frame lookahead" is not - * a problem, i.e. it is not possible to see an offset - * smaller than the offset of the current insn and for - * which no Label exist. - */ - /* - * This is not true for UNINITIALIZED type offsets. We - * solve this by parsing the stack map table without a - * full decoding (see below). - */ - } else if (FRAMES && "StackMap".equals(attrName)) { - if ((flags & SKIP_FRAMES) == 0) { - stackMap = v + 8; - stackMapSize = readInt(v + 2); - frameCount = readUnsignedShort(v + 6); - zip = false; - } - /* - * IMPORTANT! here we assume that the frames are - * ordered, as in the StackMapTable attribute, although - * this is not guaranteed by the attribute format. - */ - } else { - for (k = 0; k < attrs.length; ++k) { - if (attrs[k].type.equals(attrName)) { - attr = attrs[k].read(this, - v + 6, - readInt(v + 2), - c, - codeStart - 8, - labels); - if (attr != null) { - attr.next = cattrs; - cattrs = attr; - } - } + label += readUnsignedShort(v + 12); + if (labels[label] == null) { + readLabel(label, labels).status |= Label.DEBUG; } + v += 10; } - v += 6 + readInt(v + 2); } - - // 2nd phase: visits each instruction - if (FRAMES && stackMap != 0) { - // creates the very first (implicit) frame from the method - // descriptor - frameLocal = new Object[maxLocals]; - frameStack = new Object[maxStack]; - if (unzip) { - int local = 0; - if ((access & Opcodes.ACC_STATIC) == 0) { - if ("<init>".equals(name)) { - frameLocal[local++] = Opcodes.UNINITIALIZED_THIS; - } else { - frameLocal[local++] = readClass(header + 2, c); - } - } - j = 1; - loop: while (true) { - k = j; - switch (desc.charAt(j++)) { - case 'Z': - case 'C': - case 'B': - case 'S': - case 'I': - frameLocal[local++] = Opcodes.INTEGER; - break; - case 'F': - frameLocal[local++] = Opcodes.FLOAT; - break; - case 'J': - frameLocal[local++] = Opcodes.LONG; - break; - case 'D': - frameLocal[local++] = Opcodes.DOUBLE; - break; - case '[': - while (desc.charAt(j) == '[') { - ++j; - } - if (desc.charAt(j) == 'L') { - ++j; - while (desc.charAt(j) != ';') { - ++j; - } - } - frameLocal[local++] = desc.substring(k, ++j); - break; - case 'L': - while (desc.charAt(j) != ';') { - ++j; - } - frameLocal[local++] = desc.substring(k + 1, - j++); - break; - default: - break loop; - } + } else if ("LocalVariableTypeTable".equals(attrName)) { + varTypeTable = u + 8; + } else if ("LineNumberTable".equals(attrName)) { + if ((context.flags & SKIP_DEBUG) == 0) { + for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { + int label = readUnsignedShort(v + 10); + if (labels[label] == null) { + readLabel(label, labels).status |= Label.DEBUG; } - frameLocalCount = local; + labels[label].line = readUnsignedShort(v + 12); + v += 4; } - /* - * for the first explicit frame the offset is not - * offset_delta + 1 but only offset_delta; setting the - * implicit frame offset to -1 allow the use of the - * "offset_delta + 1" rule in all cases - */ - frameOffset = -1; - /* - * Finds labels for UNINITIALIZED frame types. Instead of - * decoding each element of the stack map table, we look - * for 3 consecutive bytes that "look like" an UNINITIALIZED - * type (tag 8, offset within code bounds, NEW instruction - * at this offset). We may find false positives (i.e. not - * real UNINITIALIZED types), but this should be rare, and - * the only consequence will be the creation of an unneeded - * label. This is better than creating a label for each NEW - * instruction, and faster than fully decoding the whole - * stack map table. - */ - for (j = stackMap; j < stackMap + stackMapSize - 2; ++j) { - if (b[j] == 8) { // UNINITIALIZED FRAME TYPE - k = readUnsignedShort(j + 1); - if (k >= 0 && k < codeLength) { // potential offset - if ((b[codeStart + k] & 0xFF) == Opcodes.NEW) { // NEW at this offset - readLabel(k, labels); - } - } + } + } else if (FRAMES && "StackMapTable".equals(attrName)) { + if ((context.flags & SKIP_FRAMES) == 0) { + stackMap = u + 10; + stackMapSize = readInt(u + 4); + frameCount = readUnsignedShort(u + 8); + } + /* + * here we do not extract the labels corresponding to the + * attribute content. This would require a full parsing of the + * attribute, which would need to be repeated in the second + * phase (see below). Instead the content of the attribute is + * read one frame at a time (i.e. after a frame has been + * visited, the next frame is read), and the labels it contains + * are also extracted one frame at a time. Thanks to the + * ordering of frames, having only a "one frame lookahead" is + * not a problem, i.e. it is not possible to see an offset + * smaller than the offset of the current insn and for which no + * Label exist. + */ + /* + * This is not true for UNINITIALIZED type offsets. We solve + * this by parsing the stack map table without a full decoding + * (see below). + */ + } else if (FRAMES && "StackMap".equals(attrName)) { + if ((context.flags & SKIP_FRAMES) == 0) { + zip = false; + stackMap = u + 10; + stackMapSize = readInt(u + 4); + frameCount = readUnsignedShort(u + 8); + } + /* + * IMPORTANT! here we assume that the frames are ordered, as in + * the StackMapTable attribute, although this is not guaranteed + * by the attribute format. + */ + } else { + for (int j = 0; j < context.attrs.length; ++j) { + if (context.attrs[j].type.equals(attrName)) { + Attribute attr = context.attrs[j].read(this, u + 8, + readInt(u + 4), c, codeStart - 8, labels); + if (attr != null) { + attr.next = attributes; + attributes = attr; } } } - v = codeStart; - Label l; - while (v < codeEnd) { - w = v - codeStart; - - l = labels[w]; - if (l != null) { - mv.visitLabel(l); - if (!skipDebug && l.line > 0) { - mv.visitLineNumber(l.line, l); + } + u += 6 + readInt(u + 4); + } + u += 2; + + // generates the first (implicit) stack map frame + if (FRAMES && stackMap != 0) { + /* + * for the first explicit frame the offset is not offset_delta + 1 + * but only offset_delta; setting the implicit frame offset to -1 + * allow the use of the "offset_delta + 1" rule in all cases + */ + frame = context; + frame.offset = -1; + frame.mode = 0; + frame.localCount = 0; + frame.localDiff = 0; + frame.stackCount = 0; + frame.local = new Object[maxLocals]; + frame.stack = new Object[maxStack]; + if (unzip) { + getImplicitFrame(context); + } + /* + * Finds labels for UNINITIALIZED frame types. Instead of decoding + * each element of the stack map table, we look for 3 consecutive + * bytes that "look like" an UNINITIALIZED type (tag 8, offset + * within code bounds, NEW instruction at this offset). We may find + * false positives (i.e. not real UNINITIALIZED types), but this + * should be rare, and the only consequence will be the creation of + * an unneeded label. This is better than creating a label for each + * NEW instruction, and faster than fully decoding the whole stack + * map table. + */ + for (int i = stackMap; i < stackMap + stackMapSize - 2; ++i) { + if (b[i] == 8) { // UNINITIALIZED FRAME TYPE + int v = readUnsignedShort(i + 1); + if (v >= 0 && v < codeLength) { + if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) { + readLabel(v, labels); } } + } + } + } - while (FRAMES && frameLocal != null - && (frameOffset == w || frameOffset == -1)) - { - // if there is a frame for this offset, - // makes the visitor visit it, - // and reads the next frame if there is one. - if (!zip || unzip) { - mv.visitFrame(Opcodes.F_NEW, - frameLocalCount, - frameLocal, - frameStackCount, - frameStack); - } else if (frameOffset != -1) { - mv.visitFrame(frameMode, - frameLocalDiff, - frameLocal, - frameStackCount, - frameStack); - } + // visits the instructions + u = codeStart; + while (u < codeEnd) { + int offset = u - codeStart; + + // visits the label and line number for this offset, if any + Label l = labels[offset]; + if (l != null) { + mv.visitLabel(l); + if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) { + mv.visitLineNumber(l.line, l); + } + } - if (frameCount > 0) { - int tag, delta, n; - if (zip) { - tag = b[stackMap++] & 0xFF; - } else { - tag = MethodWriter.FULL_FRAME; - frameOffset = -1; - } - frameLocalDiff = 0; - if (tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME) - { - delta = tag; - frameMode = Opcodes.F_SAME; - frameStackCount = 0; - } else if (tag < MethodWriter.RESERVED) { - delta = tag - - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME; - stackMap = readFrameType(frameStack, - 0, - stackMap, - c, - labels); - frameMode = Opcodes.F_SAME1; - frameStackCount = 1; - } else { - delta = readUnsignedShort(stackMap); - stackMap += 2; - if (tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) - { - stackMap = readFrameType(frameStack, - 0, - stackMap, - c, - labels); - frameMode = Opcodes.F_SAME1; - frameStackCount = 1; - } else if (tag >= MethodWriter.CHOP_FRAME - && tag < MethodWriter.SAME_FRAME_EXTENDED) - { - frameMode = Opcodes.F_CHOP; - frameLocalDiff = MethodWriter.SAME_FRAME_EXTENDED - - tag; - frameLocalCount -= frameLocalDiff; - frameStackCount = 0; - } else if (tag == MethodWriter.SAME_FRAME_EXTENDED) - { - frameMode = Opcodes.F_SAME; - frameStackCount = 0; - } else if (tag < MethodWriter.FULL_FRAME) { - j = unzip ? frameLocalCount : 0; - for (k = tag - - MethodWriter.SAME_FRAME_EXTENDED; k > 0; k--) - { - stackMap = readFrameType(frameLocal, - j++, - stackMap, - c, - labels); - } - frameMode = Opcodes.F_APPEND; - frameLocalDiff = tag - - MethodWriter.SAME_FRAME_EXTENDED; - frameLocalCount += frameLocalDiff; - frameStackCount = 0; - } else { // if (tag == FULL_FRAME) { - frameMode = Opcodes.F_FULL; - n = frameLocalDiff = frameLocalCount = readUnsignedShort(stackMap); - stackMap += 2; - for (j = 0; n > 0; n--) { - stackMap = readFrameType(frameLocal, - j++, - stackMap, - c, - labels); - } - n = frameStackCount = readUnsignedShort(stackMap); - stackMap += 2; - for (j = 0; n > 0; n--) { - stackMap = readFrameType(frameStack, - j++, - stackMap, - c, - labels); - } - } - } - frameOffset += delta + 1; - readLabel(frameOffset, labels); - - --frameCount; - } else { - frameLocal = null; - } + // visits the frame for this offset, if any + while (FRAMES && frame != null + && (frame.offset == offset || frame.offset == -1)) { + // if there is a frame for this offset, makes the visitor visit + // it, and reads the next frame if there is one. + if (frame.offset != -1) { + if (!zip || unzip) { + mv.visitFrame(Opcodes.F_NEW, frame.localCount, + frame.local, frame.stackCount, frame.stack); + } else { + mv.visitFrame(frame.mode, frame.localDiff, frame.local, + frame.stackCount, frame.stack); } + } + if (frameCount > 0) { + stackMap = readFrame(stackMap, zip, unzip, labels, frame); + --frameCount; + } else { + frame = null; + } + } - int opcode = b[v] & 0xFF; - switch (ClassWriter.TYPE[opcode]) { - case ClassWriter.NOARG_INSN: - mv.visitInsn(opcode); - v += 1; - break; - case ClassWriter.IMPLVAR_INSN: - if (opcode > Opcodes.ISTORE) { - opcode -= 59; // ISTORE_0 - mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), - opcode & 0x3); - } else { - opcode -= 26; // ILOAD_0 - mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), - opcode & 0x3); - } - v += 1; - break; - case ClassWriter.LABEL_INSN: - mv.visitJumpInsn(opcode, labels[w - + readShort(v + 1)]); - v += 3; - break; - case ClassWriter.LABELW_INSN: - mv.visitJumpInsn(opcode - 33, labels[w - + readInt(v + 1)]); - v += 5; - break; - case ClassWriter.WIDE_INSN: - opcode = b[v + 1] & 0xFF; - if (opcode == Opcodes.IINC) { - mv.visitIincInsn(readUnsignedShort(v + 2), - readShort(v + 4)); - v += 6; - } else { - mv.visitVarInsn(opcode, - readUnsignedShort(v + 2)); - v += 4; - } - break; - case ClassWriter.TABL_INSN: - // skips 0 to 3 padding bytes - v = v + 4 - (w & 3); - // reads instruction - label = w + readInt(v); - int min = readInt(v + 4); - int max = readInt(v + 8); - v += 12; - Label[] table = new Label[max - min + 1]; - for (j = 0; j < table.length; ++j) { - table[j] = labels[w + readInt(v)]; - v += 4; - } - mv.visitTableSwitchInsn(min, - max, - labels[label], - table); - break; - case ClassWriter.LOOK_INSN: - // skips 0 to 3 padding bytes - v = v + 4 - (w & 3); - // reads instruction - label = w + readInt(v); - j = readInt(v + 4); - v += 8; - int[] keys = new int[j]; - Label[] values = new Label[j]; - for (j = 0; j < keys.length; ++j) { - keys[j] = readInt(v); - values[j] = labels[w + readInt(v + 4)]; - v += 8; - } - mv.visitLookupSwitchInsn(labels[label], - keys, - values); - break; - case ClassWriter.VAR_INSN: - mv.visitVarInsn(opcode, b[v + 1] & 0xFF); - v += 2; - break; - case ClassWriter.SBYTE_INSN: - mv.visitIntInsn(opcode, b[v + 1]); - v += 2; - break; - case ClassWriter.SHORT_INSN: - mv.visitIntInsn(opcode, readShort(v + 1)); - v += 3; - break; - case ClassWriter.LDC_INSN: - mv.visitLdcInsn(readConst(b[v + 1] & 0xFF, c)); - v += 2; - break; - case ClassWriter.LDCW_INSN: - mv.visitLdcInsn(readConst(readUnsignedShort(v + 1), - c)); - v += 3; - break; - case ClassWriter.FIELDORMETH_INSN: - case ClassWriter.ITFMETH_INSN: { - int cpIndex = items[readUnsignedShort(v + 1)]; - String iowner = readClass(cpIndex, c); - cpIndex = items[readUnsignedShort(cpIndex + 2)]; - String iname = readUTF8(cpIndex, c); - String idesc = readUTF8(cpIndex + 2, c); - if (opcode < Opcodes.INVOKEVIRTUAL) { - mv.visitFieldInsn(opcode, iowner, iname, idesc); - } else { - mv.visitMethodInsn(opcode, iowner, iname, idesc); - } - if (opcode == Opcodes.INVOKEINTERFACE) { - v += 5; - } else { - v += 3; - } - break; - } - case ClassWriter.INDYMETH_INSN: { - int cpIndex = items[readUnsignedShort(v + 1)]; - int bsmIndex = bootstrapMethods[readUnsignedShort(cpIndex)]; - cpIndex = items[readUnsignedShort(cpIndex + 2)]; - String iname = readUTF8(cpIndex, c); - String idesc = readUTF8(cpIndex + 2, c); - - int mhIndex = readUnsignedShort(bsmIndex); - Handle bsm = (Handle) readConst(mhIndex, c); - int bsmArgCount = readUnsignedShort(bsmIndex + 2); - Object[] bsmArgs = new Object[bsmArgCount]; - bsmIndex += 4; - for(int a = 0; a < bsmArgCount; a++) { - int argIndex = readUnsignedShort(bsmIndex); - bsmArgs[a] = readConst(argIndex, c); - bsmIndex += 2; - } - mv.visitInvokeDynamicInsn(iname, idesc, bsm, bsmArgs); - - v += 5; - break; - } - case ClassWriter.TYPE_INSN: - mv.visitTypeInsn(opcode, readClass(v + 1, c)); - v += 3; - break; - case ClassWriter.IINC_INSN: - mv.visitIincInsn(b[v + 1] & 0xFF, b[v + 2]); - v += 3; - break; - // case MANA_INSN: - default: - mv.visitMultiANewArrayInsn(readClass(v + 1, c), - b[v + 3] & 0xFF); - v += 4; - break; - } + // visits the instruction at this offset + int opcode = b[u] & 0xFF; + switch (ClassWriter.TYPE[opcode]) { + case ClassWriter.NOARG_INSN: + mv.visitInsn(opcode); + u += 1; + break; + case ClassWriter.IMPLVAR_INSN: + if (opcode > Opcodes.ISTORE) { + opcode -= 59; // ISTORE_0 + mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), + opcode & 0x3); + } else { + opcode -= 26; // ILOAD_0 + mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3); } - l = labels[codeEnd - codeStart]; - if (l != null) { - mv.visitLabel(l); + u += 1; + break; + case ClassWriter.LABEL_INSN: + mv.visitJumpInsn(opcode, labels[offset + readShort(u + 1)]); + u += 3; + break; + case ClassWriter.LABELW_INSN: + mv.visitJumpInsn(opcode - 33, labels[offset + readInt(u + 1)]); + u += 5; + break; + case ClassWriter.WIDE_INSN: + opcode = b[u + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + mv.visitIincInsn(readUnsignedShort(u + 2), readShort(u + 4)); + u += 6; + } else { + mv.visitVarInsn(opcode, readUnsignedShort(u + 2)); + u += 4; } - // visits the local variable tables - if (!skipDebug && varTable != 0) { - int[] typeTable = null; - if (varTypeTable != 0) { - k = readUnsignedShort(varTypeTable) * 3; - w = varTypeTable + 2; - typeTable = new int[k]; - while (k > 0) { - typeTable[--k] = w + 6; // signature - typeTable[--k] = readUnsignedShort(w + 8); // index - typeTable[--k] = readUnsignedShort(w); // start - w += 10; - } - } - k = readUnsignedShort(varTable); - w = varTable + 2; - for (; k > 0; --k) { - int start = readUnsignedShort(w); - int length = readUnsignedShort(w + 2); - int index = readUnsignedShort(w + 8); - String vsignature = null; - if (typeTable != null) { - for (int a = 0; a < typeTable.length; a += 3) { - if (typeTable[a] == start - && typeTable[a + 1] == index) - { - vsignature = readUTF8(typeTable[a + 2], c); - break; - } - } - } - mv.visitLocalVariable(readUTF8(w + 4, c), - readUTF8(w + 6, c), - vsignature, - labels[start], - labels[start + length], - index); - w += 10; - } + break; + case ClassWriter.TABL_INSN: { + // skips 0 to 3 padding bytes + u = u + 4 - (offset & 3); + // reads instruction + int label = offset + readInt(u); + int min = readInt(u + 4); + int max = readInt(u + 8); + Label[] table = new Label[max - min + 1]; + u += 12; + for (int i = 0; i < table.length; ++i) { + table[i] = labels[offset + readInt(u)]; + u += 4; + } + mv.visitTableSwitchInsn(min, max, labels[label], table); + break; + } + case ClassWriter.LOOK_INSN: { + // skips 0 to 3 padding bytes + u = u + 4 - (offset & 3); + // reads instruction + int label = offset + readInt(u); + int len = readInt(u + 4); + int[] keys = new int[len]; + Label[] values = new Label[len]; + u += 8; + for (int i = 0; i < len; ++i) { + keys[i] = readInt(u); + values[i] = labels[offset + readInt(u + 4)]; + u += 8; + } + mv.visitLookupSwitchInsn(labels[label], keys, values); + break; + } + case ClassWriter.VAR_INSN: + mv.visitVarInsn(opcode, b[u + 1] & 0xFF); + u += 2; + break; + case ClassWriter.SBYTE_INSN: + mv.visitIntInsn(opcode, b[u + 1]); + u += 2; + break; + case ClassWriter.SHORT_INSN: + mv.visitIntInsn(opcode, readShort(u + 1)); + u += 3; + break; + case ClassWriter.LDC_INSN: + mv.visitLdcInsn(readConst(b[u + 1] & 0xFF, c)); + u += 2; + break; + case ClassWriter.LDCW_INSN: + mv.visitLdcInsn(readConst(readUnsignedShort(u + 1), c)); + u += 3; + break; + case ClassWriter.FIELDORMETH_INSN: + case ClassWriter.ITFMETH_INSN: { + int cpIndex = items[readUnsignedShort(u + 1)]; + String iowner = readClass(cpIndex, c); + cpIndex = items[readUnsignedShort(cpIndex + 2)]; + String iname = readUTF8(cpIndex, c); + String idesc = readUTF8(cpIndex + 2, c); + if (opcode < Opcodes.INVOKEVIRTUAL) { + mv.visitFieldInsn(opcode, iowner, iname, idesc); + } else { + mv.visitMethodInsn(opcode, iowner, iname, idesc); } - // visits the other attributes - while (cattrs != null) { - attr = cattrs.next; - cattrs.next = null; - mv.visitAttribute(cattrs); - cattrs = attr; + if (opcode == Opcodes.INVOKEINTERFACE) { + u += 5; + } else { + u += 3; } - // visits the max stack and max locals values - mv.visitMaxs(maxStack, maxLocals); + break; } + case ClassWriter.INDYMETH_INSN: { + int cpIndex = items[readUnsignedShort(u + 1)]; + int bsmIndex = context.bootstrapMethods[readUnsignedShort(cpIndex)]; + Handle bsm = (Handle) readConst(readUnsignedShort(bsmIndex), c); + int bsmArgCount = readUnsignedShort(bsmIndex + 2); + Object[] bsmArgs = new Object[bsmArgCount]; + bsmIndex += 4; + for (int i = 0; i < bsmArgCount; i++) { + bsmArgs[i] = readConst(readUnsignedShort(bsmIndex), c); + bsmIndex += 2; + } + cpIndex = items[readUnsignedShort(cpIndex + 2)]; + String iname = readUTF8(cpIndex, c); + String idesc = readUTF8(cpIndex + 2, c); + mv.visitInvokeDynamicInsn(iname, idesc, bsm, bsmArgs); + u += 5; + break; + } + case ClassWriter.TYPE_INSN: + mv.visitTypeInsn(opcode, readClass(u + 1, c)); + u += 3; + break; + case ClassWriter.IINC_INSN: + mv.visitIincInsn(b[u + 1] & 0xFF, b[u + 2]); + u += 3; + break; + // case MANA_INSN: + default: + mv.visitMultiANewArrayInsn(readClass(u + 1, c), b[u + 3] & 0xFF); + u += 4; + break; + } + } + if (labels[codeLength] != null) { + mv.visitLabel(labels[codeLength]); + } - if (mv != null) { - mv.visitEnd(); + // visits the local variable tables + if ((context.flags & SKIP_DEBUG) == 0 && varTable != 0) { + int[] typeTable = null; + if (varTypeTable != 0) { + u = varTypeTable + 2; + typeTable = new int[readUnsignedShort(varTypeTable) * 3]; + for (int i = typeTable.length; i > 0;) { + typeTable[--i] = u + 6; // signature + typeTable[--i] = readUnsignedShort(u + 8); // index + typeTable[--i] = readUnsignedShort(u); // start + u += 10; + } + } + u = varTable + 2; + for (int i = readUnsignedShort(varTable); i > 0; --i) { + int start = readUnsignedShort(u); + int length = readUnsignedShort(u + 2); + int index = readUnsignedShort(u + 8); + String vsignature = null; + if (typeTable != null) { + for (int j = 0; j < typeTable.length; j += 3) { + if (typeTable[j] == start && typeTable[j + 1] == index) { + vsignature = readUTF8(typeTable[j + 2], c); + break; + } + } + } + mv.visitLocalVariable(readUTF8(u + 4, c), readUTF8(u + 6, c), + vsignature, labels[start], labels[start + length], + index); + u += 10; } } - // visits the end of the class - classVisitor.visitEnd(); + // visits the code attributes + while (attributes != null) { + Attribute attr = attributes.next; + attributes.next = null; + mv.visitAttribute(attributes); + attributes = attr; + } + + // visits the max stack and max locals values + mv.visitMaxs(maxStack, maxLocals); } /** * Reads parameter annotations and makes the given visitor visit them. * - * @param v start offset in {@link #b b} of the annotations to be read. - * @param desc the method descriptor. - * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, - * {@link #readClass(int,char[]) readClass} or - * {@link #readConst readConst}. - * @param visible <tt>true</tt> if the annotations to be read are visible - * at runtime. - * @param mv the visitor that must visit the annotations. + * @param v + * start offset in {@link #b b} of the annotations to be read. + * @param desc + * the method descriptor. + * @param buf + * buffer to be used to call {@link #readUTF8 readUTF8}, + * {@link #readClass(int,char[]) readClass} or {@link #readConst + * readConst}. + * @param visible + * <tt>true</tt> if the annotations to be read are visible at + * runtime. + * @param mv + * the visitor that must visit the annotations. */ - private void readParameterAnnotations( - int v, - final String desc, - final char[] buf, - final boolean visible, - final MethodVisitor mv) - { + private void readParameterAnnotations(int v, final String desc, + final char[] buf, final boolean visible, final MethodVisitor mv) { int i; int n = b[v++] & 0xFF; // workaround for a bug in javac (javac compiler generates a parameter @@ -1679,21 +1458,22 @@ public class ClassReader { /** * Reads the values of an annotation and makes the given visitor visit them. * - * @param v the start offset in {@link #b b} of the values to be read - * (including the unsigned short that gives the number of values). - * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, - * {@link #readClass(int,char[]) readClass} or - * {@link #readConst readConst}. - * @param named if the annotation values are named or not. - * @param av the visitor that must visit the values. + * @param v + * the start offset in {@link #b b} of the values to be read + * (including the unsigned short that gives the number of + * values). + * @param buf + * buffer to be used to call {@link #readUTF8 readUTF8}, + * {@link #readClass(int,char[]) readClass} or {@link #readConst + * readConst}. + * @param named + * if the annotation values are named or not. + * @param av + * the visitor that must visit the values. * @return the end offset of the annotation values. */ - private int readAnnotationValues( - int v, - final char[] buf, - final boolean named, - final AnnotationVisitor av) - { + private int readAnnotationValues(int v, final char[] buf, + final boolean named, final AnnotationVisitor av) { int i = readUnsignedShort(v); v += 2; if (named) { @@ -1714,210 +1494,371 @@ public class ClassReader { /** * Reads a value of an annotation and makes the given visitor visit it. * - * @param v the start offset in {@link #b b} of the value to be read (<i>not - * including the value name constant pool index</i>). - * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, - * {@link #readClass(int,char[]) readClass} or - * {@link #readConst readConst}. - * @param name the name of the value to be read. - * @param av the visitor that must visit the value. + * @param v + * the start offset in {@link #b b} of the value to be read + * (<i>not including the value name constant pool index</i>). + * @param buf + * buffer to be used to call {@link #readUTF8 readUTF8}, + * {@link #readClass(int,char[]) readClass} or {@link #readConst + * readConst}. + * @param name + * the name of the value to be read. + * @param av + * the visitor that must visit the value. * @return the end offset of the annotation value. */ - private int readAnnotationValue( - int v, - final char[] buf, - final String name, - final AnnotationVisitor av) - { + private int readAnnotationValue(int v, final char[] buf, final String name, + final AnnotationVisitor av) { int i; if (av == null) { switch (b[v] & 0xFF) { - case 'e': // enum_const_value - return v + 5; - case '@': // annotation_value - return readAnnotationValues(v + 3, buf, true, null); - case '[': // array_value - return readAnnotationValues(v + 1, buf, false, null); - default: - return v + 3; + case 'e': // enum_const_value + return v + 5; + case '@': // annotation_value + return readAnnotationValues(v + 3, buf, true, null); + case '[': // array_value + return readAnnotationValues(v + 1, buf, false, null); + default: + return v + 3; } } switch (b[v++] & 0xFF) { - case 'I': // pointer to CONSTANT_Integer - case 'J': // pointer to CONSTANT_Long - case 'F': // pointer to CONSTANT_Float - case 'D': // pointer to CONSTANT_Double - av.visit(name, readConst(readUnsignedShort(v), buf)); - v += 2; - break; - case 'B': // pointer to CONSTANT_Byte - av.visit(name, - new Byte((byte) readInt(items[readUnsignedShort(v)]))); - v += 2; - break; - case 'Z': // pointer to CONSTANT_Boolean - av.visit(name, readInt(items[readUnsignedShort(v)]) == 0 - ? Boolean.FALSE - : Boolean.TRUE); - v += 2; - break; - case 'S': // pointer to CONSTANT_Short - av.visit(name, - new Short((short) readInt(items[readUnsignedShort(v)]))); - v += 2; + case 'I': // pointer to CONSTANT_Integer + case 'J': // pointer to CONSTANT_Long + case 'F': // pointer to CONSTANT_Float + case 'D': // pointer to CONSTANT_Double + av.visit(name, readConst(readUnsignedShort(v), buf)); + v += 2; + break; + case 'B': // pointer to CONSTANT_Byte + av.visit(name, + new Byte((byte) readInt(items[readUnsignedShort(v)]))); + v += 2; + break; + case 'Z': // pointer to CONSTANT_Boolean + av.visit(name, + readInt(items[readUnsignedShort(v)]) == 0 ? Boolean.FALSE + : Boolean.TRUE); + v += 2; + break; + case 'S': // pointer to CONSTANT_Short + av.visit(name, new Short( + (short) readInt(items[readUnsignedShort(v)]))); + v += 2; + break; + case 'C': // pointer to CONSTANT_Char + av.visit(name, new Character( + (char) readInt(items[readUnsignedShort(v)]))); + v += 2; + break; + case 's': // pointer to CONSTANT_Utf8 + av.visit(name, readUTF8(v, buf)); + v += 2; + break; + case 'e': // enum_const_value + av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf)); + v += 4; + break; + case 'c': // class_info + av.visit(name, Type.getType(readUTF8(v, buf))); + v += 2; + break; + case '@': // annotation_value + v = readAnnotationValues(v + 2, buf, true, + av.visitAnnotation(name, readUTF8(v, buf))); + break; + case '[': // array_value + int size = readUnsignedShort(v); + v += 2; + if (size == 0) { + return readAnnotationValues(v - 2, buf, false, + av.visitArray(name)); + } + switch (this.b[v++] & 0xFF) { + case 'B': + byte[] bv = new byte[size]; + for (i = 0; i < size; i++) { + bv[i] = (byte) readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, bv); + --v; break; - case 'C': // pointer to CONSTANT_Char - av.visit(name, - new Character((char) readInt(items[readUnsignedShort(v)]))); - v += 2; + case 'Z': + boolean[] zv = new boolean[size]; + for (i = 0; i < size; i++) { + zv[i] = readInt(items[readUnsignedShort(v)]) != 0; + v += 3; + } + av.visit(name, zv); + --v; break; - case 's': // pointer to CONSTANT_Utf8 - av.visit(name, readUTF8(v, buf)); - v += 2; + case 'S': + short[] sv = new short[size]; + for (i = 0; i < size; i++) { + sv[i] = (short) readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, sv); + --v; break; - case 'e': // enum_const_value - av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf)); - v += 4; + case 'C': + char[] cv = new char[size]; + for (i = 0; i < size; i++) { + cv[i] = (char) readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, cv); + --v; break; - case 'c': // class_info - av.visit(name, Type.getType(readUTF8(v, buf))); - v += 2; + case 'I': + int[] iv = new int[size]; + for (i = 0; i < size; i++) { + iv[i] = readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, iv); + --v; break; - case '@': // annotation_value - v = readAnnotationValues(v + 2, - buf, - true, - av.visitAnnotation(name, readUTF8(v, buf))); + case 'J': + long[] lv = new long[size]; + for (i = 0; i < size; i++) { + lv[i] = readLong(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, lv); + --v; break; - case '[': // array_value - int size = readUnsignedShort(v); - v += 2; - if (size == 0) { - return readAnnotationValues(v - 2, - buf, - false, - av.visitArray(name)); + case 'F': + float[] fv = new float[size]; + for (i = 0; i < size; i++) { + fv[i] = Float + .intBitsToFloat(readInt(items[readUnsignedShort(v)])); + v += 3; } - switch (this.b[v++] & 0xFF) { - case 'B': - byte[] bv = new byte[size]; - for (i = 0; i < size; i++) { - bv[i] = (byte) readInt(items[readUnsignedShort(v)]); - v += 3; - } - av.visit(name, bv); - --v; - break; - case 'Z': - boolean[] zv = new boolean[size]; - for (i = 0; i < size; i++) { - zv[i] = readInt(items[readUnsignedShort(v)]) != 0; - v += 3; - } - av.visit(name, zv); - --v; - break; - case 'S': - short[] sv = new short[size]; - for (i = 0; i < size; i++) { - sv[i] = (short) readInt(items[readUnsignedShort(v)]); - v += 3; - } - av.visit(name, sv); - --v; - break; - case 'C': - char[] cv = new char[size]; - for (i = 0; i < size; i++) { - cv[i] = (char) readInt(items[readUnsignedShort(v)]); - v += 3; - } - av.visit(name, cv); - --v; - break; - case 'I': - int[] iv = new int[size]; - for (i = 0; i < size; i++) { - iv[i] = readInt(items[readUnsignedShort(v)]); - v += 3; - } - av.visit(name, iv); - --v; - break; - case 'J': - long[] lv = new long[size]; - for (i = 0; i < size; i++) { - lv[i] = readLong(items[readUnsignedShort(v)]); - v += 3; - } - av.visit(name, lv); - --v; - break; - case 'F': - float[] fv = new float[size]; - for (i = 0; i < size; i++) { - fv[i] = Float.intBitsToFloat(readInt(items[readUnsignedShort(v)])); - v += 3; - } - av.visit(name, fv); - --v; - break; - case 'D': - double[] dv = new double[size]; - for (i = 0; i < size; i++) { - dv[i] = Double.longBitsToDouble(readLong(items[readUnsignedShort(v)])); - v += 3; - } - av.visit(name, dv); - --v; - break; - default: - v = readAnnotationValues(v - 3, - buf, - false, - av.visitArray(name)); + av.visit(name, fv); + --v; + break; + case 'D': + double[] dv = new double[size]; + for (i = 0; i < size; i++) { + dv[i] = Double + .longBitsToDouble(readLong(items[readUnsignedShort(v)])); + v += 3; } + av.visit(name, dv); + --v; + break; + default: + v = readAnnotationValues(v - 3, buf, false, av.visitArray(name)); + } } return v; } - private int readFrameType( - final Object[] frame, - final int index, - int v, - final char[] buf, - final Label[] labels) - { - int type = b[v++] & 0xFF; - switch (type) { - case 0: - frame[index] = Opcodes.TOP; - break; - case 1: - frame[index] = Opcodes.INTEGER; - break; - case 2: - frame[index] = Opcodes.FLOAT; + /** + * Computes the implicit frame of the method currently being parsed (as + * defined in the given {@link Context}) and stores it in the given context. + * + * @param frame + * information about the class being parsed. + */ + private void getImplicitFrame(final Context frame) { + String desc = frame.desc; + Object[] locals = frame.local; + int local = 0; + if ((frame.access & Opcodes.ACC_STATIC) == 0) { + if ("<init>".equals(frame.name)) { + locals[local++] = Opcodes.UNINITIALIZED_THIS; + } else { + locals[local++] = readClass(header + 2, frame.buffer); + } + } + int i = 1; + loop: while (true) { + int j = i; + switch (desc.charAt(i++)) { + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + locals[local++] = Opcodes.INTEGER; break; - case 3: - frame[index] = Opcodes.DOUBLE; + case 'F': + locals[local++] = Opcodes.FLOAT; break; - case 4: - frame[index] = Opcodes.LONG; + case 'J': + locals[local++] = Opcodes.LONG; break; - case 5: - frame[index] = Opcodes.NULL; + case 'D': + locals[local++] = Opcodes.DOUBLE; break; - case 6: - frame[index] = Opcodes.UNINITIALIZED_THIS; + case '[': + while (desc.charAt(i) == '[') { + ++i; + } + if (desc.charAt(i) == 'L') { + ++i; + while (desc.charAt(i) != ';') { + ++i; + } + } + locals[local++] = desc.substring(j, ++i); break; - case 7: // Object - frame[index] = readClass(v, buf); - v += 2; + case 'L': + while (desc.charAt(i) != ';') { + ++i; + } + locals[local++] = desc.substring(j + 1, i++); break; - default: // Uninitialized - frame[index] = readLabel(readUnsignedShort(v), labels); - v += 2; + default: + break loop; + } + } + frame.localCount = local; + } + + /** + * Reads a stack map frame and stores the result in the given + * {@link Context} object. + * + * @param stackMap + * the start offset of a stack map frame in the class file. + * @param zip + * if the stack map frame at stackMap is compressed or not. + * @param unzip + * if the stack map frame must be uncompressed. + * @param labels + * the labels of the method currently being parsed, indexed by + * their offset. A new label for the parsed stack map frame is + * stored in this array if it does not already exist. + * @param frame + * where the parsed stack map frame must be stored. + * @return the offset of the first byte following the parsed frame. + */ + private int readFrame(int stackMap, boolean zip, boolean unzip, + Label[] labels, Context frame) { + char[] c = frame.buffer; + int tag; + int delta; + if (zip) { + tag = b[stackMap++] & 0xFF; + } else { + tag = MethodWriter.FULL_FRAME; + frame.offset = -1; + } + frame.localDiff = 0; + if (tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME) { + delta = tag; + frame.mode = Opcodes.F_SAME; + frame.stackCount = 0; + } else if (tag < MethodWriter.RESERVED) { + delta = tag - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME; + stackMap = readFrameType(frame.stack, 0, stackMap, c, labels); + frame.mode = Opcodes.F_SAME1; + frame.stackCount = 1; + } else { + delta = readUnsignedShort(stackMap); + stackMap += 2; + if (tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { + stackMap = readFrameType(frame.stack, 0, stackMap, c, labels); + frame.mode = Opcodes.F_SAME1; + frame.stackCount = 1; + } else if (tag >= MethodWriter.CHOP_FRAME + && tag < MethodWriter.SAME_FRAME_EXTENDED) { + frame.mode = Opcodes.F_CHOP; + frame.localDiff = MethodWriter.SAME_FRAME_EXTENDED - tag; + frame.localCount -= frame.localDiff; + frame.stackCount = 0; + } else if (tag == MethodWriter.SAME_FRAME_EXTENDED) { + frame.mode = Opcodes.F_SAME; + frame.stackCount = 0; + } else if (tag < MethodWriter.FULL_FRAME) { + int local = unzip ? frame.localCount : 0; + for (int i = tag - MethodWriter.SAME_FRAME_EXTENDED; i > 0; i--) { + stackMap = readFrameType(frame.local, local++, stackMap, c, + labels); + } + frame.mode = Opcodes.F_APPEND; + frame.localDiff = tag - MethodWriter.SAME_FRAME_EXTENDED; + frame.localCount += frame.localDiff; + frame.stackCount = 0; + } else { // if (tag == FULL_FRAME) { + frame.mode = Opcodes.F_FULL; + int n = readUnsignedShort(stackMap); + stackMap += 2; + frame.localDiff = n; + frame.localCount = n; + for (int local = 0; n > 0; n--) { + stackMap = readFrameType(frame.local, local++, stackMap, c, + labels); + } + n = readUnsignedShort(stackMap); + stackMap += 2; + frame.stackCount = n; + for (int stack = 0; n > 0; n--) { + stackMap = readFrameType(frame.stack, stack++, stackMap, c, + labels); + } + } + } + frame.offset += delta + 1; + readLabel(frame.offset, labels); + return stackMap; + } + + /** + * Reads a stack map frame type and stores it at the given index in the + * given array. + * + * @param frame + * the array where the parsed type must be stored. + * @param index + * the index in 'frame' where the parsed type must be stored. + * @param v + * the start offset of the stack map frame type to read. + * @param buf + * a buffer to read strings. + * @param labels + * the labels of the method currently being parsed, indexed by + * their offset. If the parsed type is an Uninitialized type, a + * new label for the corresponding NEW instruction is stored in + * this array if it does not already exist. + * @return the offset of the first byte after the parsed type. + */ + private int readFrameType(final Object[] frame, final int index, int v, + final char[] buf, final Label[] labels) { + int type = b[v++] & 0xFF; + switch (type) { + case 0: + frame[index] = Opcodes.TOP; + break; + case 1: + frame[index] = Opcodes.INTEGER; + break; + case 2: + frame[index] = Opcodes.FLOAT; + break; + case 3: + frame[index] = Opcodes.DOUBLE; + break; + case 4: + frame[index] = Opcodes.LONG; + break; + case 5: + frame[index] = Opcodes.NULL; + break; + case 6: + frame[index] = Opcodes.UNINITIALIZED_THIS; + break; + case 7: // Object + frame[index] = readClass(v, buf); + v += 2; + break; + default: // Uninitialized + frame[index] = readLabel(readUnsignedShort(v), labels); + v += 2; } return v; } @@ -1927,10 +1868,12 @@ public class ClassReader { * implementation of this method creates a label for the given offset if it * has not been already created. * - * @param offset a bytecode offset in a method. - * @param labels the already created labels, indexed by their offset. If a - * label already exists for offset this method must not create a new - * one. Otherwise it must store the new label in this array. + * @param offset + * a bytecode offset in a method. + * @param labels + * the already created labels, indexed by their offset. If a + * label already exists for offset this method must not create a + * new one. Otherwise it must store the new label in this array. * @return a non null Label, which must be equal to labels[offset]. */ protected Label readLabel(int offset, Label[] labels) { @@ -1941,39 +1884,67 @@ public class ClassReader { } /** + * Returns the start index of the attribute_info structure of this class. + * + * @return the start index of the attribute_info structure of this class. + */ + private int getAttributes() { + // skips the header + int u = header + 8 + readUnsignedShort(header + 6) * 2; + // skips fields and methods + for (int i = readUnsignedShort(u); i > 0; --i) { + for (int j = readUnsignedShort(u + 8); j > 0; --j) { + u += 6 + readInt(u + 12); + } + u += 8; + } + u += 2; + for (int i = readUnsignedShort(u); i > 0; --i) { + for (int j = readUnsignedShort(u + 8); j > 0; --j) { + u += 6 + readInt(u + 12); + } + u += 8; + } + // the attribute_info structure starts just after the methods + return u + 2; + } + + /** * Reads an attribute in {@link #b b}. * - * @param attrs prototypes of the attributes that must be parsed during the - * visit of the class. Any attribute whose type is not equal to the - * type of one the prototypes is ignored (i.e. an empty - * {@link Attribute} instance is returned). - * @param type the type of the attribute. - * @param off index of the first byte of the attribute's content in - * {@link #b b}. The 6 attribute header bytes, containing the type - * and the length of the attribute, are not taken into account here - * (they have already been read). - * @param len the length of the attribute's content. - * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, - * {@link #readClass(int,char[]) readClass} or - * {@link #readConst readConst}. - * @param codeOff index of the first byte of code's attribute content in - * {@link #b b}, or -1 if the attribute to be read is not a code - * attribute. The 6 attribute header bytes, containing the type and - * the length of the attribute, are not taken into account here. - * @param labels the labels of the method's code, or <tt>null</tt> if the - * attribute to be read is not a code attribute. + * @param attrs + * prototypes of the attributes that must be parsed during the + * visit of the class. Any attribute whose type is not equal to + * the type of one the prototypes is ignored (i.e. an empty + * {@link Attribute} instance is returned). + * @param type + * the type of the attribute. + * @param off + * index of the first byte of the attribute's content in + * {@link #b b}. The 6 attribute header bytes, containing the + * type and the length of the attribute, are not taken into + * account here (they have already been read). + * @param len + * the length of the attribute's content. + * @param buf + * buffer to be used to call {@link #readUTF8 readUTF8}, + * {@link #readClass(int,char[]) readClass} or {@link #readConst + * readConst}. + * @param codeOff + * index of the first byte of code's attribute content in + * {@link #b b}, or -1 if the attribute to be read is not a code + * attribute. The 6 attribute header bytes, containing the type + * and the length of the attribute, are not taken into account + * here. + * @param labels + * the labels of the method's code, or <tt>null</tt> if the + * attribute to be read is not a code attribute. * @return the attribute that has been read, or <tt>null</tt> to skip this * attribute. */ - private Attribute readAttribute( - final Attribute[] attrs, - final String type, - final int off, - final int len, - final char[] buf, - final int codeOff, - final Label[] labels) - { + private Attribute readAttribute(final Attribute[] attrs, final String type, + final int off, final int len, final char[] buf, final int codeOff, + final Label[] labels) { for (int i = 0; i < attrs.length; ++i) { if (attrs[i].type.equals(type)) { return attrs[i].read(this, off, len, buf, codeOff, labels); @@ -1987,9 +1958,9 @@ public class ClassReader { // ------------------------------------------------------------------------ /** - * Returns the number of constant pool items in {@link #b b}. + * Returns the number of constant pool items in {@link #b b}. * - * @return the number of constant pool items in {@link #b b}. + * @return the number of constant pool items in {@link #b b}. */ public int getItemCount() { return items.length; @@ -2000,7 +1971,8 @@ public class ClassReader { * one. <i>This method is intended for {@link Attribute} sub classes, and is * normally not needed by class generators or adapters.</i> * - * @param item the index a constant pool item. + * @param item + * the index a constant pool item. * @return the start index of the constant pool item in {@link #b b}, plus * one. */ @@ -2024,7 +1996,8 @@ public class ClassReader { * {@link Attribute} sub classes, and is normally not needed by class * generators or adapters.</i> * - * @param index the start index of the value to be read in {@link #b b}. + * @param index + * the start index of the value to be read in {@link #b b}. * @return the read value. */ public int readByte(final int index) { @@ -2032,11 +2005,12 @@ public class ClassReader { } /** - * Reads an unsigned short value in {@link #b b}. <i>This method is - * intended for {@link Attribute} sub classes, and is normally not needed by - * class generators or adapters.</i> + * Reads an unsigned short value in {@link #b b}. <i>This method is intended + * for {@link Attribute} sub classes, and is normally not needed by class + * generators or adapters.</i> * - * @param index the start index of the value to be read in {@link #b b}. + * @param index + * the start index of the value to be read in {@link #b b}. * @return the read value. */ public int readUnsignedShort(final int index) { @@ -2049,7 +2023,8 @@ public class ClassReader { * for {@link Attribute} sub classes, and is normally not needed by class * generators or adapters.</i> * - * @param index the start index of the value to be read in {@link #b b}. + * @param index + * the start index of the value to be read in {@link #b b}. * @return the read value. */ public short readShort(final int index) { @@ -2062,7 +2037,8 @@ public class ClassReader { * {@link Attribute} sub classes, and is normally not needed by class * generators or adapters.</i> * - * @param index the start index of the value to be read in {@link #b b}. + * @param index + * the start index of the value to be read in {@link #b b}. * @return the read value. */ public int readInt(final int index) { @@ -2072,11 +2048,12 @@ public class ClassReader { } /** - * Reads a signed long value in {@link #b b}. <i>This method is intended - * for {@link Attribute} sub classes, and is normally not needed by class + * Reads a signed long value in {@link #b b}. <i>This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class * generators or adapters.</i> * - * @param index the start index of the value to be read in {@link #b b}. + * @param index + * the start index of the value to be read in {@link #b b}. * @return the read value. */ public long readLong(final int index) { @@ -2090,14 +2067,19 @@ public class ClassReader { * is intended for {@link Attribute} sub classes, and is normally not needed * by class generators or adapters.</i> * - * @param index the start index of an unsigned short value in {@link #b b}, - * whose value is the index of an UTF8 constant pool item. - * @param buf buffer to be used to read the item. This buffer must be - * sufficiently large. It is not automatically resized. + * @param index + * the start index of an unsigned short value in {@link #b b}, + * whose value is the index of an UTF8 constant pool item. + * @param buf + * buffer to be used to read the item. This buffer must be + * sufficiently large. It is not automatically resized. * @return the String corresponding to the specified UTF8 item. */ public String readUTF8(int index, final char[] buf) { int item = readUnsignedShort(index); + if (index == 0 || item == 0) { + return null; + } String s = strings[item]; if (s != null) { return s; @@ -2109,10 +2091,13 @@ public class ClassReader { /** * Reads UTF8 string in {@link #b b}. * - * @param index start offset of the UTF8 string to be read. - * @param utfLen length of the UTF8 string to be read. - * @param buf buffer to be used to read the string. This buffer must be - * sufficiently large. It is not automatically resized. + * @param index + * start offset of the UTF8 string to be read. + * @param utfLen + * length of the UTF8 string to be read. + * @param buf + * buffer to be used to read the string. This buffer must be + * sufficiently large. It is not automatically resized. * @return the String corresponding to the specified UTF8 string. */ private String readUTF(int index, final int utfLen, final char[] buf) { @@ -2125,28 +2110,28 @@ public class ClassReader { while (index < endIndex) { c = b[index++]; switch (st) { - case 0: - c = c & 0xFF; - if (c < 0x80) { // 0xxxxxxx - buf[strLen++] = (char) c; - } else if (c < 0xE0 && c > 0xBF) { // 110x xxxx 10xx xxxx - cc = (char) (c & 0x1F); - st = 1; - } else { // 1110 xxxx 10xx xxxx 10xx xxxx - cc = (char) (c & 0x0F); - st = 2; - } - break; + case 0: + c = c & 0xFF; + if (c < 0x80) { // 0xxxxxxx + buf[strLen++] = (char) c; + } else if (c < 0xE0 && c > 0xBF) { // 110x xxxx 10xx xxxx + cc = (char) (c & 0x1F); + st = 1; + } else { // 1110 xxxx 10xx xxxx 10xx xxxx + cc = (char) (c & 0x0F); + st = 2; + } + break; - case 1: // byte 2 of 2-byte char or byte 3 of 3-byte char - buf[strLen++] = (char) ((cc << 6) | (c & 0x3F)); - st = 0; - break; + case 1: // byte 2 of 2-byte char or byte 3 of 3-byte char + buf[strLen++] = (char) ((cc << 6) | (c & 0x3F)); + st = 0; + break; - case 2: // byte 2 of 3-byte char - cc = (char) ((cc << 6) | (c & 0x3F)); - st = 1; - break; + case 2: // byte 2 of 3-byte char + cc = (char) ((cc << 6) | (c & 0x3F)); + st = 1; + break; } } return new String(buf, 0, strLen); @@ -2157,10 +2142,12 @@ public class ClassReader { * intended for {@link Attribute} sub classes, and is normally not needed by * class generators or adapters.</i> * - * @param index the start index of an unsigned short value in {@link #b b}, - * whose value is the index of a class constant pool item. - * @param buf buffer to be used to read the item. This buffer must be - * sufficiently large. It is not automatically resized. + * @param index + * the start index of an unsigned short value in {@link #b b}, + * whose value is the index of a class constant pool item. + * @param buf + * buffer to be used to read the item. This buffer must be + * sufficiently large. It is not automatically resized. * @return the String corresponding to the specified class item. */ public String readClass(final int index, final char[] buf) { @@ -2175,9 +2162,11 @@ public class ClassReader { * method is intended for {@link Attribute} sub classes, and is normally not * needed by class generators or adapters.</i> * - * @param item the index of a constant pool item. - * @param buf buffer to be used to read the item. This buffer must be - * sufficiently large. It is not automatically resized. + * @param item + * the index of a constant pool item. + * @param buf + * buffer to be used to read the item. This buffer must be + * sufficiently large. It is not automatically resized. * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, * {@link String}, {@link Type} or {@link Handle} corresponding to * the given constant pool item. @@ -2185,32 +2174,29 @@ public class ClassReader { public Object readConst(final int item, final char[] buf) { int index = items[item]; switch (b[index - 1]) { - case ClassWriter.INT: - return new Integer(readInt(index)); - case ClassWriter.FLOAT: - return new Float(Float.intBitsToFloat(readInt(index))); - case ClassWriter.LONG: - return new Long(readLong(index)); - case ClassWriter.DOUBLE: - return new Double(Double.longBitsToDouble(readLong(index))); - case ClassWriter.CLASS: - return Type.getObjectType(readUTF8(index, buf)); - case ClassWriter.STR: - return readUTF8(index, buf); - case ClassWriter.MTYPE: - return Type.getMethodType(readUTF8(index, buf)); - - //case ClassWriter.HANDLE_BASE + [1..9]: - default: { - int tag = readByte(index); - int[] items = this.items; - int cpIndex = items[readUnsignedShort(index + 1)]; - String owner = readClass(cpIndex, buf); - cpIndex = items[readUnsignedShort(cpIndex + 2)]; - String name = readUTF8(cpIndex, buf); - String desc = readUTF8(cpIndex + 2, buf); - return new Handle(tag, owner, name, desc); - } + case ClassWriter.INT: + return new Integer(readInt(index)); + case ClassWriter.FLOAT: + return new Float(Float.intBitsToFloat(readInt(index))); + case ClassWriter.LONG: + return new Long(readLong(index)); + case ClassWriter.DOUBLE: + return new Double(Double.longBitsToDouble(readLong(index))); + case ClassWriter.CLASS: + return Type.getObjectType(readUTF8(index, buf)); + case ClassWriter.STR: + return readUTF8(index, buf); + case ClassWriter.MTYPE: + return Type.getMethodType(readUTF8(index, buf)); + default: // case ClassWriter.HANDLE_BASE + [1..9]: + int tag = readByte(index); + int[] items = this.items; + int cpIndex = items[readUnsignedShort(index + 1)]; + String owner = readClass(cpIndex, buf); + cpIndex = items[readUnsignedShort(cpIndex + 2)]; + String name = readUTF8(cpIndex, buf); + String desc = readUTF8(cpIndex + 2, buf); + return new Handle(tag, owner, name, desc); } } } diff --git a/src/asm/scala/tools/asm/ClassVisitor.java b/src/asm/scala/tools/asm/ClassVisitor.java index ae38ae0ab9..3fc364d5e5 100644 --- a/src/asm/scala/tools/asm/ClassVisitor.java +++ b/src/asm/scala/tools/asm/ClassVisitor.java @@ -30,11 +30,11 @@ package scala.tools.asm; /** - * A visitor to visit a Java class. The methods of this class must be called - * in the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [ + * A visitor to visit a Java class. The methods of this class must be called in + * the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [ * <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> | - * <tt>visitAttribute</tt> )* ( <tt>visitInnerClass</tt> | - * <tt>visitField</tt> | <tt>visitMethod</tt> )* <tt>visitEnd</tt>. + * <tt>visitAttribute</tt> )* ( <tt>visitInnerClass</tt> | <tt>visitField</tt> | + * <tt>visitMethod</tt> )* <tt>visitEnd</tt>. * * @author Eric Bruneton */ @@ -55,8 +55,9 @@ public abstract class ClassVisitor { /** * Constructs a new {@link ClassVisitor}. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. */ public ClassVisitor(final int api) { this(api, null); @@ -65,15 +66,17 @@ public abstract class ClassVisitor { /** * Constructs a new {@link ClassVisitor}. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. - * @param cv the class visitor to which this visitor must delegate method - * calls. May be null. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param cv + * the class visitor to which this visitor must delegate method + * calls. May be null. */ public ClassVisitor(final int api, final ClassVisitor cv) { - /*if (api != Opcodes.ASM4) { + if (api != Opcodes.ASM4) { throw new IllegalArgumentException(); - }*/ + } this.api = api; this.cv = cv; } @@ -81,30 +84,30 @@ public abstract class ClassVisitor { /** * Visits the header of the class. * - * @param version the class version. - * @param access the class's access flags (see {@link Opcodes}). This - * parameter also indicates if the class is deprecated. - * @param name the internal name of the class (see - * {@link Type#getInternalName() getInternalName}). - * @param signature the signature of this class. May be <tt>null</tt> if - * the class is not a generic one, and does not extend or implement - * generic classes or interfaces. - * @param superName the internal of name of the super class (see - * {@link Type#getInternalName() getInternalName}). For interfaces, - * the super class is {@link Object}. May be <tt>null</tt>, but - * only for the {@link Object} class. - * @param interfaces the internal names of the class's interfaces (see - * {@link Type#getInternalName() getInternalName}). May be - * <tt>null</tt>. + * @param version + * the class version. + * @param access + * the class's access flags (see {@link Opcodes}). This parameter + * also indicates if the class is deprecated. + * @param name + * the internal name of the class (see + * {@link Type#getInternalName() getInternalName}). + * @param signature + * the signature of this class. May be <tt>null</tt> if the class + * is not a generic one, and does not extend or implement generic + * classes or interfaces. + * @param superName + * the internal of name of the super class (see + * {@link Type#getInternalName() getInternalName}). For + * interfaces, the super class is {@link Object}. May be + * <tt>null</tt>, but only for the {@link Object} class. + * @param interfaces + * the internal names of the class's interfaces (see + * {@link Type#getInternalName() getInternalName}). May be + * <tt>null</tt>. */ - public void visit( - int version, - int access, - String name, - String signature, - String superName, - String[] interfaces) - { + public void visit(int version, int access, String name, String signature, + String superName, String[] interfaces) { if (cv != null) { cv.visit(version, access, name, signature, superName, interfaces); } @@ -113,11 +116,13 @@ public abstract class ClassVisitor { /** * Visits the source of the class. * - * @param source the name of the source file from which the class was - * compiled. May be <tt>null</tt>. - * @param debug additional debug information to compute the correspondance - * between source and compiled elements of the class. May be - * <tt>null</tt>. + * @param source + * the name of the source file from which the class was compiled. + * May be <tt>null</tt>. + * @param debug + * additional debug information to compute the correspondance + * between source and compiled elements of the class. May be + * <tt>null</tt>. */ public void visitSource(String source, String debug) { if (cv != null) { @@ -129,16 +134,19 @@ public abstract class ClassVisitor { * Visits the enclosing class of the class. This method must be called only * if the class has an enclosing class. * - * @param owner internal name of the enclosing class of the class. - * @param name the name of the method that contains the class, or - * <tt>null</tt> if the class is not enclosed in a method of its - * enclosing class. - * @param desc the descriptor of the method that contains the class, or - * <tt>null</tt> if the class is not enclosed in a method of its - * enclosing class. + * @param owner + * internal name of the enclosing class of the class. + * @param name + * the name of the method that contains the class, or + * <tt>null</tt> if the class is not enclosed in a method of its + * enclosing class. + * @param desc + * the descriptor of the method that contains the class, or + * <tt>null</tt> if the class is not enclosed in a method of its + * enclosing class. */ public void visitOuterClass(String owner, String name, String desc) { - if (cv != null) { + if (cv != null) { cv.visitOuterClass(owner, name, desc); } } @@ -146,8 +154,10 @@ public abstract class ClassVisitor { /** * Visits an annotation of the class. * - * @param desc the class descriptor of the annotation class. - * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * <tt>true</tt> if the annotation is visible at runtime. * @return a visitor to visit the annotation values, or <tt>null</tt> if * this visitor is not interested in visiting this annotation. */ @@ -161,7 +171,8 @@ public abstract class ClassVisitor { /** * Visits a non standard attribute of the class. * - * @param attr an attribute. + * @param attr + * an attribute. */ public void visitAttribute(Attribute attr) { if (cv != null) { @@ -173,23 +184,22 @@ public abstract class ClassVisitor { * Visits information about an inner class. This inner class is not * necessarily a member of the class being visited. * - * @param name the internal name of an inner class (see - * {@link Type#getInternalName() getInternalName}). - * @param outerName the internal name of the class to which the inner class - * belongs (see {@link Type#getInternalName() getInternalName}). May - * be <tt>null</tt> for not member classes. - * @param innerName the (simple) name of the inner class inside its - * enclosing class. May be <tt>null</tt> for anonymous inner - * classes. - * @param access the access flags of the inner class as originally declared - * in the enclosing class. + * @param name + * the internal name of an inner class (see + * {@link Type#getInternalName() getInternalName}). + * @param outerName + * the internal name of the class to which the inner class + * belongs (see {@link Type#getInternalName() getInternalName}). + * May be <tt>null</tt> for not member classes. + * @param innerName + * the (simple) name of the inner class inside its enclosing + * class. May be <tt>null</tt> for anonymous inner classes. + * @param access + * the access flags of the inner class as originally declared in + * the enclosing class. */ - public void visitInnerClass( - String name, - String outerName, - String innerName, - int access) - { + public void visitInnerClass(String name, String outerName, + String innerName, int access) { if (cv != null) { cv.visitInnerClass(name, outerName, innerName, access); } @@ -198,33 +208,32 @@ public abstract class ClassVisitor { /** * Visits a field of the class. * - * @param access the field's access flags (see {@link Opcodes}). This - * parameter also indicates if the field is synthetic and/or - * deprecated. - * @param name the field's name. - * @param desc the field's descriptor (see {@link Type Type}). - * @param signature the field's signature. May be <tt>null</tt> if the - * field's type does not use generic types. - * @param value the field's initial value. This parameter, which may be - * <tt>null</tt> if the field does not have an initial value, must - * be an {@link Integer}, a {@link Float}, a {@link Long}, a - * {@link Double} or a {@link String} (for <tt>int</tt>, - * <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields - * respectively). <i>This parameter is only used for static fields</i>. - * Its value is ignored for non static fields, which must be - * initialized through bytecode instructions in constructors or - * methods. + * @param access + * the field's access flags (see {@link Opcodes}). This parameter + * also indicates if the field is synthetic and/or deprecated. + * @param name + * the field's name. + * @param desc + * the field's descriptor (see {@link Type Type}). + * @param signature + * the field's signature. May be <tt>null</tt> if the field's + * type does not use generic types. + * @param value + * the field's initial value. This parameter, which may be + * <tt>null</tt> if the field does not have an initial value, + * must be an {@link Integer}, a {@link Float}, a {@link Long}, a + * {@link Double} or a {@link String} (for <tt>int</tt>, + * <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields + * respectively). <i>This parameter is only used for static + * fields</i>. Its value is ignored for non static fields, which + * must be initialized through bytecode instructions in + * constructors or methods. * @return a visitor to visit field annotations and attributes, or - * <tt>null</tt> if this class visitor is not interested in - * visiting these annotations and attributes. + * <tt>null</tt> if this class visitor is not interested in visiting + * these annotations and attributes. */ - public FieldVisitor visitField( - int access, - String name, - String desc, - String signature, - Object value) - { + public FieldVisitor visitField(int access, String name, String desc, + String signature, Object value) { if (cv != null) { return cv.visitField(access, name, desc, signature, value); } @@ -233,31 +242,31 @@ public abstract class ClassVisitor { /** * Visits a method of the class. This method <i>must</i> return a new - * {@link MethodVisitor} instance (or <tt>null</tt>) each time it is - * called, i.e., it should not return a previously returned visitor. + * {@link MethodVisitor} instance (or <tt>null</tt>) each time it is called, + * i.e., it should not return a previously returned visitor. * - * @param access the method's access flags (see {@link Opcodes}). This - * parameter also indicates if the method is synthetic and/or - * deprecated. - * @param name the method's name. - * @param desc the method's descriptor (see {@link Type Type}). - * @param signature the method's signature. May be <tt>null</tt> if the - * method parameters, return type and exceptions do not use generic - * types. - * @param exceptions the internal names of the method's exception classes - * (see {@link Type#getInternalName() getInternalName}). May be - * <tt>null</tt>. + * @param access + * the method's access flags (see {@link Opcodes}). This + * parameter also indicates if the method is synthetic and/or + * deprecated. + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link Type Type}). + * @param signature + * the method's signature. May be <tt>null</tt> if the method + * parameters, return type and exceptions do not use generic + * types. + * @param exceptions + * the internal names of the method's exception classes (see + * {@link Type#getInternalName() getInternalName}). May be + * <tt>null</tt>. * @return an object to visit the byte code of the method, or <tt>null</tt> * if this class visitor is not interested in visiting the code of * this method. */ - public MethodVisitor visitMethod( - int access, - String name, - String desc, - String signature, - String[] exceptions) - { + public MethodVisitor visitMethod(int access, String name, String desc, + String signature, String[] exceptions) { if (cv != null) { return cv.visitMethod(access, name, desc, signature, exceptions); } diff --git a/src/asm/scala/tools/asm/ClassWriter.java b/src/asm/scala/tools/asm/ClassWriter.java index c7a0736b51..93ed7313c7 100644 --- a/src/asm/scala/tools/asm/ClassWriter.java +++ b/src/asm/scala/tools/asm/ClassWriter.java @@ -66,12 +66,18 @@ public class ClassWriter extends ClassVisitor { public static final int COMPUTE_FRAMES = 2; /** - * Pseudo access flag to distinguish between the synthetic attribute and - * the synthetic access flag. + * Pseudo access flag to distinguish between the synthetic attribute and the + * synthetic access flag. */ static final int ACC_SYNTHETIC_ATTRIBUTE = 0x40000; /** + * Factor to convert from ACC_SYNTHETIC_ATTRIBUTE to Opcode.ACC_SYNTHETIC. + */ + static final int TO_ACC_SYNTHETIC = ACC_SYNTHETIC_ATTRIBUTE + / Opcodes.ACC_SYNTHETIC; + + /** * The type of instructions without any argument. */ static final int NOARG_INSN = 0; @@ -238,8 +244,8 @@ public class ClassWriter extends ClassVisitor { /** * The base value for all CONSTANT_MethodHandle constant pool items. - * Internally, ASM store the 9 variations of CONSTANT_MethodHandle into - * 9 different items. + * Internally, ASM store the 9 variations of CONSTANT_MethodHandle into 9 + * different items. */ static final int HANDLE_BASE = 20; @@ -266,9 +272,8 @@ public class ClassWriter extends ClassVisitor { static final int TYPE_MERGED = 32; /** - * The type of BootstrapMethods items. These items are stored in a - * special class attribute named BootstrapMethods and - * not in the constant pool. + * The type of BootstrapMethods items. These items are stored in a special + * class attribute named BootstrapMethods and not in the constant pool. */ static final int BSM = 33; @@ -327,10 +332,10 @@ public class ClassWriter extends ClassVisitor { * necessarily be stored in the constant pool. This type table is used by * the control flow and data flow analysis algorithm used to compute stack * map frames from scratch. This array associates to each index <tt>i</tt> - * the Item whose index is <tt>i</tt>. All Item objects stored in this - * array are also stored in the {@link #items} hash table. These two arrays - * allow to retrieve an Item from its index or, conversely, to get the index - * of an Item from its value. Each Item stores an internal name in its + * the Item whose index is <tt>i</tt>. All Item objects stored in this array + * are also stored in the {@link #items} hash table. These two arrays allow + * to retrieve an Item from its index or, conversely, to get the index of an + * Item from its value. Each Item stores an internal name in its * {@link Item#strVal1} field. */ Item[] typeTable; @@ -439,16 +444,16 @@ public class ClassWriter extends ClassVisitor { /** * The fields of this class. These fields are stored in a linked list of * {@link FieldWriter} objects, linked to each other by their - * {@link FieldWriter#fv} field. This field stores the first element of - * this list. + * {@link FieldWriter#fv} field. This field stores the first element of this + * list. */ FieldWriter firstField; /** * The fields of this class. These fields are stored in a linked list of * {@link FieldWriter} objects, linked to each other by their - * {@link FieldWriter#fv} field. This field stores the last element of - * this list. + * {@link FieldWriter#fv} field. This field stores the last element of this + * list. */ FieldWriter lastField; @@ -463,8 +468,8 @@ public class ClassWriter extends ClassVisitor { /** * The methods of this class. These methods are stored in a linked list of * {@link MethodWriter} objects, linked to each other by their - * {@link MethodWriter#mv} field. This field stores the last element of - * this list. + * {@link MethodWriter#mv} field. This field stores the last element of this + * list. */ MethodWriter lastMethod; @@ -584,8 +589,10 @@ public class ClassWriter extends ClassVisitor { /** * Constructs a new {@link ClassWriter} object. * - * @param flags option flags that can be used to modify the default behavior - * of this class. See {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}. + * @param flags + * option flags that can be used to modify the default behavior + * of this class. See {@link #COMPUTE_MAXS}, + * {@link #COMPUTE_FRAMES}. */ public ClassWriter(final int flags) { super(Opcodes.ASM4); @@ -606,26 +613,32 @@ public class ClassWriter extends ClassVisitor { * "mostly add" bytecode transformations. These optimizations are the * following: * - * <ul> <li>The constant pool from the original class is copied as is in the - * new class, which saves time. New constant pool entries will be added at - * the end if necessary, but unused constant pool entries <i>won't be - * removed</i>.</li> <li>Methods that are not transformed are copied as is - * in the new class, directly from the original class bytecode (i.e. without - * emitting visit events for all the method instructions), which saves a - * <i>lot</i> of time. Untransformed methods are detected by the fact that - * the {@link ClassReader} receives {@link MethodVisitor} objects that come - * from a {@link ClassWriter} (and not from any other {@link ClassVisitor} - * instance).</li> </ul> + * <ul> + * <li>The constant pool from the original class is copied as is in the new + * class, which saves time. New constant pool entries will be added at the + * end if necessary, but unused constant pool entries <i>won't be + * removed</i>.</li> + * <li>Methods that are not transformed are copied as is in the new class, + * directly from the original class bytecode (i.e. without emitting visit + * events for all the method instructions), which saves a <i>lot</i> of + * time. Untransformed methods are detected by the fact that the + * {@link ClassReader} receives {@link MethodVisitor} objects that come from + * a {@link ClassWriter} (and not from any other {@link ClassVisitor} + * instance).</li> + * </ul> * - * @param classReader the {@link ClassReader} used to read the original - * class. It will be used to copy the entire constant pool from the - * original class and also to copy other fragments of original - * bytecode where applicable. - * @param flags option flags that can be used to modify the default behavior - * of this class. <i>These option flags do not affect methods that - * are copied as is in the new class. This means that the maximum - * stack size nor the stack frames will be computed for these - * methods</i>. See {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}. + * @param classReader + * the {@link ClassReader} used to read the original class. It + * will be used to copy the entire constant pool from the + * original class and also to copy other fragments of original + * bytecode where applicable. + * @param flags + * option flags that can be used to modify the default behavior + * of this class. <i>These option flags do not affect methods + * that are copied as is in the new class. This means that the + * maximum stack size nor the stack frames will be computed for + * these methods</i>. See {@link #COMPUTE_MAXS}, + * {@link #COMPUTE_FRAMES}. */ public ClassWriter(final ClassReader classReader, final int flags) { this(flags); @@ -638,14 +651,9 @@ public class ClassWriter extends ClassVisitor { // ------------------------------------------------------------------------ @Override - public final void visit( - final int version, - final int access, - final String name, - final String signature, - final String superName, - final String[] interfaces) - { + public final void visit(final int version, final int access, + final String name, final String signature, final String superName, + final String[] interfaces) { this.version = version; this.access = access; this.name = newClass(name); @@ -674,11 +682,8 @@ public class ClassWriter extends ClassVisitor { } @Override - public final void visitOuterClass( - final String owner, - final String name, - final String desc) - { + public final void visitOuterClass(final String owner, final String name, + final String desc) { enclosingMethodOwner = newClass(owner); if (name != null && desc != null) { enclosingMethod = newNameType(name, desc); @@ -686,10 +691,8 @@ public class ClassWriter extends ClassVisitor { } @Override - public final AnnotationVisitor visitAnnotation( - final String desc, - final boolean visible) - { + public final AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { if (!ClassReader.ANNOTATIONS) { return null; } @@ -714,12 +717,8 @@ public class ClassWriter extends ClassVisitor { } @Override - public final void visitInnerClass( - final String name, - final String outerName, - final String innerName, - final int access) - { + public final void visitInnerClass(final String name, + final String outerName, final String innerName, final int access) { if (innerClasses == null) { innerClasses = new ByteVector(); } @@ -731,32 +730,16 @@ public class ClassWriter extends ClassVisitor { } @Override - public final FieldVisitor visitField( - final int access, - final String name, - final String desc, - final String signature, - final Object value) - { + public final FieldVisitor visitField(final int access, final String name, + final String desc, final String signature, final Object value) { return new FieldWriter(this, access, name, desc, signature, value); } @Override - public final MethodVisitor visitMethod( - final int access, - final String name, - final String desc, - final String signature, - final String[] exceptions) - { - return new MethodWriter(this, - access, - name, - desc, - signature, - exceptions, - computeMaxs, - computeFrames); + public final MethodVisitor visitMethod(final int access, final String name, + final String desc, final String signature, final String[] exceptions) { + return new MethodWriter(this, access, name, desc, signature, + exceptions, computeMaxs, computeFrames); } @Override @@ -773,7 +756,7 @@ public class ClassWriter extends ClassVisitor { * @return the bytecode of the class that was build with this class writer. */ public byte[] toByteArray() { - if (index > Short.MAX_VALUE) { + if (index > 0xFFFF) { throw new RuntimeException("Class file too large!"); } // computes the real size of the bytecode of this class @@ -793,8 +776,9 @@ public class ClassWriter extends ClassVisitor { mb = (MethodWriter) mb.mv; } int attributeCount = 0; - if (bootstrapMethods != null) { // we put it as first argument in order - // to improve a bit ClassReader.copyBootstrapMethods + if (bootstrapMethods != null) { + // we put it as first attribute in order to improve a bit + // ClassReader.copyBootstrapMethods ++attributeCount; size += 8 + bootstrapMethods.length; newUTF8("BootstrapMethods"); @@ -824,12 +808,13 @@ public class ClassWriter extends ClassVisitor { size += 6; newUTF8("Deprecated"); } - if ((access & Opcodes.ACC_SYNTHETIC) != 0 - && ((version & 0xFFFF) < Opcodes.V1_5 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0)) - { - ++attributeCount; - size += 6; - newUTF8("Synthetic"); + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if ((version & 0xFFFF) < Opcodes.V1_5 + || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) { + ++attributeCount; + size += 6; + newUTF8("Synthetic"); + } } if (innerClasses != null) { ++attributeCount; @@ -856,9 +841,8 @@ public class ClassWriter extends ClassVisitor { ByteVector out = new ByteVector(size); out.putInt(0xCAFEBABE).putInt(version); out.putShort(index).putByteArray(pool.data, 0, pool.length); - int mask = Opcodes.ACC_DEPRECATED - | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE - | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / (ClassWriter.ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC)); + int mask = Opcodes.ACC_DEPRECATED | ACC_SYNTHETIC_ATTRIBUTE + | ((access & ACC_SYNTHETIC_ATTRIBUTE) / TO_ACC_SYNTHETIC); out.putShort(access & ~mask).putShort(name).putShort(superName); out.putShort(interfaceCount); for (int i = 0; i < interfaceCount; ++i) { @@ -877,9 +861,10 @@ public class ClassWriter extends ClassVisitor { mb = (MethodWriter) mb.mv; } out.putShort(attributeCount); - if (bootstrapMethods != null) { // should be the first class attribute ? + if (bootstrapMethods != null) { out.putShort(newUTF8("BootstrapMethods")); - out.putInt(bootstrapMethods.length + 2).putShort(bootstrapMethodsCount); + out.putInt(bootstrapMethods.length + 2).putShort( + bootstrapMethodsCount); out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length); } if (ClassReader.SIGNATURES && signature != 0) { @@ -900,10 +885,11 @@ public class ClassWriter extends ClassVisitor { if ((access & Opcodes.ACC_DEPRECATED) != 0) { out.putShort(newUTF8("Deprecated")).putInt(0); } - if ((access & Opcodes.ACC_SYNTHETIC) != 0 - && ((version & 0xFFFF) < Opcodes.V1_5 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0)) - { - out.putShort(newUTF8("Synthetic")).putInt(0); + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if ((version & 0xFFFF) < Opcodes.V1_5 + || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) { + out.putShort(newUTF8("Synthetic")).putInt(0); + } } if (innerClasses != null) { out.putShort(newUTF8("InnerClasses")); @@ -937,10 +923,11 @@ public class ClassWriter extends ClassVisitor { * Adds a number or string constant to the constant pool of the class being * build. Does nothing if the constant pool already contains a similar item. * - * @param cst the value of the constant to be added to the constant pool. - * This parameter must be an {@link Integer}, a {@link Float}, a - * {@link Long}, a {@link Double}, a {@link String} or a - * {@link Type}. + * @param cst + * the value of the constant to be added to the constant pool. + * This parameter must be an {@link Integer}, a {@link Float}, a + * {@link Long}, a {@link Double}, a {@link String} or a + * {@link Type}. * @return a new or already existing constant item with the given value. */ Item newConstItem(final Object cst) { @@ -973,12 +960,12 @@ public class ClassWriter extends ClassVisitor { } else if (cst instanceof Type) { Type t = (Type) cst; int s = t.getSort(); - if (s == Type.ARRAY) { - return newClassItem(t.getDescriptor()); - } else if (s == Type.OBJECT) { + if (s == Type.OBJECT) { return newClassItem(t.getInternalName()); - } else { // s == Type.METHOD + } else if (s == Type.METHOD) { return newMethodTypeItem(t.getDescriptor()); + } else { // s == primitive type or array + return newClassItem(t.getDescriptor()); } } else if (cst instanceof Handle) { Handle h = (Handle) cst; @@ -994,9 +981,10 @@ public class ClassWriter extends ClassVisitor { * <i>This method is intended for {@link Attribute} sub classes, and is * normally not needed by class generators or adapters.</i> * - * @param cst the value of the constant to be added to the constant pool. - * This parameter must be an {@link Integer}, a {@link Float}, a - * {@link Long}, a {@link Double} or a {@link String}. + * @param cst + * the value of the constant to be added to the constant pool. + * This parameter must be an {@link Integer}, a {@link Float}, a + * {@link Long}, a {@link Double} or a {@link String}. * @return the index of a new or already existing constant item with the * given value. */ @@ -1010,7 +998,8 @@ public class ClassWriter extends ClassVisitor { * method is intended for {@link Attribute} sub classes, and is normally not * needed by class generators or adapters.</i> * - * @param value the String value. + * @param value + * the String value. * @return the index of a new or already existing UTF8 item. */ public int newUTF8(final String value) { @@ -1030,7 +1019,8 @@ public class ClassWriter extends ClassVisitor { * <i>This method is intended for {@link Attribute} sub classes, and is * normally not needed by class generators or adapters.</i> * - * @param value the internal name of the class. + * @param value + * the internal name of the class. * @return a new or already existing class reference item. */ Item newClassItem(final String value) { @@ -1050,7 +1040,8 @@ public class ClassWriter extends ClassVisitor { * <i>This method is intended for {@link Attribute} sub classes, and is * normally not needed by class generators or adapters.</i> * - * @param value the internal name of the class. + * @param value + * the internal name of the class. * @return the index of a new or already existing class reference item. */ public int newClass(final String value) { @@ -1063,7 +1054,8 @@ public class ClassWriter extends ClassVisitor { * <i>This method is intended for {@link Attribute} sub classes, and is * normally not needed by class generators or adapters.</i> * - * @param methodDesc method descriptor of the method type. + * @param methodDesc + * method descriptor of the method type. * @return a new or already existing method type reference item. */ Item newMethodTypeItem(final String methodDesc) { @@ -1083,7 +1075,8 @@ public class ClassWriter extends ClassVisitor { * <i>This method is intended for {@link Attribute} sub classes, and is * normally not needed by class generators or adapters.</i> * - * @param methodDesc method descriptor of the method type. + * @param methodDesc + * method descriptor of the method type. * @return the index of a new or already existing method type reference * item. */ @@ -1097,33 +1090,34 @@ public class ClassWriter extends ClassVisitor { * intended for {@link Attribute} sub classes, and is normally not needed by * class generators or adapters.</i> * - * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, - * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, - * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, - * {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, - * {@link Opcodes#H_NEWINVOKESPECIAL} or - * {@link Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of the field or method owner class. - * @param name the name of the field or method. - * @param desc the descriptor of the field or method. + * @param tag + * the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, + * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, + * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, + * {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or + * {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner + * the internal name of the field or method owner class. + * @param name + * the name of the field or method. + * @param desc + * the descriptor of the field or method. * @return a new or an already existing method type reference item. */ - Item newHandleItem( - final int tag, - final String owner, - final String name, - final String desc) - { + Item newHandleItem(final int tag, final String owner, final String name, + final String desc) { key4.set(HANDLE_BASE + tag, owner, name, desc); Item result = get(key4); if (result == null) { if (tag <= Opcodes.H_PUTSTATIC) { put112(HANDLE, tag, newField(owner, name, desc)); } else { - put112(HANDLE, tag, newMethod(owner, - name, - desc, - tag == Opcodes.H_INVOKEINTERFACE)); + put112(HANDLE, + tag, + newMethod(owner, name, desc, + tag == Opcodes.H_INVOKEINTERFACE)); } result = new Item(index++, key4); put(result); @@ -1132,29 +1126,30 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds a handle to the constant pool of the class being - * build. Does nothing if the constant pool already contains a similar item. - * <i>This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters.</i> + * Adds a handle to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. <i>This method is + * intended for {@link Attribute} sub classes, and is normally not needed by + * class generators or adapters.</i> * - * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, - * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, - * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, - * {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, - * {@link Opcodes#H_NEWINVOKESPECIAL} or - * {@link Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of the field or method owner class. - * @param name the name of the field or method. - * @param desc the descriptor of the field or method. + * @param tag + * the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, + * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, + * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, + * {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or + * {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner + * the internal name of the field or method owner class. + * @param name + * the name of the field or method. + * @param desc + * the descriptor of the field or method. * @return the index of a new or already existing method type reference * item. */ - public int newHandle( - final int tag, - final String owner, - final String name, - final String desc) - { + public int newHandle(final int tag, final String owner, final String name, + final String desc) { return newHandleItem(tag, owner, name, desc).index; } @@ -1164,19 +1159,19 @@ public class ClassWriter extends ClassVisitor { * <i>This method is intended for {@link Attribute} sub classes, and is * normally not needed by class generators or adapters.</i> * - * @param name name of the invoked method. - * @param desc descriptor of the invoke method. - * @param bsm the bootstrap method. - * @param bsmArgs the bootstrap method constant arguments. + * @param name + * name of the invoked method. + * @param desc + * descriptor of the invoke method. + * @param bsm + * the bootstrap method. + * @param bsmArgs + * the bootstrap method constant arguments. * * @return a new or an already existing invokedynamic type reference item. */ - Item newInvokeDynamicItem( - final String name, - final String desc, - final Handle bsm, - final Object... bsmArgs) - { + Item newInvokeDynamicItem(final String name, final String desc, + final Handle bsm, final Object... bsmArgs) { // cache for performance ByteVector bootstrapMethods = this.bootstrapMethods; if (bootstrapMethods == null) { @@ -1186,9 +1181,7 @@ public class ClassWriter extends ClassVisitor { int position = bootstrapMethods.length; // record current position int hashCode = bsm.hashCode(); - bootstrapMethods.putShort(newHandle(bsm.tag, - bsm.owner, - bsm.name, + bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name, bsm.desc)); int argsLength = bsmArgs.length; @@ -1250,20 +1243,20 @@ public class ClassWriter extends ClassVisitor { * <i>This method is intended for {@link Attribute} sub classes, and is * normally not needed by class generators or adapters.</i> * - * @param name name of the invoked method. - * @param desc descriptor of the invoke method. - * @param bsm the bootstrap method. - * @param bsmArgs the bootstrap method constant arguments. + * @param name + * name of the invoked method. + * @param desc + * descriptor of the invoke method. + * @param bsm + * the bootstrap method. + * @param bsmArgs + * the bootstrap method constant arguments. * - * @return the index of a new or already existing invokedynamic - * reference item. - */ - public int newInvokeDynamic( - final String name, - final String desc, - final Handle bsm, - final Object... bsmArgs) - { + * @return the index of a new or already existing invokedynamic reference + * item. + */ + public int newInvokeDynamic(final String name, final String desc, + final Handle bsm, final Object... bsmArgs) { return newInvokeDynamicItem(name, desc, bsm, bsmArgs).index; } @@ -1271,13 +1264,15 @@ public class ClassWriter extends ClassVisitor { * Adds a field reference to the constant pool of the class being build. * Does nothing if the constant pool already contains a similar item. * - * @param owner the internal name of the field's owner class. - * @param name the field's name. - * @param desc the field's descriptor. + * @param owner + * the internal name of the field's owner class. + * @param name + * the field's name. + * @param desc + * the field's descriptor. * @return a new or already existing field reference item. */ - Item newFieldItem(final String owner, final String name, final String desc) - { + Item newFieldItem(final String owner, final String name, final String desc) { key3.set(FIELD, owner, name, desc); Item result = get(key3); if (result == null) { @@ -1294,13 +1289,15 @@ public class ClassWriter extends ClassVisitor { * <i>This method is intended for {@link Attribute} sub classes, and is * normally not needed by class generators or adapters.</i> * - * @param owner the internal name of the field's owner class. - * @param name the field's name. - * @param desc the field's descriptor. + * @param owner + * the internal name of the field's owner class. + * @param name + * the field's name. + * @param desc + * the field's descriptor. * @return the index of a new or already existing field reference item. */ - public int newField(final String owner, final String name, final String desc) - { + public int newField(final String owner, final String name, final String desc) { return newFieldItem(owner, name, desc).index; } @@ -1308,18 +1305,18 @@ public class ClassWriter extends ClassVisitor { * Adds a method reference to the constant pool of the class being build. * Does nothing if the constant pool already contains a similar item. * - * @param owner the internal name of the method's owner class. - * @param name the method's name. - * @param desc the method's descriptor. - * @param itf <tt>true</tt> if <tt>owner</tt> is an interface. + * @param owner + * the internal name of the method's owner class. + * @param name + * the method's name. + * @param desc + * the method's descriptor. + * @param itf + * <tt>true</tt> if <tt>owner</tt> is an interface. * @return a new or already existing method reference item. */ - Item newMethodItem( - final String owner, - final String name, - final String desc, - final boolean itf) - { + Item newMethodItem(final String owner, final String name, + final String desc, final boolean itf) { int type = itf ? IMETH : METH; key3.set(type, owner, name, desc); Item result = get(key3); @@ -1337,18 +1334,18 @@ public class ClassWriter extends ClassVisitor { * <i>This method is intended for {@link Attribute} sub classes, and is * normally not needed by class generators or adapters.</i> * - * @param owner the internal name of the method's owner class. - * @param name the method's name. - * @param desc the method's descriptor. - * @param itf <tt>true</tt> if <tt>owner</tt> is an interface. + * @param owner + * the internal name of the method's owner class. + * @param name + * the method's name. + * @param desc + * the method's descriptor. + * @param itf + * <tt>true</tt> if <tt>owner</tt> is an interface. * @return the index of a new or already existing method reference item. */ - public int newMethod( - final String owner, - final String name, - final String desc, - final boolean itf) - { + public int newMethod(final String owner, final String name, + final String desc, final boolean itf) { return newMethodItem(owner, name, desc, itf).index; } @@ -1356,7 +1353,8 @@ public class ClassWriter extends ClassVisitor { * Adds an integer to the constant pool of the class being build. Does * nothing if the constant pool already contains a similar item. * - * @param value the int value. + * @param value + * the int value. * @return a new or already existing int item. */ Item newInteger(final int value) { @@ -1374,7 +1372,8 @@ public class ClassWriter extends ClassVisitor { * Adds a float to the constant pool of the class being build. Does nothing * if the constant pool already contains a similar item. * - * @param value the float value. + * @param value + * the float value. * @return a new or already existing float item. */ Item newFloat(final float value) { @@ -1392,7 +1391,8 @@ public class ClassWriter extends ClassVisitor { * Adds a long to the constant pool of the class being build. Does nothing * if the constant pool already contains a similar item. * - * @param value the long value. + * @param value + * the long value. * @return a new or already existing long item. */ Item newLong(final long value) { @@ -1411,7 +1411,8 @@ public class ClassWriter extends ClassVisitor { * Adds a double to the constant pool of the class being build. Does nothing * if the constant pool already contains a similar item. * - * @param value the double value. + * @param value + * the double value. * @return a new or already existing double item. */ Item newDouble(final double value) { @@ -1430,7 +1431,8 @@ public class ClassWriter extends ClassVisitor { * Adds a string to the constant pool of the class being build. Does nothing * if the constant pool already contains a similar item. * - * @param value the String value. + * @param value + * the String value. * @return a new or already existing string item. */ private Item newString(final String value) { @@ -1450,8 +1452,10 @@ public class ClassWriter extends ClassVisitor { * method is intended for {@link Attribute} sub classes, and is normally not * needed by class generators or adapters.</i> * - * @param name a name. - * @param desc a type descriptor. + * @param name + * a name. + * @param desc + * a type descriptor. * @return the index of a new or already existing name and type item. */ public int newNameType(final String name, final String desc) { @@ -1462,8 +1466,10 @@ public class ClassWriter extends ClassVisitor { * Adds a name and type to the constant pool of the class being build. Does * nothing if the constant pool already contains a similar item. * - * @param name a name. - * @param desc a type descriptor. + * @param name + * a name. + * @param desc + * a type descriptor. * @return a new or already existing name and type item. */ Item newNameTypeItem(final String name, final String desc) { @@ -1481,7 +1487,8 @@ public class ClassWriter extends ClassVisitor { * Adds the given internal name to {@link #typeTable} and returns its index. * Does nothing if the type table already contains this internal name. * - * @param type the internal name to be added to the type table. + * @param type + * the internal name to be added to the type table. * @return the index of this internal name in the type table. */ int addType(final String type) { @@ -1498,9 +1505,11 @@ public class ClassWriter extends ClassVisitor { * index. This method is used for UNINITIALIZED types, made of an internal * name and a bytecode offset. * - * @param type the internal name to be added to the type table. - * @param offset the bytecode offset of the NEW instruction that created - * this UNINITIALIZED type value. + * @param type + * the internal name to be added to the type table. + * @param offset + * the bytecode offset of the NEW instruction that created this + * UNINITIALIZED type value. * @return the index of this internal name in the type table. */ int addUninitializedType(final String type, final int offset) { @@ -1518,7 +1527,8 @@ public class ClassWriter extends ClassVisitor { /** * Adds the given Item to {@link #typeTable}. * - * @param item the value to be added to the type table. + * @param item + * the value to be added to the type table. * @return the added Item, which a new Item instance with the same value as * the given Item. */ @@ -1544,8 +1554,10 @@ public class ClassWriter extends ClassVisitor { * {@link #items} hash table to speedup future calls with the same * parameters. * - * @param type1 index of an internal name in {@link #typeTable}. - * @param type2 index of an internal name in {@link #typeTable}. + * @param type1 + * index of an internal name in {@link #typeTable}. + * @param type2 + * index of an internal name in {@link #typeTable}. * @return the index of the common super type of the two given types. */ int getMergedType(final int type1, final int type2) { @@ -1572,13 +1584,14 @@ public class ClassWriter extends ClassVisitor { * that is currently being generated by this ClassWriter, which can of * course not be loaded since it is under construction. * - * @param type1 the internal name of a class. - * @param type2 the internal name of another class. + * @param type1 + * the internal name of a class. + * @param type2 + * the internal name of another class. * @return the internal name of the common super class of the two given * classes. */ - protected String getCommonSuperClass(final String type1, final String type2) - { + protected String getCommonSuperClass(final String type1, final String type2) { Class<?> c, d; ClassLoader classLoader = getClass().getClassLoader(); try { @@ -1607,7 +1620,8 @@ public class ClassWriter extends ClassVisitor { * Returns the constant pool's hash table item which is equal to the given * item. * - * @param key a constant pool item. + * @param key + * a constant pool item. * @return the constant pool's hash table item which is equal to the given * item, or <tt>null</tt> if there is no such item. */ @@ -1623,7 +1637,8 @@ public class ClassWriter extends ClassVisitor { * Puts the given item in the constant pool's hash table. The hash table * <i>must</i> not already contains this item. * - * @param i the item to be added to the constant pool's hash table. + * @param i + * the item to be added to the constant pool's hash table. */ private void put(final Item i) { if (index + typeCount > threshold) { @@ -1651,9 +1666,12 @@ public class ClassWriter extends ClassVisitor { /** * Puts one byte and two shorts into the constant pool. * - * @param b a byte. - * @param s1 a short. - * @param s2 another short. + * @param b + * a byte. + * @param s1 + * a short. + * @param s2 + * another short. */ private void put122(final int b, final int s1, final int s2) { pool.put12(b, s1).putShort(s2); @@ -1662,9 +1680,12 @@ public class ClassWriter extends ClassVisitor { /** * Puts two bytes and one short into the constant pool. * - * @param b1 a byte. - * @param b2 another byte. - * @param s a short. + * @param b1 + * a byte. + * @param b2 + * another byte. + * @param s + * a short. */ private void put112(final int b1, final int b2, final int s) { pool.put11(b1, b2).putShort(s); diff --git a/src/asm/scala/tools/asm/Context.java b/src/asm/scala/tools/asm/Context.java new file mode 100644 index 0000000000..7b3a2ad9dd --- /dev/null +++ b/src/asm/scala/tools/asm/Context.java @@ -0,0 +1,110 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package scala.tools.asm; + +/** + * Information about a class being parsed in a {@link ClassReader}. + * + * @author Eric Bruneton + */ +class Context { + + /** + * Prototypes of the attributes that must be parsed for this class. + */ + Attribute[] attrs; + + /** + * The {@link ClassReader} option flags for the parsing of this class. + */ + int flags; + + /** + * The buffer used to read strings. + */ + char[] buffer; + + /** + * The start index of each bootstrap method. + */ + int[] bootstrapMethods; + + /** + * The access flags of the method currently being parsed. + */ + int access; + + /** + * The name of the method currently being parsed. + */ + String name; + + /** + * The descriptor of the method currently being parsed. + */ + String desc; + + /** + * The offset of the latest stack map frame that has been parsed. + */ + int offset; + + /** + * The encoding of the latest stack map frame that has been parsed. + */ + int mode; + + /** + * The number of locals in the latest stack map frame that has been parsed. + */ + int localCount; + + /** + * The number locals in the latest stack map frame that has been parsed, + * minus the number of locals in the previous frame. + */ + int localDiff; + + /** + * The local values of the latest stack map frame that has been parsed. + */ + Object[] local; + + /** + * The stack size of the latest stack map frame that has been parsed. + */ + int stackCount; + + /** + * The stack values of the latest stack map frame that has been parsed. + */ + Object[] stack; +} diff --git a/src/asm/scala/tools/asm/FieldVisitor.java b/src/asm/scala/tools/asm/FieldVisitor.java index 9ac0f6236f..9171f331e5 100644 --- a/src/asm/scala/tools/asm/FieldVisitor.java +++ b/src/asm/scala/tools/asm/FieldVisitor.java @@ -30,9 +30,9 @@ package scala.tools.asm; /** - * A visitor to visit a Java field. The methods of this class must be called - * in the following order: ( <tt>visitAnnotation</tt> | - * <tt>visitAttribute</tt> )* <tt>visitEnd</tt>. + * A visitor to visit a Java field. The methods of this class must be called in + * the following order: ( <tt>visitAnnotation</tt> | <tt>visitAttribute</tt> )* + * <tt>visitEnd</tt>. * * @author Eric Bruneton */ @@ -53,8 +53,9 @@ public abstract class FieldVisitor { /** * Constructs a new {@link FieldVisitor}. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. */ public FieldVisitor(final int api) { this(api, null); @@ -63,15 +64,17 @@ public abstract class FieldVisitor { /** * Constructs a new {@link FieldVisitor}. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. - * @param fv the field visitor to which this visitor must delegate method - * calls. May be null. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param fv + * the field visitor to which this visitor must delegate method + * calls. May be null. */ public FieldVisitor(final int api, final FieldVisitor fv) { - /*if (api != Opcodes.ASM4) { + if (api != Opcodes.ASM4) { throw new IllegalArgumentException(); - }*/ + } this.api = api; this.fv = fv; } @@ -79,8 +82,10 @@ public abstract class FieldVisitor { /** * Visits an annotation of the field. * - * @param desc the class descriptor of the annotation class. - * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * <tt>true</tt> if the annotation is visible at runtime. * @return a visitor to visit the annotation values, or <tt>null</tt> if * this visitor is not interested in visiting this annotation. */ @@ -94,7 +99,8 @@ public abstract class FieldVisitor { /** * Visits a non standard attribute of the field. * - * @param attr an attribute. + * @param attr + * an attribute. */ public void visitAttribute(Attribute attr) { if (fv != null) { diff --git a/src/asm/scala/tools/asm/FieldWriter.java b/src/asm/scala/tools/asm/FieldWriter.java index 45ef6d0df3..02c6059b91 100644 --- a/src/asm/scala/tools/asm/FieldWriter.java +++ b/src/asm/scala/tools/asm/FieldWriter.java @@ -92,21 +92,21 @@ final class FieldWriter extends FieldVisitor { /** * Constructs a new {@link FieldWriter}. * - * @param cw the class writer to which this field must be added. - * @param access the field's access flags (see {@link Opcodes}). - * @param name the field's name. - * @param desc the field's descriptor (see {@link Type}). - * @param signature the field's signature. May be <tt>null</tt>. - * @param value the field's constant value. May be <tt>null</tt>. + * @param cw + * the class writer to which this field must be added. + * @param access + * the field's access flags (see {@link Opcodes}). + * @param name + * the field's name. + * @param desc + * the field's descriptor (see {@link Type}). + * @param signature + * the field's signature. May be <tt>null</tt>. + * @param value + * the field's constant value. May be <tt>null</tt>. */ - FieldWriter( - final ClassWriter cw, - final int access, - final String name, - final String desc, - final String signature, - final Object value) - { + FieldWriter(final ClassWriter cw, final int access, final String name, + final String desc, final String signature, final Object value) { super(Opcodes.ASM4); if (cw.firstField == null) { cw.firstField = this; @@ -131,10 +131,8 @@ final class FieldWriter extends FieldVisitor { // ------------------------------------------------------------------------ @Override - public AnnotationVisitor visitAnnotation( - final String desc, - final boolean visible) - { + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { if (!ClassReader.ANNOTATIONS) { return null; } @@ -177,11 +175,12 @@ final class FieldWriter extends FieldVisitor { cw.newUTF8("ConstantValue"); size += 8; } - if ((access & Opcodes.ACC_SYNTHETIC) != 0 - && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) - { - cw.newUTF8("Synthetic"); - size += 6; + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if ((cw.version & 0xFFFF) < Opcodes.V1_5 + || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { + cw.newUTF8("Synthetic"); + size += 6; + } } if ((access & Opcodes.ACC_DEPRECATED) != 0) { cw.newUTF8("Deprecated"); @@ -208,21 +207,23 @@ final class FieldWriter extends FieldVisitor { /** * Puts the content of this field into the given byte vector. * - * @param out where the content of this field must be put. + * @param out + * where the content of this field must be put. */ void put(final ByteVector out) { - int mask = Opcodes.ACC_DEPRECATED - | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE - | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / (ClassWriter.ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC)); + final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; + int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE + | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); out.putShort(access & ~mask).putShort(name).putShort(desc); int attributeCount = 0; if (value != 0) { ++attributeCount; } - if ((access & Opcodes.ACC_SYNTHETIC) != 0 - && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) - { - ++attributeCount; + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if ((cw.version & 0xFFFF) < Opcodes.V1_5 + || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { + ++attributeCount; + } } if ((access & Opcodes.ACC_DEPRECATED) != 0) { ++attributeCount; @@ -244,10 +245,11 @@ final class FieldWriter extends FieldVisitor { out.putShort(cw.newUTF8("ConstantValue")); out.putInt(2).putShort(value); } - if ((access & Opcodes.ACC_SYNTHETIC) != 0 - && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) - { - out.putShort(cw.newUTF8("Synthetic")).putInt(0); + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if ((cw.version & 0xFFFF) < Opcodes.V1_5 + || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { + out.putShort(cw.newUTF8("Synthetic")).putInt(0); + } } if ((access & Opcodes.ACC_DEPRECATED) != 0) { out.putShort(cw.newUTF8("Deprecated")).putInt(0); diff --git a/src/asm/scala/tools/asm/Frame.java b/src/asm/scala/tools/asm/Frame.java index 387b56796d..bcc3e8450b 100644 --- a/src/asm/scala/tools/asm/Frame.java +++ b/src/asm/scala/tools/asm/Frame.java @@ -80,13 +80,13 @@ final class Frame { * table contains only internal type names (array type descriptors are * forbidden - dimensions must be represented through the DIM field). * - * The LONG and DOUBLE types are always represented by using two slots (LONG + - * TOP or DOUBLE + TOP), for local variable types as well as in the operand - * stack. This is necessary to be able to simulate DUPx_y instructions, - * whose effect would be dependent on the actual type values if types were - * always represented by a single slot in the stack (and this is not - * possible, since actual type values are not always known - cf LOCAL and - * STACK type kinds). + * The LONG and DOUBLE types are always represented by using two slots (LONG + * + TOP or DOUBLE + TOP), for local variable types as well as in the + * operand stack. This is necessary to be able to simulate DUPx_y + * instructions, whose effect would be dependent on the actual type values + * if types were always represented by a single slot in the stack (and this + * is not possible, since actual type values are not always known - cf LOCAL + * and STACK type kinds). */ /** @@ -117,9 +117,9 @@ final class Frame { /** * Flag used for LOCAL and STACK types. Indicates that if this type happens * to be a long or double type (during the computations of input frames), - * then it must be set to TOP because the second word of this value has - * been reused to store other data in the basic block. Hence the first word - * no longer stores a valid long or double value. + * then it must be set to TOP because the second word of this value has been + * reused to store other data in the basic block. Hence the first word no + * longer stores a valid long or double value. */ static final int TOP_IF_LONG_OR_DOUBLE = 0x800000; @@ -523,7 +523,8 @@ final class Frame { /** * Returns the output frame local variable type at the given index. * - * @param local the index of the local that must be returned. + * @param local + * the index of the local that must be returned. * @return the output frame local variable type at the given index. */ private int get(final int local) { @@ -545,8 +546,10 @@ final class Frame { /** * Sets the output frame local variable type at the given index. * - * @param local the index of the local that must be set. - * @param type the value of the local that must be set. + * @param local + * the index of the local that must be set. + * @param type + * the value of the local that must be set. */ private void set(final int local, final int type) { // creates and/or resizes the output local variables array if necessary @@ -566,7 +569,8 @@ final class Frame { /** * Pushes a new type onto the output frame stack. * - * @param type the type that must be pushed. + * @param type + * the type that must be pushed. */ private void push(final int type) { // creates and/or resizes the output stack array if necessary @@ -591,10 +595,12 @@ final class Frame { /** * Pushes a new type onto the output frame stack. * - * @param cw the ClassWriter to which this label belongs. - * @param desc the descriptor of the type to be pushed. Can also be a method - * descriptor (in this case this method pushes its return type onto - * the output frame stack). + * @param cw + * the ClassWriter to which this label belongs. + * @param desc + * the descriptor of the type to be pushed. Can also be a method + * descriptor (in this case this method pushes its return type + * onto the output frame stack). */ private void push(final ClassWriter cw, final String desc) { int type = type(cw, desc); @@ -609,72 +615,74 @@ final class Frame { /** * Returns the int encoding of the given type. * - * @param cw the ClassWriter to which this label belongs. - * @param desc a type descriptor. + * @param cw + * the ClassWriter to which this label belongs. + * @param desc + * a type descriptor. * @return the int encoding of the given type. */ private static int type(final ClassWriter cw, final String desc) { String t; int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0; switch (desc.charAt(index)) { - case 'V': - return 0; + case 'V': + return 0; + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + return INTEGER; + case 'F': + return FLOAT; + case 'J': + return LONG; + case 'D': + return DOUBLE; + case 'L': + // stores the internal name, not the descriptor! + t = desc.substring(index + 1, desc.length() - 1); + return OBJECT | cw.addType(t); + // case '[': + default: + // extracts the dimensions and the element type + int data; + int dims = index + 1; + while (desc.charAt(dims) == '[') { + ++dims; + } + switch (desc.charAt(dims)) { case 'Z': + data = BOOLEAN; + break; case 'C': + data = CHAR; + break; case 'B': + data = BYTE; + break; case 'S': + data = SHORT; + break; case 'I': - return INTEGER; + data = INTEGER; + break; case 'F': - return FLOAT; + data = FLOAT; + break; case 'J': - return LONG; + data = LONG; + break; case 'D': - return DOUBLE; - case 'L': - // stores the internal name, not the descriptor! - t = desc.substring(index + 1, desc.length() - 1); - return OBJECT | cw.addType(t); - // case '[': + data = DOUBLE; + break; + // case 'L': default: - // extracts the dimensions and the element type - int data; - int dims = index + 1; - while (desc.charAt(dims) == '[') { - ++dims; - } - switch (desc.charAt(dims)) { - case 'Z': - data = BOOLEAN; - break; - case 'C': - data = CHAR; - break; - case 'B': - data = BYTE; - break; - case 'S': - data = SHORT; - break; - case 'I': - data = INTEGER; - break; - case 'F': - data = FLOAT; - break; - case 'J': - data = LONG; - break; - case 'D': - data = DOUBLE; - break; - // case 'L': - default: - // stores the internal name, not the descriptor - t = desc.substring(dims + 1, desc.length() - 1); - data = OBJECT | cw.addType(t); - } - return (dims - index) << 28 | data; + // stores the internal name, not the descriptor + t = desc.substring(dims + 1, desc.length() - 1); + data = OBJECT | cw.addType(t); + } + return (dims - index) << 28 | data; } } @@ -695,7 +703,8 @@ final class Frame { /** * Pops the given number of types from the output frame stack. * - * @param elements the number of types that must be popped. + * @param elements + * the number of types that must be popped. */ private void pop(final int elements) { if (outputStackTop >= elements) { @@ -712,9 +721,10 @@ final class Frame { /** * Pops a type from the output frame stack. * - * @param desc the descriptor of the type to be popped. Can also be a method - * descriptor (in this case this method pops the types corresponding - * to the method arguments). + * @param desc + * the descriptor of the type to be popped. Can also be a method + * descriptor (in this case this method pops the types + * corresponding to the method arguments). */ private void pop(final String desc) { char c = desc.charAt(0); @@ -731,7 +741,8 @@ final class Frame { * Adds a new type to the list of types on which a constructor is invoked in * the basic block. * - * @param var a type on a which a constructor is invoked. + * @param var + * a type on a which a constructor is invoked. */ private void init(final int var) { // creates and/or resizes the initializations array if necessary @@ -752,8 +763,10 @@ final class Frame { * Replaces the given type with the appropriate type if it is one of the * types on which a constructor is invoked in the basic block. * - * @param cw the ClassWriter to which this label belongs. - * @param t a type + * @param cw + * the ClassWriter to which this label belongs. + * @param t + * a type * @return t or, if t is one of the types on which a constructor is invoked * in the basic block, the type corresponding to this constructor. */ @@ -787,17 +800,17 @@ final class Frame { * Initializes the input frame of the first basic block from the method * descriptor. * - * @param cw the ClassWriter to which this label belongs. - * @param access the access flags of the method to which this label belongs. - * @param args the formal parameter types of this method. - * @param maxLocals the maximum number of local variables of this method. + * @param cw + * the ClassWriter to which this label belongs. + * @param access + * the access flags of the method to which this label belongs. + * @param args + * the formal parameter types of this method. + * @param maxLocals + * the maximum number of local variables of this method. */ - void initInputFrame( - final ClassWriter cw, - final int access, - final Type[] args, - final int maxLocals) - { + void initInputFrame(final ClassWriter cw, final int access, + final Type[] args, final int maxLocals) { inputLocals = new int[maxLocals]; inputStack = new int[0]; int i = 0; @@ -823,435 +836,435 @@ final class Frame { /** * Simulates the action of the given instruction on the output stack frame. * - * @param opcode the opcode of the instruction. - * @param arg the operand of the instruction, if any. - * @param cw the class writer to which this label belongs. - * @param item the operand of the instructions, if any. + * @param opcode + * the opcode of the instruction. + * @param arg + * the operand of the instruction, if any. + * @param cw + * the class writer to which this label belongs. + * @param item + * the operand of the instructions, if any. */ - void execute( - final int opcode, - final int arg, - final ClassWriter cw, - final Item item) - { + void execute(final int opcode, final int arg, final ClassWriter cw, + final Item item) { int t1, t2, t3, t4; switch (opcode) { - case Opcodes.NOP: - case Opcodes.INEG: - case Opcodes.LNEG: - case Opcodes.FNEG: - case Opcodes.DNEG: - case Opcodes.I2B: - case Opcodes.I2C: - case Opcodes.I2S: - case Opcodes.GOTO: - case Opcodes.RETURN: - break; - case Opcodes.ACONST_NULL: - push(NULL); - break; - case Opcodes.ICONST_M1: - case Opcodes.ICONST_0: - case Opcodes.ICONST_1: - case Opcodes.ICONST_2: - case Opcodes.ICONST_3: - case Opcodes.ICONST_4: - case Opcodes.ICONST_5: - case Opcodes.BIPUSH: - case Opcodes.SIPUSH: - case Opcodes.ILOAD: + case Opcodes.NOP: + case Opcodes.INEG: + case Opcodes.LNEG: + case Opcodes.FNEG: + case Opcodes.DNEG: + case Opcodes.I2B: + case Opcodes.I2C: + case Opcodes.I2S: + case Opcodes.GOTO: + case Opcodes.RETURN: + break; + case Opcodes.ACONST_NULL: + push(NULL); + break; + case Opcodes.ICONST_M1: + case Opcodes.ICONST_0: + case Opcodes.ICONST_1: + case Opcodes.ICONST_2: + case Opcodes.ICONST_3: + case Opcodes.ICONST_4: + case Opcodes.ICONST_5: + case Opcodes.BIPUSH: + case Opcodes.SIPUSH: + case Opcodes.ILOAD: + push(INTEGER); + break; + case Opcodes.LCONST_0: + case Opcodes.LCONST_1: + case Opcodes.LLOAD: + push(LONG); + push(TOP); + break; + case Opcodes.FCONST_0: + case Opcodes.FCONST_1: + case Opcodes.FCONST_2: + case Opcodes.FLOAD: + push(FLOAT); + break; + case Opcodes.DCONST_0: + case Opcodes.DCONST_1: + case Opcodes.DLOAD: + push(DOUBLE); + push(TOP); + break; + case Opcodes.LDC: + switch (item.type) { + case ClassWriter.INT: push(INTEGER); break; - case Opcodes.LCONST_0: - case Opcodes.LCONST_1: - case Opcodes.LLOAD: + case ClassWriter.LONG: push(LONG); push(TOP); break; - case Opcodes.FCONST_0: - case Opcodes.FCONST_1: - case Opcodes.FCONST_2: - case Opcodes.FLOAD: + case ClassWriter.FLOAT: push(FLOAT); break; - case Opcodes.DCONST_0: - case Opcodes.DCONST_1: - case Opcodes.DLOAD: + case ClassWriter.DOUBLE: push(DOUBLE); push(TOP); break; - case Opcodes.LDC: - switch (item.type) { - case ClassWriter.INT: - push(INTEGER); - break; - case ClassWriter.LONG: - push(LONG); - push(TOP); - break; - case ClassWriter.FLOAT: - push(FLOAT); - break; - case ClassWriter.DOUBLE: - push(DOUBLE); - push(TOP); - break; - case ClassWriter.CLASS: - push(OBJECT | cw.addType("java/lang/Class")); - break; - case ClassWriter.STR: - push(OBJECT | cw.addType("java/lang/String")); - break; - case ClassWriter.MTYPE: - push(OBJECT | cw.addType("java/lang/invoke/MethodType")); - break; - // case ClassWriter.HANDLE_BASE + [1..9]: - default: - push(OBJECT | cw.addType("java/lang/invoke/MethodHandle")); - } - break; - case Opcodes.ALOAD: - push(get(arg)); - break; - case Opcodes.IALOAD: - case Opcodes.BALOAD: - case Opcodes.CALOAD: - case Opcodes.SALOAD: - pop(2); - push(INTEGER); - break; - case Opcodes.LALOAD: - case Opcodes.D2L: - pop(2); - push(LONG); - push(TOP); + case ClassWriter.CLASS: + push(OBJECT | cw.addType("java/lang/Class")); break; - case Opcodes.FALOAD: - pop(2); - push(FLOAT); + case ClassWriter.STR: + push(OBJECT | cw.addType("java/lang/String")); break; - case Opcodes.DALOAD: - case Opcodes.L2D: - pop(2); - push(DOUBLE); - push(TOP); + case ClassWriter.MTYPE: + push(OBJECT | cw.addType("java/lang/invoke/MethodType")); break; - case Opcodes.AALOAD: - pop(1); - t1 = pop(); - push(ELEMENT_OF + t1); - break; - case Opcodes.ISTORE: - case Opcodes.FSTORE: - case Opcodes.ASTORE: - t1 = pop(); - set(arg, t1); - if (arg > 0) { - t2 = get(arg - 1); - // if t2 is of kind STACK or LOCAL we cannot know its size! - if (t2 == LONG || t2 == DOUBLE) { - set(arg - 1, TOP); - } else if ((t2 & KIND) != BASE) { - set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); - } + // case ClassWriter.HANDLE_BASE + [1..9]: + default: + push(OBJECT | cw.addType("java/lang/invoke/MethodHandle")); + } + break; + case Opcodes.ALOAD: + push(get(arg)); + break; + case Opcodes.IALOAD: + case Opcodes.BALOAD: + case Opcodes.CALOAD: + case Opcodes.SALOAD: + pop(2); + push(INTEGER); + break; + case Opcodes.LALOAD: + case Opcodes.D2L: + pop(2); + push(LONG); + push(TOP); + break; + case Opcodes.FALOAD: + pop(2); + push(FLOAT); + break; + case Opcodes.DALOAD: + case Opcodes.L2D: + pop(2); + push(DOUBLE); + push(TOP); + break; + case Opcodes.AALOAD: + pop(1); + t1 = pop(); + push(ELEMENT_OF + t1); + break; + case Opcodes.ISTORE: + case Opcodes.FSTORE: + case Opcodes.ASTORE: + t1 = pop(); + set(arg, t1); + if (arg > 0) { + t2 = get(arg - 1); + // if t2 is of kind STACK or LOCAL we cannot know its size! + if (t2 == LONG || t2 == DOUBLE) { + set(arg - 1, TOP); + } else if ((t2 & KIND) != BASE) { + set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); } - break; - case Opcodes.LSTORE: - case Opcodes.DSTORE: - pop(1); - t1 = pop(); - set(arg, t1); - set(arg + 1, TOP); - if (arg > 0) { - t2 = get(arg - 1); - // if t2 is of kind STACK or LOCAL we cannot know its size! - if (t2 == LONG || t2 == DOUBLE) { - set(arg - 1, TOP); - } else if ((t2 & KIND) != BASE) { - set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); - } + } + break; + case Opcodes.LSTORE: + case Opcodes.DSTORE: + pop(1); + t1 = pop(); + set(arg, t1); + set(arg + 1, TOP); + if (arg > 0) { + t2 = get(arg - 1); + // if t2 is of kind STACK or LOCAL we cannot know its size! + if (t2 == LONG || t2 == DOUBLE) { + set(arg - 1, TOP); + } else if ((t2 & KIND) != BASE) { + set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); } - break; - case Opcodes.IASTORE: - case Opcodes.BASTORE: - case Opcodes.CASTORE: - case Opcodes.SASTORE: - case Opcodes.FASTORE: - case Opcodes.AASTORE: - pop(3); - break; - case Opcodes.LASTORE: - case Opcodes.DASTORE: - pop(4); - break; - case Opcodes.POP: - case Opcodes.IFEQ: - case Opcodes.IFNE: - case Opcodes.IFLT: - case Opcodes.IFGE: - case Opcodes.IFGT: - case Opcodes.IFLE: - case Opcodes.IRETURN: - case Opcodes.FRETURN: - case Opcodes.ARETURN: - case Opcodes.TABLESWITCH: - case Opcodes.LOOKUPSWITCH: - case Opcodes.ATHROW: - case Opcodes.MONITORENTER: - case Opcodes.MONITOREXIT: - case Opcodes.IFNULL: - case Opcodes.IFNONNULL: - pop(1); - break; - case Opcodes.POP2: - case Opcodes.IF_ICMPEQ: - case Opcodes.IF_ICMPNE: - case Opcodes.IF_ICMPLT: - case Opcodes.IF_ICMPGE: - case Opcodes.IF_ICMPGT: - case Opcodes.IF_ICMPLE: - case Opcodes.IF_ACMPEQ: - case Opcodes.IF_ACMPNE: - case Opcodes.LRETURN: - case Opcodes.DRETURN: - pop(2); - break; - case Opcodes.DUP: - t1 = pop(); - push(t1); - push(t1); - break; - case Opcodes.DUP_X1: - t1 = pop(); - t2 = pop(); - push(t1); - push(t2); - push(t1); - break; - case Opcodes.DUP_X2: - t1 = pop(); - t2 = pop(); - t3 = pop(); - push(t1); - push(t3); - push(t2); - push(t1); - break; - case Opcodes.DUP2: - t1 = pop(); - t2 = pop(); - push(t2); - push(t1); - push(t2); - push(t1); - break; - case Opcodes.DUP2_X1: - t1 = pop(); - t2 = pop(); - t3 = pop(); - push(t2); - push(t1); - push(t3); - push(t2); - push(t1); - break; - case Opcodes.DUP2_X2: - t1 = pop(); - t2 = pop(); - t3 = pop(); - t4 = pop(); - push(t2); - push(t1); - push(t4); - push(t3); - push(t2); - push(t1); - break; - case Opcodes.SWAP: + } + break; + case Opcodes.IASTORE: + case Opcodes.BASTORE: + case Opcodes.CASTORE: + case Opcodes.SASTORE: + case Opcodes.FASTORE: + case Opcodes.AASTORE: + pop(3); + break; + case Opcodes.LASTORE: + case Opcodes.DASTORE: + pop(4); + break; + case Opcodes.POP: + case Opcodes.IFEQ: + case Opcodes.IFNE: + case Opcodes.IFLT: + case Opcodes.IFGE: + case Opcodes.IFGT: + case Opcodes.IFLE: + case Opcodes.IRETURN: + case Opcodes.FRETURN: + case Opcodes.ARETURN: + case Opcodes.TABLESWITCH: + case Opcodes.LOOKUPSWITCH: + case Opcodes.ATHROW: + case Opcodes.MONITORENTER: + case Opcodes.MONITOREXIT: + case Opcodes.IFNULL: + case Opcodes.IFNONNULL: + pop(1); + break; + case Opcodes.POP2: + case Opcodes.IF_ICMPEQ: + case Opcodes.IF_ICMPNE: + case Opcodes.IF_ICMPLT: + case Opcodes.IF_ICMPGE: + case Opcodes.IF_ICMPGT: + case Opcodes.IF_ICMPLE: + case Opcodes.IF_ACMPEQ: + case Opcodes.IF_ACMPNE: + case Opcodes.LRETURN: + case Opcodes.DRETURN: + pop(2); + break; + case Opcodes.DUP: + t1 = pop(); + push(t1); + push(t1); + break; + case Opcodes.DUP_X1: + t1 = pop(); + t2 = pop(); + push(t1); + push(t2); + push(t1); + break; + case Opcodes.DUP_X2: + t1 = pop(); + t2 = pop(); + t3 = pop(); + push(t1); + push(t3); + push(t2); + push(t1); + break; + case Opcodes.DUP2: + t1 = pop(); + t2 = pop(); + push(t2); + push(t1); + push(t2); + push(t1); + break; + case Opcodes.DUP2_X1: + t1 = pop(); + t2 = pop(); + t3 = pop(); + push(t2); + push(t1); + push(t3); + push(t2); + push(t1); + break; + case Opcodes.DUP2_X2: + t1 = pop(); + t2 = pop(); + t3 = pop(); + t4 = pop(); + push(t2); + push(t1); + push(t4); + push(t3); + push(t2); + push(t1); + break; + case Opcodes.SWAP: + t1 = pop(); + t2 = pop(); + push(t1); + push(t2); + break; + case Opcodes.IADD: + case Opcodes.ISUB: + case Opcodes.IMUL: + case Opcodes.IDIV: + case Opcodes.IREM: + case Opcodes.IAND: + case Opcodes.IOR: + case Opcodes.IXOR: + case Opcodes.ISHL: + case Opcodes.ISHR: + case Opcodes.IUSHR: + case Opcodes.L2I: + case Opcodes.D2I: + case Opcodes.FCMPL: + case Opcodes.FCMPG: + pop(2); + push(INTEGER); + break; + case Opcodes.LADD: + case Opcodes.LSUB: + case Opcodes.LMUL: + case Opcodes.LDIV: + case Opcodes.LREM: + case Opcodes.LAND: + case Opcodes.LOR: + case Opcodes.LXOR: + pop(4); + push(LONG); + push(TOP); + break; + case Opcodes.FADD: + case Opcodes.FSUB: + case Opcodes.FMUL: + case Opcodes.FDIV: + case Opcodes.FREM: + case Opcodes.L2F: + case Opcodes.D2F: + pop(2); + push(FLOAT); + break; + case Opcodes.DADD: + case Opcodes.DSUB: + case Opcodes.DMUL: + case Opcodes.DDIV: + case Opcodes.DREM: + pop(4); + push(DOUBLE); + push(TOP); + break; + case Opcodes.LSHL: + case Opcodes.LSHR: + case Opcodes.LUSHR: + pop(3); + push(LONG); + push(TOP); + break; + case Opcodes.IINC: + set(arg, INTEGER); + break; + case Opcodes.I2L: + case Opcodes.F2L: + pop(1); + push(LONG); + push(TOP); + break; + case Opcodes.I2F: + pop(1); + push(FLOAT); + break; + case Opcodes.I2D: + case Opcodes.F2D: + pop(1); + push(DOUBLE); + push(TOP); + break; + case Opcodes.F2I: + case Opcodes.ARRAYLENGTH: + case Opcodes.INSTANCEOF: + pop(1); + push(INTEGER); + break; + case Opcodes.LCMP: + case Opcodes.DCMPL: + case Opcodes.DCMPG: + pop(4); + push(INTEGER); + break; + case Opcodes.JSR: + case Opcodes.RET: + throw new RuntimeException( + "JSR/RET are not supported with computeFrames option"); + case Opcodes.GETSTATIC: + push(cw, item.strVal3); + break; + case Opcodes.PUTSTATIC: + pop(item.strVal3); + break; + case Opcodes.GETFIELD: + pop(1); + push(cw, item.strVal3); + break; + case Opcodes.PUTFIELD: + pop(item.strVal3); + pop(); + break; + case Opcodes.INVOKEVIRTUAL: + case Opcodes.INVOKESPECIAL: + case Opcodes.INVOKESTATIC: + case Opcodes.INVOKEINTERFACE: + pop(item.strVal3); + if (opcode != Opcodes.INVOKESTATIC) { t1 = pop(); - t2 = pop(); - push(t1); - push(t2); - break; - case Opcodes.IADD: - case Opcodes.ISUB: - case Opcodes.IMUL: - case Opcodes.IDIV: - case Opcodes.IREM: - case Opcodes.IAND: - case Opcodes.IOR: - case Opcodes.IXOR: - case Opcodes.ISHL: - case Opcodes.ISHR: - case Opcodes.IUSHR: - case Opcodes.L2I: - case Opcodes.D2I: - case Opcodes.FCMPL: - case Opcodes.FCMPG: - pop(2); - push(INTEGER); - break; - case Opcodes.LADD: - case Opcodes.LSUB: - case Opcodes.LMUL: - case Opcodes.LDIV: - case Opcodes.LREM: - case Opcodes.LAND: - case Opcodes.LOR: - case Opcodes.LXOR: - pop(4); - push(LONG); - push(TOP); - break; - case Opcodes.FADD: - case Opcodes.FSUB: - case Opcodes.FMUL: - case Opcodes.FDIV: - case Opcodes.FREM: - case Opcodes.L2F: - case Opcodes.D2F: - pop(2); - push(FLOAT); - break; - case Opcodes.DADD: - case Opcodes.DSUB: - case Opcodes.DMUL: - case Opcodes.DDIV: - case Opcodes.DREM: - pop(4); - push(DOUBLE); - push(TOP); - break; - case Opcodes.LSHL: - case Opcodes.LSHR: - case Opcodes.LUSHR: - pop(3); - push(LONG); - push(TOP); - break; - case Opcodes.IINC: - set(arg, INTEGER); - break; - case Opcodes.I2L: - case Opcodes.F2L: - pop(1); - push(LONG); - push(TOP); - break; - case Opcodes.I2F: - pop(1); - push(FLOAT); - break; - case Opcodes.I2D: - case Opcodes.F2D: - pop(1); - push(DOUBLE); - push(TOP); - break; - case Opcodes.F2I: - case Opcodes.ARRAYLENGTH: - case Opcodes.INSTANCEOF: - pop(1); - push(INTEGER); - break; - case Opcodes.LCMP: - case Opcodes.DCMPL: - case Opcodes.DCMPG: - pop(4); - push(INTEGER); - break; - case Opcodes.JSR: - case Opcodes.RET: - throw new RuntimeException("JSR/RET are not supported with computeFrames option"); - case Opcodes.GETSTATIC: - push(cw, item.strVal3); - break; - case Opcodes.PUTSTATIC: - pop(item.strVal3); - break; - case Opcodes.GETFIELD: - pop(1); - push(cw, item.strVal3); - break; - case Opcodes.PUTFIELD: - pop(item.strVal3); - pop(); - break; - case Opcodes.INVOKEVIRTUAL: - case Opcodes.INVOKESPECIAL: - case Opcodes.INVOKESTATIC: - case Opcodes.INVOKEINTERFACE: - pop(item.strVal3); - if (opcode != Opcodes.INVOKESTATIC) { - t1 = pop(); - if (opcode == Opcodes.INVOKESPECIAL - && item.strVal2.charAt(0) == '<') - { - init(t1); - } + if (opcode == Opcodes.INVOKESPECIAL + && item.strVal2.charAt(0) == '<') { + init(t1); } - push(cw, item.strVal3); + } + push(cw, item.strVal3); + break; + case Opcodes.INVOKEDYNAMIC: + pop(item.strVal2); + push(cw, item.strVal2); + break; + case Opcodes.NEW: + push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg)); + break; + case Opcodes.NEWARRAY: + pop(); + switch (arg) { + case Opcodes.T_BOOLEAN: + push(ARRAY_OF | BOOLEAN); break; - case Opcodes.INVOKEDYNAMIC: - pop(item.strVal2); - push(cw, item.strVal2); + case Opcodes.T_CHAR: + push(ARRAY_OF | CHAR); break; - case Opcodes.NEW: - push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg)); + case Opcodes.T_BYTE: + push(ARRAY_OF | BYTE); break; - case Opcodes.NEWARRAY: - pop(); - switch (arg) { - case Opcodes.T_BOOLEAN: - push(ARRAY_OF | BOOLEAN); - break; - case Opcodes.T_CHAR: - push(ARRAY_OF | CHAR); - break; - case Opcodes.T_BYTE: - push(ARRAY_OF | BYTE); - break; - case Opcodes.T_SHORT: - push(ARRAY_OF | SHORT); - break; - case Opcodes.T_INT: - push(ARRAY_OF | INTEGER); - break; - case Opcodes.T_FLOAT: - push(ARRAY_OF | FLOAT); - break; - case Opcodes.T_DOUBLE: - push(ARRAY_OF | DOUBLE); - break; - // case Opcodes.T_LONG: - default: - push(ARRAY_OF | LONG); - break; - } + case Opcodes.T_SHORT: + push(ARRAY_OF | SHORT); break; - case Opcodes.ANEWARRAY: - String s = item.strVal1; - pop(); - if (s.charAt(0) == '[') { - push(cw, '[' + s); - } else { - push(ARRAY_OF | OBJECT | cw.addType(s)); - } + case Opcodes.T_INT: + push(ARRAY_OF | INTEGER); break; - case Opcodes.CHECKCAST: - s = item.strVal1; - pop(); - if (s.charAt(0) == '[') { - push(cw, s); - } else { - push(OBJECT | cw.addType(s)); - } + case Opcodes.T_FLOAT: + push(ARRAY_OF | FLOAT); break; - // case Opcodes.MULTIANEWARRAY: + case Opcodes.T_DOUBLE: + push(ARRAY_OF | DOUBLE); + break; + // case Opcodes.T_LONG: default: - pop(arg); - push(cw, item.strVal1); + push(ARRAY_OF | LONG); break; + } + break; + case Opcodes.ANEWARRAY: + String s = item.strVal1; + pop(); + if (s.charAt(0) == '[') { + push(cw, '[' + s); + } else { + push(ARRAY_OF | OBJECT | cw.addType(s)); + } + break; + case Opcodes.CHECKCAST: + s = item.strVal1; + pop(); + if (s.charAt(0) == '[') { + push(cw, s); + } else { + push(OBJECT | cw.addType(s)); + } + break; + // case Opcodes.MULTIANEWARRAY: + default: + pop(arg); + push(cw, item.strVal1); + break; } } @@ -1260,10 +1273,13 @@ final class Frame { * frames of this basic block. Returns <tt>true</tt> if the input frame of * the given label has been changed by this operation. * - * @param cw the ClassWriter to which this label belongs. - * @param frame the basic block whose input frame must be updated. - * @param edge the kind of the {@link Edge} between this label and 'label'. - * See {@link Edge#info}. + * @param cw + * the ClassWriter to which this label belongs. + * @param frame + * the basic block whose input frame must be updated. + * @param edge + * the kind of the {@link Edge} between this label and 'label'. + * See {@link Edge#info}. * @return <tt>true</tt> if the input frame of the given label has been * changed by this operation. */ @@ -1294,7 +1310,8 @@ final class Frame { } else { t = dim + inputStack[nStack - (s & VALUE)]; } - if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (t == LONG || t == DOUBLE)) { + if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 + && (t == LONG || t == DOUBLE)) { t = TOP; } } @@ -1346,7 +1363,8 @@ final class Frame { } else { t = dim + inputStack[nStack - (s & VALUE)]; } - if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (t == LONG || t == DOUBLE)) { + if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 + && (t == LONG || t == DOUBLE)) { t = TOP; } } @@ -1363,19 +1381,19 @@ final class Frame { * type. Returns <tt>true</tt> if the type array has been modified by this * operation. * - * @param cw the ClassWriter to which this label belongs. - * @param t the type with which the type array element must be merged. - * @param types an array of types. - * @param index the index of the type that must be merged in 'types'. + * @param cw + * the ClassWriter to which this label belongs. + * @param t + * the type with which the type array element must be merged. + * @param types + * an array of types. + * @param index + * the index of the type that must be merged in 'types'. * @return <tt>true</tt> if the type array has been modified by this * operation. */ - private static boolean merge( - final ClassWriter cw, - int t, - final int[] types, - final int index) - { + private static boolean merge(final ClassWriter cw, int t, + final int[] types, final int index) { int u = types[index]; if (u == t) { // if the types are equal, merge(u,t)=u, so there is no change diff --git a/src/asm/scala/tools/asm/Handle.java b/src/asm/scala/tools/asm/Handle.java index be8f334192..5dd06a54b9 100644 --- a/src/asm/scala/tools/asm/Handle.java +++ b/src/asm/scala/tools/asm/Handle.java @@ -66,18 +66,23 @@ public final class Handle { /** * Constructs a new field or method handle. * - * @param tag the kind of field or method designated by this Handle. Must be - * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, - * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, - * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, - * {@link Opcodes#H_INVOKESPECIAL}, - * {@link Opcodes#H_NEWINVOKESPECIAL} or - * {@link Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of the field or method designed by this - * handle. - * @param name the name of the field or method designated by this handle. - * @param desc the descriptor of the field or method designated by this - * handle. + * @param tag + * the kind of field or method designated by this Handle. Must be + * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, + * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, + * {@link Opcodes#H_INVOKEVIRTUAL}, + * {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or + * {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner + * the internal name of the field or method designed by this + * handle. + * @param name + * the name of the field or method designated by this handle. + * @param desc + * the descriptor of the field or method designated by this + * handle. */ public Handle(int tag, String owner, String name, String desc) { this.tag = tag; @@ -101,11 +106,9 @@ public final class Handle { } /** - * Returns the internal name of the field or method designed by this - * handle. + * Returns the internal name of the field or method designed by this handle. * - * @return the internal name of the field or method designed by this - * handle. + * @return the internal name of the field or method designed by this handle. */ public String getOwner() { return owner; @@ -138,8 +141,8 @@ public final class Handle { return false; } Handle h = (Handle) obj; - return tag == h.tag && owner.equals(h.owner) - && name.equals(h.name) && desc.equals(h.desc); + return tag == h.tag && owner.equals(h.owner) && name.equals(h.name) + && desc.equals(h.desc); } @Override @@ -149,8 +152,13 @@ public final class Handle { /** * Returns the textual representation of this handle. The textual - * representation is: <pre>owner '.' name desc ' ' '(' tag ')'</pre>. As - * this format is unambiguous, it can be parsed if necessary. + * representation is: + * + * <pre> + * owner '.' name desc ' ' '(' tag ')' + * </pre> + * + * . As this format is unambiguous, it can be parsed if necessary. */ @Override public String toString() { diff --git a/src/asm/scala/tools/asm/Handler.java b/src/asm/scala/tools/asm/Handler.java index 9e92bb98be..a06cb8152a 100644 --- a/src/asm/scala/tools/asm/Handler.java +++ b/src/asm/scala/tools/asm/Handler.java @@ -72,9 +72,12 @@ class Handler { * Removes the range between start and end from the given exception * handlers. * - * @param h an exception handler list. - * @param start the start of the range to be removed. - * @param end the end of the range to be removed. Maybe null. + * @param h + * an exception handler list. + * @param start + * the start of the range to be removed. + * @param end + * the end of the range to be removed. Maybe null. * @return the exception handler list with the start-end range removed. */ static Handler remove(Handler h, Label start, Label end) { diff --git a/src/asm/scala/tools/asm/Item.java b/src/asm/scala/tools/asm/Item.java index 021a0b11d3..94195a1082 100644 --- a/src/asm/scala/tools/asm/Item.java +++ b/src/asm/scala/tools/asm/Item.java @@ -53,8 +53,8 @@ final class Item { * {@link ClassWriter#METH}, {@link ClassWriter#IMETH}, * {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}. * - * MethodHandle constant 9 variations are stored using a range - * of 9 values from {@link ClassWriter#HANDLE_BASE} + 1 to + * MethodHandle constant 9 variations are stored using a range of 9 values + * from {@link ClassWriter#HANDLE_BASE} + 1 to * {@link ClassWriter#HANDLE_BASE} + 9. * * Special Item types are used for Items that are stored in the ClassWriter @@ -115,7 +115,8 @@ final class Item { * Constructs an uninitialized {@link Item} for constant pool element at * given position. * - * @param index index of the item to be constructed. + * @param index + * index of the item to be constructed. */ Item(final int index) { this.index = index; @@ -124,8 +125,10 @@ final class Item { /** * Constructs a copy of the given item. * - * @param index index of the item to be constructed. - * @param i the item that must be copied into the item to be constructed. + * @param index + * index of the item to be constructed. + * @param i + * the item that must be copied into the item to be constructed. */ Item(final int index, final Item i) { this.index = index; @@ -141,7 +144,8 @@ final class Item { /** * Sets this item to an integer item. * - * @param intVal the value of this item. + * @param intVal + * the value of this item. */ void set(final int intVal) { this.type = ClassWriter.INT; @@ -152,7 +156,8 @@ final class Item { /** * Sets this item to a long item. * - * @param longVal the value of this item. + * @param longVal + * the value of this item. */ void set(final long longVal) { this.type = ClassWriter.LONG; @@ -163,7 +168,8 @@ final class Item { /** * Sets this item to a float item. * - * @param floatVal the value of this item. + * @param floatVal + * the value of this item. */ void set(final float floatVal) { this.type = ClassWriter.FLOAT; @@ -174,7 +180,8 @@ final class Item { /** * Sets this item to a double item. * - * @param doubleVal the value of this item. + * @param doubleVal + * the value of this item. */ void set(final double doubleVal) { this.type = ClassWriter.DOUBLE; @@ -185,49 +192,53 @@ final class Item { /** * Sets this item to an item that do not hold a primitive value. * - * @param type the type of this item. - * @param strVal1 first part of the value of this item. - * @param strVal2 second part of the value of this item. - * @param strVal3 third part of the value of this item. + * @param type + * the type of this item. + * @param strVal1 + * first part of the value of this item. + * @param strVal2 + * second part of the value of this item. + * @param strVal3 + * third part of the value of this item. */ - void set( - final int type, - final String strVal1, - final String strVal2, - final String strVal3) - { + void set(final int type, final String strVal1, final String strVal2, + final String strVal3) { this.type = type; this.strVal1 = strVal1; this.strVal2 = strVal2; this.strVal3 = strVal3; switch (type) { - case ClassWriter.UTF8: - case ClassWriter.STR: - case ClassWriter.CLASS: - case ClassWriter.MTYPE: - case ClassWriter.TYPE_NORMAL: - hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()); - return; - case ClassWriter.NAME_TYPE: - hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() - * strVal2.hashCode()); - return; - // ClassWriter.FIELD: - // ClassWriter.METH: - // ClassWriter.IMETH: - // ClassWriter.HANDLE_BASE + 1..9 - default: - hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() - * strVal2.hashCode() * strVal3.hashCode()); + case ClassWriter.UTF8: + case ClassWriter.STR: + case ClassWriter.CLASS: + case ClassWriter.MTYPE: + case ClassWriter.TYPE_NORMAL: + hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()); + return; + case ClassWriter.NAME_TYPE: { + hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() + * strVal2.hashCode()); + return; + } + // ClassWriter.FIELD: + // ClassWriter.METH: + // ClassWriter.IMETH: + // ClassWriter.HANDLE_BASE + 1..9 + default: + hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() + * strVal2.hashCode() * strVal3.hashCode()); } } /** * Sets the item to an InvokeDynamic item. * - * @param name invokedynamic's name. - * @param desc invokedynamic's desc. - * @param bsmIndex zero based index into the class attribute BootrapMethods. + * @param name + * invokedynamic's name. + * @param desc + * invokedynamic's desc. + * @param bsmIndex + * zero based index into the class attribute BootrapMethods. */ void set(String name, String desc, int bsmIndex) { this.type = ClassWriter.INDY; @@ -241,10 +252,12 @@ final class Item { /** * Sets the item to a BootstrapMethod item. * - * @param position position in byte in the class attribute BootrapMethods. - * @param hashCode hashcode of the item. This hashcode is processed from - * the hashcode of the bootstrap method and the hashcode of - * all bootstrap arguments. + * @param position + * position in byte in the class attribute BootrapMethods. + * @param hashCode + * hashcode of the item. This hashcode is processed from the + * hashcode of the bootstrap method and the hashcode of all + * bootstrap arguments. */ void set(int position, int hashCode) { this.type = ClassWriter.BSM; @@ -256,41 +269,42 @@ final class Item { * Indicates if the given item is equal to this one. <i>This method assumes * that the two items have the same {@link #type}</i>. * - * @param i the item to be compared to this one. Both items must have the - * same {@link #type}. + * @param i + * the item to be compared to this one. Both items must have the + * same {@link #type}. * @return <tt>true</tt> if the given item if equal to this one, * <tt>false</tt> otherwise. */ boolean isEqualTo(final Item i) { switch (type) { - case ClassWriter.UTF8: - case ClassWriter.STR: - case ClassWriter.CLASS: - case ClassWriter.MTYPE: - case ClassWriter.TYPE_NORMAL: - return i.strVal1.equals(strVal1); - case ClassWriter.TYPE_MERGED: - case ClassWriter.LONG: - case ClassWriter.DOUBLE: - return i.longVal == longVal; - case ClassWriter.INT: - case ClassWriter.FLOAT: - return i.intVal == intVal; - case ClassWriter.TYPE_UNINIT: - return i.intVal == intVal && i.strVal1.equals(strVal1); - case ClassWriter.NAME_TYPE: - return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2); - case ClassWriter.INDY: - return i.longVal == longVal && i.strVal1.equals(strVal1) - && i.strVal2.equals(strVal2); - - // case ClassWriter.FIELD: - // case ClassWriter.METH: - // case ClassWriter.IMETH: - // case ClassWriter.HANDLE_BASE + 1..9 - default: - return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2) - && i.strVal3.equals(strVal3); + case ClassWriter.UTF8: + case ClassWriter.STR: + case ClassWriter.CLASS: + case ClassWriter.MTYPE: + case ClassWriter.TYPE_NORMAL: + return i.strVal1.equals(strVal1); + case ClassWriter.TYPE_MERGED: + case ClassWriter.LONG: + case ClassWriter.DOUBLE: + return i.longVal == longVal; + case ClassWriter.INT: + case ClassWriter.FLOAT: + return i.intVal == intVal; + case ClassWriter.TYPE_UNINIT: + return i.intVal == intVal && i.strVal1.equals(strVal1); + case ClassWriter.NAME_TYPE: + return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2); + case ClassWriter.INDY: { + return i.longVal == longVal && i.strVal1.equals(strVal1) + && i.strVal2.equals(strVal2); + } + // case ClassWriter.FIELD: + // case ClassWriter.METH: + // case ClassWriter.IMETH: + // case ClassWriter.HANDLE_BASE + 1..9 + default: + return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2) + && i.strVal3.equals(strVal3); } } diff --git a/src/asm/scala/tools/asm/Label.java b/src/asm/scala/tools/asm/Label.java index 712c7f251f..5d5529ce74 100644 --- a/src/asm/scala/tools/asm/Label.java +++ b/src/asm/scala/tools/asm/Label.java @@ -32,9 +32,9 @@ package scala.tools.asm; /** * A label represents a position in the bytecode of a method. Labels are used * for jump, goto, and switch instructions, and for try catch blocks. A label - * designates the <i>instruction</i> that is just after. Note however that - * there can be other elements between a label and the instruction it - * designates (such as other labels, stack map frames, line numbers, etc.). + * designates the <i>instruction</i> that is just after. Note however that there + * can be other elements between a label and the instruction it designates (such + * as other labels, stack map frames, line numbers, etc.). * * @author Eric Bruneton */ @@ -110,8 +110,8 @@ public class Label { /** * Field used to associate user information to a label. Warning: this field * is used by the ASM tree package. In order to use it with the ASM tree - * package you must override the {@link - * org.objectweb.asm.tree.MethodNode#getLabelNode} method. + * package you must override the + * {@link scala.tools.asm.tree.MethodNode#getLabelNode} method. */ public Object info; @@ -154,7 +154,7 @@ public class Label { * indicates if this reference uses 2 or 4 bytes, and its absolute value * gives the position of the bytecode instruction. This array is also used * as a bitset to store the subroutines to which a basic block belongs. This - * information is needed in {@linked MethodWriter#visitMaxs}, after all + * information is needed in {@linked MethodWriter#visitMaxs}, after all * forward references have been resolved. Hence the same array can be used * for both purposes without problems. */ @@ -177,11 +177,11 @@ public class Label { * state of the local variables and the operand stack at the end of each * basic block, called the "output frame", <i>relatively</i> to the frame * state at the beginning of the basic block, which is called the "input - * frame", and which is <i>unknown</i> during this step. The second step, - * in {@link MethodWriter#visitMaxs}, is a fix point algorithm that - * computes information about the input frame of each basic block, from the - * input state of the first basic block (known from the method signature), - * and by the using the previously computed relative output frames. + * frame", and which is <i>unknown</i> during this step. The second step, in + * {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes + * information about the input frame of each basic block, from the input + * state of the first basic block (known from the method signature), and by + * the using the previously computed relative output frames. * * The algorithm used to compute the maximum stack size only computes the * relative output and absolute input stack heights, while the algorithm @@ -266,11 +266,13 @@ public class Label { * generators or adapters.</i> * * @return the offset corresponding to this label. - * @throws IllegalStateException if this label is not resolved yet. + * @throws IllegalStateException + * if this label is not resolved yet. */ public int getOffset() { if ((status & RESOLVED) == 0) { - throw new IllegalStateException("Label offset position has not been resolved yet"); + throw new IllegalStateException( + "Label offset position has not been resolved yet"); } return position; } @@ -281,21 +283,21 @@ public class Label { * directly. Otherwise, a null offset is written and a new forward reference * is declared for this label. * - * @param owner the code writer that calls this method. - * @param out the bytecode of the method. - * @param source the position of first byte of the bytecode instruction that - * contains this label. - * @param wideOffset <tt>true</tt> if the reference must be stored in 4 - * bytes, or <tt>false</tt> if it must be stored with 2 bytes. - * @throws IllegalArgumentException if this label has not been created by - * the given code writer. - */ - void put( - final MethodWriter owner, - final ByteVector out, - final int source, - final boolean wideOffset) - { + * @param owner + * the code writer that calls this method. + * @param out + * the bytecode of the method. + * @param source + * the position of first byte of the bytecode instruction that + * contains this label. + * @param wideOffset + * <tt>true</tt> if the reference must be stored in 4 bytes, or + * <tt>false</tt> if it must be stored with 2 bytes. + * @throws IllegalArgumentException + * if this label has not been created by the given code writer. + */ + void put(final MethodWriter owner, final ByteVector out, final int source, + final boolean wideOffset) { if ((status & RESOLVED) == 0) { if (wideOffset) { addReference(-1 - source, out.length); @@ -319,25 +321,21 @@ public class Label { * yet. For backward references, the offset of the reference can be, and * must be, computed and stored directly. * - * @param sourcePosition the position of the referencing instruction. This - * position will be used to compute the offset of this forward - * reference. - * @param referencePosition the position where the offset for this forward - * reference must be stored. - */ - private void addReference( - final int sourcePosition, - final int referencePosition) - { + * @param sourcePosition + * the position of the referencing instruction. This position + * will be used to compute the offset of this forward reference. + * @param referencePosition + * the position where the offset for this forward reference must + * be stored. + */ + private void addReference(final int sourcePosition, + final int referencePosition) { if (srcAndRefPositions == null) { srcAndRefPositions = new int[6]; } if (referenceCount >= srcAndRefPositions.length) { int[] a = new int[srcAndRefPositions.length + 6]; - System.arraycopy(srcAndRefPositions, - 0, - a, - 0, + System.arraycopy(srcAndRefPositions, 0, a, 0, srcAndRefPositions.length); srcAndRefPositions = a; } @@ -351,9 +349,12 @@ public class Label { * position becomes known. This method fills in the blanks that where left * in the bytecode by each forward reference previously added to this label. * - * @param owner the code writer that calls this method. - * @param position the position of this label in the bytecode. - * @param data the bytecode of the method. + * @param owner + * the code writer that calls this method. + * @param position + * the position of this label in the bytecode. + * @param data + * the bytecode of the method. * @return <tt>true</tt> if a blank that was left for this label was to * small to store the offset. In such a case the corresponding jump * instruction is replaced with a pseudo instruction (using unused @@ -361,14 +362,12 @@ public class Label { * instructions will need to be replaced with true instructions with * wider offsets (4 bytes instead of 2). This is done in * {@link MethodWriter#resizeInstructions}. - * @throws IllegalArgumentException if this label has already been resolved, - * or if it has not been created by the given code writer. - */ - boolean resolve( - final MethodWriter owner, - final int position, - final byte[] data) - { + * @throws IllegalArgumentException + * if this label has already been resolved, or if it has not + * been created by the given code writer. + */ + boolean resolve(final MethodWriter owner, final int position, + final byte[] data) { boolean needUpdate = false; this.status |= RESOLVED; this.position = position; @@ -431,7 +430,8 @@ public class Label { /** * Returns true is this basic block belongs to the given subroutine. * - * @param id a subroutine id. + * @param id + * a subroutine id. * @return true is this basic block belongs to the given subroutine. */ boolean inSubroutine(final long id) { @@ -445,7 +445,8 @@ public class Label { * Returns true if this basic block and the given one belong to a common * subroutine. * - * @param block another basic block. + * @param block + * another basic block. * @return true if this basic block and the given one belong to a common * subroutine. */ @@ -464,8 +465,10 @@ public class Label { /** * Marks this basic block as belonging to the given subroutine. * - * @param id a subroutine id. - * @param nbSubroutines the total number of subroutines in the method. + * @param id + * a subroutine id. + * @param nbSubroutines + * the total number of subroutines in the method. */ void addToSubroutine(final long id, final int nbSubroutines) { if ((status & VISITED) == 0) { @@ -481,14 +484,16 @@ public class Label { * flow graph to find all the blocks that are reachable from the current * block WITHOUT following any JSR target. * - * @param JSR a JSR block that jumps to this subroutine. If this JSR is not - * null it is added to the successor of the RET blocks found in the - * subroutine. - * @param id the id of this subroutine. - * @param nbSubroutines the total number of subroutines in the method. - */ - void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) - { + * @param JSR + * a JSR block that jumps to this subroutine. If this JSR is not + * null it is added to the successor of the RET blocks found in + * the subroutine. + * @param id + * the id of this subroutine. + * @param nbSubroutines + * the total number of subroutines in the method. + */ + void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) { // user managed stack of labels, to avoid using a recursive method // (recursivity can lead to stack overflow with very large methods) Label stack = this; diff --git a/src/asm/scala/tools/asm/MethodVisitor.java b/src/asm/scala/tools/asm/MethodVisitor.java index a8a859a6a9..e43ca97823 100644 --- a/src/asm/scala/tools/asm/MethodVisitor.java +++ b/src/asm/scala/tools/asm/MethodVisitor.java @@ -30,19 +30,19 @@ package scala.tools.asm; /** - * A visitor to visit a Java method. The methods of this class must be - * called in the following order: [ <tt>visitAnnotationDefault</tt> ] ( + * A visitor to visit a Java method. The methods of this class must be called in + * the following order: [ <tt>visitAnnotationDefault</tt> ] ( * <tt>visitAnnotation</tt> | <tt>visitParameterAnnotation</tt> | * <tt>visitAttribute</tt> )* [ <tt>visitCode</tt> ( <tt>visitFrame</tt> | - * <tt>visit</tt><i>X</i>Insn</tt> | <tt>visitLabel</tt> | <tt>visitTryCatchBlock</tt> | - * <tt>visitLocalVariable</tt> | <tt>visitLineNumber</tt> )* <tt>visitMaxs</tt> ] - * <tt>visitEnd</tt>. In addition, the <tt>visit</tt><i>X</i>Insn</tt> - * and <tt>visitLabel</tt> methods must be called in the sequential order of - * the bytecode instructions of the visited code, <tt>visitTryCatchBlock</tt> - * must be called <i>before</i> the labels passed as arguments have been - * visited, and the <tt>visitLocalVariable</tt> and <tt>visitLineNumber</tt> - * methods must be called <i>after</i> the labels passed as arguments have been - * visited. + * <tt>visit</tt><i>X</i>Insn</tt> | <tt>visitLabel</tt> | + * <tt>visitTryCatchBlock</tt> | <tt>visitLocalVariable</tt> | + * <tt>visitLineNumber</tt> )* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In + * addition, the <tt>visit</tt><i>X</i>Insn</tt> and <tt>visitLabel</tt> methods + * must be called in the sequential order of the bytecode instructions of the + * visited code, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the + * labels passed as arguments have been visited, and the + * <tt>visitLocalVariable</tt> and <tt>visitLineNumber</tt> methods must be + * called <i>after</i> the labels passed as arguments have been visited. * * @author Eric Bruneton */ @@ -63,8 +63,9 @@ public abstract class MethodVisitor { /** * Constructs a new {@link MethodVisitor}. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. */ public MethodVisitor(final int api) { this(api, null); @@ -73,15 +74,17 @@ public abstract class MethodVisitor { /** * Constructs a new {@link MethodVisitor}. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. - * @param mv the method visitor to which this visitor must delegate method - * calls. May be null. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param mv + * the method visitor to which this visitor must delegate method + * calls. May be null. */ public MethodVisitor(final int api, final MethodVisitor mv) { - /*if (api != Opcodes.ASM4) { + if (api != Opcodes.ASM4) { throw new IllegalArgumentException(); - }*/ + } this.api = api; this.mv = mv; } @@ -94,8 +97,8 @@ public abstract class MethodVisitor { * Visits the default value of this annotation interface method. * * @return a visitor to the visit the actual default value of this - * annotation interface method, or <tt>null</tt> if this visitor - * is not interested in visiting this default value. The 'name' + * annotation interface method, or <tt>null</tt> if this visitor is + * not interested in visiting this default value. The 'name' * parameters passed to the methods of this annotation visitor are * ignored. Moreover, exacly one visit method must be called on this * annotation visitor, followed by visitEnd. @@ -110,8 +113,10 @@ public abstract class MethodVisitor { /** * Visits an annotation of this method. * - * @param desc the class descriptor of the annotation class. - * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * <tt>true</tt> if the annotation is visible at runtime. * @return a visitor to visit the annotation values, or <tt>null</tt> if * this visitor is not interested in visiting this annotation. */ @@ -125,17 +130,17 @@ public abstract class MethodVisitor { /** * Visits an annotation of a parameter this method. * - * @param parameter the parameter index. - * @param desc the class descriptor of the annotation class. - * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @param parameter + * the parameter index. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * <tt>true</tt> if the annotation is visible at runtime. * @return a visitor to visit the annotation values, or <tt>null</tt> if * this visitor is not interested in visiting this annotation. */ - public AnnotationVisitor visitParameterAnnotation( - int parameter, - String desc, - boolean visible) - { + public AnnotationVisitor visitParameterAnnotation(int parameter, + String desc, boolean visible) { if (mv != null) { return mv.visitParameterAnnotation(parameter, desc, visible); } @@ -145,7 +150,8 @@ public abstract class MethodVisitor { /** * Visits a non standard attribute of this method. * - * @param attr an attribute. + * @param attr + * an attribute. */ public void visitAttribute(Attribute attr) { if (mv != null) { @@ -169,57 +175,74 @@ public abstract class MethodVisitor { * such as GOTO or THROW, that is the target of a jump instruction, or that * starts an exception handler block. The visited types must describe the * values of the local variables and of the operand stack elements <i>just - * before</i> <b>i</b> is executed. <br> <br> (*) this is mandatory only - * for classes whose version is greater than or equal to - * {@link Opcodes#V1_6 V1_6}. <br> <br> Packed frames are basically - * "deltas" from the state of the previous frame (very first frame is - * implicitly defined by the method's parameters and access flags): <ul> + * before</i> <b>i</b> is executed.<br> + * <br> + * (*) this is mandatory only for classes whose version is greater than or + * equal to {@link Opcodes#V1_6 V1_6}. <br> + * <br> + * The frames of a method must be given either in expanded form, or in + * compressed form (all frames must use the same format, i.e. you must not + * mix expanded and compressed frames within a single method): + * <ul> + * <li>In expanded form, all frames must have the F_NEW type.</li> + * <li>In compressed form, frames are basically "deltas" from the state of + * the previous frame: + * <ul> * <li>{@link Opcodes#F_SAME} representing frame with exactly the same - * locals as the previous frame and with the empty stack.</li> <li>{@link Opcodes#F_SAME1} - * representing frame with exactly the same locals as the previous frame and - * with single value on the stack (<code>nStack</code> is 1 and - * <code>stack[0]</code> contains value for the type of the stack item).</li> + * locals as the previous frame and with the empty stack.</li> + * <li>{@link Opcodes#F_SAME1} representing frame with exactly the same + * locals as the previous frame and with single value on the stack ( + * <code>nStack</code> is 1 and <code>stack[0]</code> contains value for the + * type of the stack item).</li> * <li>{@link Opcodes#F_APPEND} representing frame with current locals are * the same as the locals in the previous frame, except that additional * locals are defined (<code>nLocal</code> is 1, 2 or 3 and * <code>local</code> elements contains values representing added types).</li> - * <li>{@link Opcodes#F_CHOP} representing frame with current locals are - * the same as the locals in the previous frame, except that the last 1-3 - * locals are absent and with the empty stack (<code>nLocals</code> is 1, - * 2 or 3). </li> <li>{@link Opcodes#F_FULL} representing complete frame - * data.</li> </li> </ul> + * <li>{@link Opcodes#F_CHOP} representing frame with current locals are the + * same as the locals in the previous frame, except that the last 1-3 locals + * are absent and with the empty stack (<code>nLocals</code> is 1, 2 or 3).</li> + * <li>{@link Opcodes#F_FULL} representing complete frame data.</li></li> + * </ul> + * </ul> <br> + * In both cases the first frame, corresponding to the method's parameters + * and access flags, is implicit and must not be visited. Also, it is + * illegal to visit two or more frames for the same code location (i.e., at + * least one instruction must be visited between two calls to visitFrame). * - * @param type the type of this stack map frame. Must be - * {@link Opcodes#F_NEW} for expanded frames, or - * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, - * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or - * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed - * frames. - * @param nLocal the number of local variables in the visited frame. - * @param local the local variable types in this frame. This array must not - * be modified. Primitive types are represented by - * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, - * {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, - * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or - * {@link Opcodes#UNINITIALIZED_THIS} (long and double are - * represented by a single element). Reference types are represented - * by String objects (representing internal names), and uninitialized - * types by Label objects (this label designates the NEW instruction - * that created this uninitialized value). - * @param nStack the number of operand stack elements in the visited frame. - * @param stack the operand stack types in this frame. This array must not - * be modified. Its content has the same format as the "local" array. - * @throws IllegalStateException if a frame is visited just after another - * one, without any instruction between the two (unless this frame - * is a Opcodes#F_SAME frame, in which case it is silently ignored). + * @param type + * the type of this stack map frame. Must be + * {@link Opcodes#F_NEW} for expanded frames, or + * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, + * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or + * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for + * compressed frames. + * @param nLocal + * the number of local variables in the visited frame. + * @param local + * the local variable types in this frame. This array must not be + * modified. Primitive types are represented by + * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, + * {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, + * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or + * {@link Opcodes#UNINITIALIZED_THIS} (long and double are + * represented by a single element). Reference types are + * represented by String objects (representing internal names), + * and uninitialized types by Label objects (this label + * designates the NEW instruction that created this uninitialized + * value). + * @param nStack + * the number of operand stack elements in the visited frame. + * @param stack + * the operand stack types in this frame. This array must not be + * modified. Its content has the same format as the "local" + * array. + * @throws IllegalStateException + * if a frame is visited just after another one, without any + * instruction between the two (unless this frame is a + * Opcodes#F_SAME frame, in which case it is silently ignored). */ - public void visitFrame( - int type, - int nLocal, - Object[] local, - int nStack, - Object[] stack) - { + public void visitFrame(int type, int nLocal, Object[] local, int nStack, + Object[] stack) { if (mv != null) { mv.visitFrame(type, nLocal, local, nStack, stack); } @@ -232,20 +255,22 @@ public abstract class MethodVisitor { /** * Visits a zero operand instruction. * - * @param opcode the opcode of the instruction to be visited. This opcode is - * either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, - * ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, FCONST_0, - * FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD, FALOAD, - * DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, FASTORE, - * DASTORE, AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, - * DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP, IADD, LADD, FADD, - * DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, - * FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, - * LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, - * I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, - * I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, - * FRETURN, DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, - * MONITORENTER, or MONITOREXIT. + * @param opcode + * the opcode of the instruction to be visited. This opcode is + * either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, + * ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, + * FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, + * LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, + * IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, + * SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, + * DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, + * IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM, + * FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, + * IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D, + * L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S, + * LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN, + * DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, + * or MONITOREXIT. */ public void visitInsn(int opcode) { if (mv != null) { @@ -256,17 +281,20 @@ public abstract class MethodVisitor { /** * Visits an instruction with a single int operand. * - * @param opcode the opcode of the instruction to be visited. This opcode is - * either BIPUSH, SIPUSH or NEWARRAY. - * @param operand the operand of the instruction to be visited.<br> When - * opcode is BIPUSH, operand value should be between Byte.MIN_VALUE - * and Byte.MAX_VALUE.<br> When opcode is SIPUSH, operand value - * should be between Short.MIN_VALUE and Short.MAX_VALUE.<br> When - * opcode is NEWARRAY, operand value should be one of - * {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR}, - * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, - * {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT}, - * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}. + * @param opcode + * the opcode of the instruction to be visited. This opcode is + * either BIPUSH, SIPUSH or NEWARRAY. + * @param operand + * the operand of the instruction to be visited.<br> + * When opcode is BIPUSH, operand value should be between + * Byte.MIN_VALUE and Byte.MAX_VALUE.<br> + * When opcode is SIPUSH, operand value should be between + * Short.MIN_VALUE and Short.MAX_VALUE.<br> + * When opcode is NEWARRAY, operand value should be one of + * {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR}, + * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, + * {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT}, + * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}. */ public void visitIntInsn(int opcode, int operand) { if (mv != null) { @@ -278,11 +306,13 @@ public abstract class MethodVisitor { * Visits a local variable instruction. A local variable instruction is an * instruction that loads or stores the value of a local variable. * - * @param opcode the opcode of the local variable instruction to be visited. - * This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, - * LSTORE, FSTORE, DSTORE, ASTORE or RET. - * @param var the operand of the instruction to be visited. This operand is - * the index of a local variable. + * @param opcode + * the opcode of the local variable instruction to be visited. + * This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, + * ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET. + * @param var + * the operand of the instruction to be visited. This operand is + * the index of a local variable. */ public void visitVarInsn(int opcode, int var) { if (mv != null) { @@ -294,11 +324,13 @@ public abstract class MethodVisitor { * Visits a type instruction. A type instruction is an instruction that * takes the internal name of a class as parameter. * - * @param opcode the opcode of the type instruction to be visited. This - * opcode is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. - * @param type the operand of the instruction to be visited. This operand - * must be the internal name of an object or array class (see {@link - * Type#getInternalName() getInternalName}). + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. + * @param type + * the operand of the instruction to be visited. This operand + * must be the internal name of an object or array class (see + * {@link Type#getInternalName() getInternalName}). */ public void visitTypeInsn(int opcode, String type) { if (mv != null) { @@ -310,14 +342,19 @@ public abstract class MethodVisitor { * Visits a field instruction. A field instruction is an instruction that * loads or stores the value of a field of an object. * - * @param opcode the opcode of the type instruction to be visited. This - * opcode is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. - * @param owner the internal name of the field's owner class (see {@link - * Type#getInternalName() getInternalName}). - * @param name the field's name. - * @param desc the field's descriptor (see {@link Type Type}). + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. + * @param owner + * the internal name of the field's owner class (see + * {@link Type#getInternalName() getInternalName}). + * @param name + * the field's name. + * @param desc + * the field's descriptor (see {@link Type Type}). */ - public void visitFieldInsn(int opcode, String owner, String name, String desc) { + public void visitFieldInsn(int opcode, String owner, String name, + String desc) { if (mv != null) { mv.visitFieldInsn(opcode, owner, name, desc); } @@ -327,15 +364,20 @@ public abstract class MethodVisitor { * Visits a method instruction. A method instruction is an instruction that * invokes a method. * - * @param opcode the opcode of the type instruction to be visited. This - * opcode is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC - * or INVOKEINTERFACE. - * @param owner the internal name of the method's owner class (see {@link - * Type#getInternalName() getInternalName}). - * @param name the method's name. - * @param desc the method's descriptor (see {@link Type Type}). + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or + * INVOKEINTERFACE. + * @param owner + * the internal name of the method's owner class (see + * {@link Type#getInternalName() getInternalName}). + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link Type Type}). */ - public void visitMethodInsn(int opcode, String owner, String name, String desc) { + public void visitMethodInsn(int opcode, String owner, String name, + String desc) { if (mv != null) { mv.visitMethodInsn(opcode, owner, name, desc); } @@ -344,16 +386,21 @@ public abstract class MethodVisitor { /** * Visits an invokedynamic instruction. * - * @param name the method's name. - * @param desc the method's descriptor (see {@link Type Type}). - * @param bsm the bootstrap method. - * @param bsmArgs the bootstrap method constant arguments. Each argument - * must be an {@link Integer}, {@link Float}, {@link Long}, - * {@link Double}, {@link String}, {@link Type} or {@link Handle} - * value. This method is allowed to modify the content of the array - * so a caller should expect that this array may change. + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link Type Type}). + * @param bsm + * the bootstrap method. + * @param bsmArgs + * the bootstrap method constant arguments. Each argument must be + * an {@link Integer}, {@link Float}, {@link Long}, + * {@link Double}, {@link String}, {@link Type} or {@link Handle} + * value. This method is allowed to modify the content of the + * array so a caller should expect that this array may change. */ - public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, + Object... bsmArgs) { if (mv != null) { mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); } @@ -363,13 +410,15 @@ public abstract class MethodVisitor { * Visits a jump instruction. A jump instruction is an instruction that may * jump to another instruction. * - * @param opcode the opcode of the type instruction to be visited. This - * opcode is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, - * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, - * IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL. - * @param label the operand of the instruction to be visited. This operand - * is a label that designates the instruction to which the jump - * instruction may jump. + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, + * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, + * IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL. + * @param label + * the operand of the instruction to be visited. This operand is + * a label that designates the instruction to which the jump + * instruction may jump. */ public void visitJumpInsn(int opcode, Label label) { if (mv != null) { @@ -381,7 +430,8 @@ public abstract class MethodVisitor { * Visits a label. A label designates the instruction that will be visited * just after it. * - * @param label a {@link Label Label} object. + * @param label + * a {@link Label Label} object. */ public void visitLabel(Label label) { if (mv != null) { @@ -398,41 +448,44 @@ public abstract class MethodVisitor { * future versions of the Java Virtual Machine. To easily detect new * constant types, implementations of this method should check for * unexpected constant types, like this: + * * <pre> * if (cst instanceof Integer) { - * // ... + * // ... * } else if (cst instanceof Float) { - * // ... + * // ... * } else if (cst instanceof Long) { - * // ... - * } else if (cst instanceof Double) { - * // ... - * } else if (cst instanceof String) { - * // ... - * } else if (cst instanceof Type) { - * int sort = ((Type) cst).getSort(); - * if (sort == Type.OBJECT) { * // ... - * } else if (sort == Type.ARRAY) { + * } else if (cst instanceof Double) { * // ... - * } else if (sort == Type.METHOD) { + * } else if (cst instanceof String) { * // ... - * } else { - * // throw an exception - * } + * } else if (cst instanceof Type) { + * int sort = ((Type) cst).getSort(); + * if (sort == Type.OBJECT) { + * // ... + * } else if (sort == Type.ARRAY) { + * // ... + * } else if (sort == Type.METHOD) { + * // ... + * } else { + * // throw an exception + * } * } else if (cst instanceof Handle) { - * // ... + * // ... * } else { - * // throw an exception - * }</pre> + * // throw an exception + * } + * </pre> * - * @param cst the constant to be loaded on the stack. This parameter must be - * a non null {@link Integer}, a {@link Float}, a {@link Long}, a - * {@link Double}, a {@link String}, a {@link Type} of OBJECT or ARRAY - * sort for <tt>.class</tt> constants, for classes whose version is - * 49.0, a {@link Type} of METHOD sort or a {@link Handle} for - * MethodType and MethodHandle constants, for classes whose version - * is 51.0. + * @param cst + * the constant to be loaded on the stack. This parameter must be + * a non null {@link Integer}, a {@link Float}, a {@link Long}, a + * {@link Double}, a {@link String}, a {@link Type} of OBJECT or + * ARRAY sort for <tt>.class</tt> constants, for classes whose + * version is 49.0, a {@link Type} of METHOD sort or a + * {@link Handle} for MethodType and MethodHandle constants, for + * classes whose version is 51.0. */ public void visitLdcInsn(Object cst) { if (mv != null) { @@ -443,8 +496,10 @@ public abstract class MethodVisitor { /** * Visits an IINC instruction. * - * @param var index of the local variable to be incremented. - * @param increment amount to increment the local variable by. + * @param var + * index of the local variable to be incremented. + * @param increment + * amount to increment the local variable by. */ public void visitIincInsn(int var, int increment) { if (mv != null) { @@ -455,13 +510,18 @@ public abstract class MethodVisitor { /** * Visits a TABLESWITCH instruction. * - * @param min the minimum key value. - * @param max the maximum key value. - * @param dflt beginning of the default handler block. - * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is - * the beginning of the handler block for the <tt>min + i</tt> key. + * @param min + * the minimum key value. + * @param max + * the maximum key value. + * @param dflt + * beginning of the default handler block. + * @param labels + * beginnings of the handler blocks. <tt>labels[i]</tt> is the + * beginning of the handler block for the <tt>min + i</tt> key. */ - public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) { + public void visitTableSwitchInsn(int min, int max, Label dflt, + Label... labels) { if (mv != null) { mv.visitTableSwitchInsn(min, max, dflt, labels); } @@ -470,10 +530,13 @@ public abstract class MethodVisitor { /** * Visits a LOOKUPSWITCH instruction. * - * @param dflt beginning of the default handler block. - * @param keys the values of the keys. - * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is - * the beginning of the handler block for the <tt>keys[i]</tt> key. + * @param dflt + * beginning of the default handler block. + * @param keys + * the values of the keys. + * @param labels + * beginnings of the handler blocks. <tt>labels[i]</tt> is the + * beginning of the handler block for the <tt>keys[i]</tt> key. */ public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { if (mv != null) { @@ -484,8 +547,10 @@ public abstract class MethodVisitor { /** * Visits a MULTIANEWARRAY instruction. * - * @param desc an array type descriptor (see {@link Type Type}). - * @param dims number of dimensions of the array to allocate. + * @param desc + * an array type descriptor (see {@link Type Type}). + * @param dims + * number of dimensions of the array to allocate. */ public void visitMultiANewArrayInsn(String desc, int dims) { if (mv != null) { @@ -500,17 +565,22 @@ public abstract class MethodVisitor { /** * Visits a try catch block. * - * @param start beginning of the exception handler's scope (inclusive). - * @param end end of the exception handler's scope (exclusive). - * @param handler beginning of the exception handler's code. - * @param type internal name of the type of exceptions handled by the - * handler, or <tt>null</tt> to catch any exceptions (for "finally" - * blocks). - * @throws IllegalArgumentException if one of the labels has already been - * visited by this visitor (by the {@link #visitLabel visitLabel} - * method). + * @param start + * beginning of the exception handler's scope (inclusive). + * @param end + * end of the exception handler's scope (exclusive). + * @param handler + * beginning of the exception handler's code. + * @param type + * internal name of the type of exceptions handled by the + * handler, or <tt>null</tt> to catch any exceptions (for + * "finally" blocks). + * @throws IllegalArgumentException + * if one of the labels has already been visited by this visitor + * (by the {@link #visitLabel visitLabel} method). */ - public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { + public void visitTryCatchBlock(Label start, Label end, Label handler, + String type) { if (mv != null) { mv.visitTryCatchBlock(start, end, handler, type); } @@ -519,28 +589,28 @@ public abstract class MethodVisitor { /** * Visits a local variable declaration. * - * @param name the name of a local variable. - * @param desc the type descriptor of this local variable. - * @param signature the type signature of this local variable. May be - * <tt>null</tt> if the local variable type does not use generic - * types. - * @param start the first instruction corresponding to the scope of this - * local variable (inclusive). - * @param end the last instruction corresponding to the scope of this local - * variable (exclusive). - * @param index the local variable's index. - * @throws IllegalArgumentException if one of the labels has not already - * been visited by this visitor (by the - * {@link #visitLabel visitLabel} method). + * @param name + * the name of a local variable. + * @param desc + * the type descriptor of this local variable. + * @param signature + * the type signature of this local variable. May be + * <tt>null</tt> if the local variable type does not use generic + * types. + * @param start + * the first instruction corresponding to the scope of this local + * variable (inclusive). + * @param end + * the last instruction corresponding to the scope of this local + * variable (exclusive). + * @param index + * the local variable's index. + * @throws IllegalArgumentException + * if one of the labels has not already been visited by this + * visitor (by the {@link #visitLabel visitLabel} method). */ - public void visitLocalVariable( - String name, - String desc, - String signature, - Label start, - Label end, - int index) - { + public void visitLocalVariable(String name, String desc, String signature, + Label start, Label end, int index) { if (mv != null) { mv.visitLocalVariable(name, desc, signature, start, end, index); } @@ -549,12 +619,14 @@ public abstract class MethodVisitor { /** * Visits a line number declaration. * - * @param line a line number. This number refers to the source file from - * which the class was compiled. - * @param start the first instruction corresponding to this line number. - * @throws IllegalArgumentException if <tt>start</tt> has not already been - * visited by this visitor (by the {@link #visitLabel visitLabel} - * method). + * @param line + * a line number. This number refers to the source file from + * which the class was compiled. + * @param start + * the first instruction corresponding to this line number. + * @throws IllegalArgumentException + * if <tt>start</tt> has not already been visited by this + * visitor (by the {@link #visitLabel visitLabel} method). */ public void visitLineNumber(int line, Label start) { if (mv != null) { @@ -566,8 +638,10 @@ public abstract class MethodVisitor { * Visits the maximum stack size and the maximum number of local variables * of the method. * - * @param maxStack maximum stack size of the method. - * @param maxLocals maximum number of local variables for the method. + * @param maxStack + * maximum stack size of the method. + * @param maxLocals + * maximum number of local variables for the method. */ public void visitMaxs(int maxStack, int maxLocals) { if (mv != null) { diff --git a/src/asm/scala/tools/asm/MethodWriter.java b/src/asm/scala/tools/asm/MethodWriter.java index 321bacb6fc..f5fbd1e74f 100644 --- a/src/asm/scala/tools/asm/MethodWriter.java +++ b/src/asm/scala/tools/asm/MethodWriter.java @@ -42,7 +42,7 @@ class MethodWriter extends MethodVisitor { /** * Pseudo access flag used to denote constructors. */ - static final int ACC_CONSTRUCTOR = 262144; + static final int ACC_CONSTRUCTOR = 0x80000; /** * Frame has exactly the same locals as the previous stack map frame and @@ -229,7 +229,7 @@ class MethodWriter extends MethodVisitor { private int maxLocals; /** - * Number of local variables in the current stack map frame. + * Number of local variables in the current stack map frame. */ private int currentLocals; @@ -257,11 +257,6 @@ class MethodWriter extends MethodVisitor { private int[] previousFrame; /** - * Index of the next element to be added in {@link #frame}. - */ - private int frameIndex; - - /** * The current stack map frame. The first element contains the offset of the * instruction to which the frame corresponds, the second element is the * number of locals and the third one is the number of stack elements. The @@ -357,7 +352,8 @@ class MethodWriter extends MethodVisitor { * A list of labels. This list is the list of basic blocks in the method, * i.e. a list of Label objects linked to each other by their * {@link Label#successor} field, in the order they are visited by - * {@link MethodVisitor#visitLabel}, and starting with the first basic block. + * {@link MethodVisitor#visitLabel}, and starting with the first basic + * block. */ private Label labels; @@ -396,28 +392,30 @@ class MethodWriter extends MethodVisitor { /** * Constructs a new {@link MethodWriter}. * - * @param cw the class writer in which the method must be added. - * @param access the method's access flags (see {@link Opcodes}). - * @param name the method's name. - * @param desc the method's descriptor (see {@link Type}). - * @param signature the method's signature. May be <tt>null</tt>. - * @param exceptions the internal names of the method's exceptions. May be - * <tt>null</tt>. - * @param computeMaxs <tt>true</tt> if the maximum stack size and number - * of local variables must be automatically computed. - * @param computeFrames <tt>true</tt> if the stack map tables must be - * recomputed from scratch. - */ - MethodWriter( - final ClassWriter cw, - final int access, - final String name, - final String desc, - final String signature, - final String[] exceptions, - final boolean computeMaxs, - final boolean computeFrames) - { + * @param cw + * the class writer in which the method must be added. + * @param access + * the method's access flags (see {@link Opcodes}). + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link Type}). + * @param signature + * the method's signature. May be <tt>null</tt>. + * @param exceptions + * the internal names of the method's exceptions. May be + * <tt>null</tt>. + * @param computeMaxs + * <tt>true</tt> if the maximum stack size and number of local + * variables must be automatically computed. + * @param computeFrames + * <tt>true</tt> if the stack map tables must be recomputed from + * scratch. + */ + MethodWriter(final ClassWriter cw, final int access, final String name, + final String desc, final String signature, + final String[] exceptions, final boolean computeMaxs, + final boolean computeFrames) { super(Opcodes.ASM4); if (cw.firstMethod == null) { cw.firstMethod = this; @@ -427,6 +425,9 @@ class MethodWriter extends MethodVisitor { cw.lastMethod = this; this.cw = cw; this.access = access; + if ("<init>".equals(name)) { + this.access |= ACC_CONSTRUCTOR; + } this.name = cw.newUTF8(name); this.desc = cw.newUTF8(desc); this.descriptor = desc; @@ -442,9 +443,6 @@ class MethodWriter extends MethodVisitor { } this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING); if (computeMaxs || computeFrames) { - if (computeFrames && "<init>".equals(name)) { - this.access |= ACC_CONSTRUCTOR; - } // updates maxLocals int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2; if ((access & Opcodes.ACC_STATIC) != 0) { @@ -473,10 +471,8 @@ class MethodWriter extends MethodVisitor { } @Override - public AnnotationVisitor visitAnnotation( - final String desc, - final boolean visible) - { + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { if (!ClassReader.ANNOTATIONS) { return null; } @@ -495,11 +491,8 @@ class MethodWriter extends MethodVisitor { } @Override - public AnnotationVisitor visitParameterAnnotation( - final int parameter, - final String desc, - final boolean visible) - { + public AnnotationVisitor visitParameterAnnotation(final int parameter, + final String desc, final boolean visible) { if (!ClassReader.ANNOTATIONS) { return null; } @@ -545,20 +538,18 @@ class MethodWriter extends MethodVisitor { } @Override - public void visitFrame( - final int type, - final int nLocal, - final Object[] local, - final int nStack, - final Object[] stack) - { + public void visitFrame(final int type, final int nLocal, + final Object[] local, final int nStack, final Object[] stack) { if (!ClassReader.FRAMES || compute == FRAMES) { return; } if (type == Opcodes.F_NEW) { + if (previousFrame == null) { + visitImplicitFirstFrame(); + } currentLocals = nLocal; - startFrame(code.length, nLocal, nStack); + int frameIndex = startFrame(code.length, nLocal, nStack); for (int i = 0; i < nLocal; ++i) { if (local[i] instanceof String) { frame[frameIndex++] = Frame.OBJECT @@ -601,48 +592,44 @@ class MethodWriter extends MethodVisitor { } switch (type) { - case Opcodes.F_FULL: - currentLocals = nLocal; - stackMap.putByte(FULL_FRAME) - .putShort(delta) - .putShort(nLocal); - for (int i = 0; i < nLocal; ++i) { - writeFrameType(local[i]); - } - stackMap.putShort(nStack); - for (int i = 0; i < nStack; ++i) { - writeFrameType(stack[i]); - } - break; - case Opcodes.F_APPEND: - currentLocals += nLocal; - stackMap.putByte(SAME_FRAME_EXTENDED + nLocal) - .putShort(delta); - for (int i = 0; i < nLocal; ++i) { - writeFrameType(local[i]); - } - break; - case Opcodes.F_CHOP: - currentLocals -= nLocal; - stackMap.putByte(SAME_FRAME_EXTENDED - nLocal) + case Opcodes.F_FULL: + currentLocals = nLocal; + stackMap.putByte(FULL_FRAME).putShort(delta).putShort(nLocal); + for (int i = 0; i < nLocal; ++i) { + writeFrameType(local[i]); + } + stackMap.putShort(nStack); + for (int i = 0; i < nStack; ++i) { + writeFrameType(stack[i]); + } + break; + case Opcodes.F_APPEND: + currentLocals += nLocal; + stackMap.putByte(SAME_FRAME_EXTENDED + nLocal).putShort(delta); + for (int i = 0; i < nLocal; ++i) { + writeFrameType(local[i]); + } + break; + case Opcodes.F_CHOP: + currentLocals -= nLocal; + stackMap.putByte(SAME_FRAME_EXTENDED - nLocal).putShort(delta); + break; + case Opcodes.F_SAME: + if (delta < 64) { + stackMap.putByte(delta); + } else { + stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); + } + break; + case Opcodes.F_SAME1: + if (delta < 64) { + stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); + } else { + stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) .putShort(delta); - break; - case Opcodes.F_SAME: - if (delta < 64) { - stackMap.putByte(delta); - } else { - stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); - } - break; - case Opcodes.F_SAME1: - if (delta < 64) { - stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); - } else { - stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) - .putShort(delta); - } - writeFrameType(stack[0]); - break; + } + writeFrameType(stack[0]); + break; } previousFrameOffset = code.length; @@ -672,8 +659,7 @@ class MethodWriter extends MethodVisitor { } // if opcode == ATHROW or xRETURN, ends current block (no successor) if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) - || opcode == Opcodes.ATHROW) - { + || opcode == Opcodes.ATHROW) { noSuccessor(); } } @@ -731,8 +717,7 @@ class MethodWriter extends MethodVisitor { // updates max locals int n; if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD - || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) - { + || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) { n = var + 2; } else { n = var + 1; @@ -784,12 +769,8 @@ class MethodWriter extends MethodVisitor { } @Override - public void visitFieldInsn( - final int opcode, - final String owner, - final String name, - final String desc) - { + public void visitFieldInsn(final int opcode, final String owner, + final String name, final String desc) { Item i = cw.newFieldItem(owner, name, desc); // Label currentBlock = this.currentBlock; if (currentBlock != null) { @@ -800,19 +781,19 @@ class MethodWriter extends MethodVisitor { // computes the stack size variation char c = desc.charAt(0); switch (opcode) { - case Opcodes.GETSTATIC: - size = stackSize + (c == 'D' || c == 'J' ? 2 : 1); - break; - case Opcodes.PUTSTATIC: - size = stackSize + (c == 'D' || c == 'J' ? -2 : -1); - break; - case Opcodes.GETFIELD: - size = stackSize + (c == 'D' || c == 'J' ? 1 : 0); - break; - // case Constants.PUTFIELD: - default: - size = stackSize + (c == 'D' || c == 'J' ? -3 : -2); - break; + case Opcodes.GETSTATIC: + size = stackSize + (c == 'D' || c == 'J' ? 2 : 1); + break; + case Opcodes.PUTSTATIC: + size = stackSize + (c == 'D' || c == 'J' ? -2 : -1); + break; + case Opcodes.GETFIELD: + size = stackSize + (c == 'D' || c == 'J' ? 1 : 0); + break; + // case Constants.PUTFIELD: + default: + size = stackSize + (c == 'D' || c == 'J' ? -3 : -2); + break; } // updates current and max stack sizes if (size > maxStackSize) { @@ -826,12 +807,8 @@ class MethodWriter extends MethodVisitor { } @Override - public void visitMethodInsn( - final int opcode, - final String owner, - final String name, - final String desc) - { + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { boolean itf = opcode == Opcodes.INVOKEINTERFACE; Item i = cw.newMethodItem(owner, name, desc, itf); int argSize = i.intVal; @@ -882,12 +859,8 @@ class MethodWriter extends MethodVisitor { } @Override - public void visitInvokeDynamicInsn( - final String name, - final String desc, - final Handle bsm, - final Object... bsmArgs) - { + public void visitInvokeDynamicInsn(final String name, final String desc, + final Handle bsm, final Object... bsmArgs) { Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs); int argSize = i.intVal; // Label currentBlock = this.currentBlock; @@ -967,8 +940,7 @@ class MethodWriter extends MethodVisitor { } // adds the instruction to the bytecode of the method if ((label.status & Label.RESOLVED) != 0 - && label.position - code.length < Short.MIN_VALUE) - { + && label.position - code.length < Short.MIN_VALUE) { /* * case of a backward jump with an offset < -32768. In this case we * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx @@ -986,8 +958,7 @@ class MethodWriter extends MethodVisitor { if (nextInsn != null) { nextInsn.status |= Label.TARGET; } - code.putByte(opcode <= 166 - ? ((opcode + 1) ^ 1) - 1 + code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1); code.putShort(8); // jump offset code.putByte(200); // GOTO_W @@ -1082,8 +1053,7 @@ class MethodWriter extends MethodVisitor { } else { int size; // computes the stack size variation - if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) - { + if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { size = stackSize + 2; } else { size = stackSize + 1; @@ -1122,8 +1092,7 @@ class MethodWriter extends MethodVisitor { } // adds the instruction to the bytecode of the method if ((var > 255) || (increment > 127) || (increment < -128)) { - code.putByte(196 /* WIDE */) - .put12(Opcodes.IINC, var) + code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var) .putShort(increment); } else { code.putByte(Opcodes.IINC).put11(var, increment); @@ -1131,12 +1100,8 @@ class MethodWriter extends MethodVisitor { } @Override - public void visitTableSwitchInsn( - final int min, - final int max, - final Label dflt, - final Label... labels) - { + public void visitTableSwitchInsn(final int min, final int max, + final Label dflt, final Label... labels) { // adds the instruction to the bytecode of the method int source = code.length; code.putByte(Opcodes.TABLESWITCH); @@ -1151,11 +1116,8 @@ class MethodWriter extends MethodVisitor { } @Override - public void visitLookupSwitchInsn( - final Label dflt, - final int[] keys, - final Label[] labels) - { + public void visitLookupSwitchInsn(final Label dflt, final int[] keys, + final Label[] labels) { // adds the instruction to the bytecode of the method int source = code.length; code.putByte(Opcodes.LOOKUPSWITCH); @@ -1214,12 +1176,8 @@ class MethodWriter extends MethodVisitor { } @Override - public void visitTryCatchBlock( - final Label start, - final Label end, - final Label handler, - final String type) - { + public void visitTryCatchBlock(final Label start, final Label end, + final Label handler, final String type) { ++handlerCount; Handler h = new Handler(); h.start = start; @@ -1236,14 +1194,9 @@ class MethodWriter extends MethodVisitor { } @Override - public void visitLocalVariable( - final String name, - final String desc, - final String signature, - final Label start, - final Label end, - final int index) - { + public void visitLocalVariable(final String name, final String desc, + final String signature, final Label start, final Label end, + final int index) { if (signature != null) { if (localVarType == null) { localVarType = new ByteVector(); @@ -1251,8 +1204,7 @@ class MethodWriter extends MethodVisitor { ++localVarTypeCount; localVarType.putShort(start.position) .putShort(end.position - start.position) - .putShort(cw.newUTF8(name)) - .putShort(cw.newUTF8(signature)) + .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(signature)) .putShort(index); } if (localVar == null) { @@ -1261,8 +1213,7 @@ class MethodWriter extends MethodVisitor { ++localVarCount; localVar.putShort(start.position) .putShort(end.position - start.position) - .putShort(cw.newUTF8(name)) - .putShort(cw.newUTF8(desc)) + .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(desc)) .putShort(index); if (compute != NOTHING) { // updates max locals @@ -1294,8 +1245,7 @@ class MethodWriter extends MethodVisitor { Label h = handler.handler.getFirst(); Label e = handler.end.getFirst(); // computes the kind of the edges to 'h' - String t = handler.desc == null - ? "java/lang/Throwable" + String t = handler.desc == null ? "java/lang/Throwable" : handler.desc; int kind = Frame.OBJECT | cw.addType(t); // h is an exception handler @@ -1382,11 +1332,12 @@ class MethodWriter extends MethodVisitor { } code.data[end] = (byte) Opcodes.ATHROW; // emits a frame for this unreachable block - startFrame(start, 0, 1); - frame[frameIndex++] = Frame.OBJECT + int frameIndex = startFrame(start, 0, 1); + frame[frameIndex] = Frame.OBJECT | cw.addType("java/lang/Throwable"); endFrame(); - // removes the start-end range from the exception handlers + // removes the start-end range from the exception + // handlers firstHandler = Handler.remove(firstHandler, l, k); } } @@ -1535,8 +1486,10 @@ class MethodWriter extends MethodVisitor { /** * Adds a successor to the {@link #currentBlock currentBlock} block. * - * @param info information about the control flow edge to be added. - * @param successor the successor block to be added to the current block. + * @param info + * information about the control flow edge to be added. + * @param successor + * the successor block to be added to the current block. */ private void addSuccessor(final int info, final Label successor) { // creates and initializes an Edge object... @@ -1573,7 +1526,8 @@ class MethodWriter extends MethodVisitor { /** * Visits a frame that has been computed from scratch. * - * @param f the frame that must be visited. + * @param f + * the frame that must be visited. */ private void visitFrame(final Frame f) { int i, t; @@ -1606,7 +1560,7 @@ class MethodWriter extends MethodVisitor { } } // visits the frame and its content - startFrame(f.owner.position, nLocal, nStack); + int frameIndex = startFrame(f.owner.position, nLocal, nStack); for (i = 0; nLocal > 0; ++i, --nLocal) { t = locals[i]; frame[frameIndex++] = t; @@ -1625,15 +1579,78 @@ class MethodWriter extends MethodVisitor { } /** + * Visit the implicit first frame of this method. + */ + private void visitImplicitFirstFrame() { + // There can be at most descriptor.length() + 1 locals + int frameIndex = startFrame(0, descriptor.length() + 1, 0); + if ((access & Opcodes.ACC_STATIC) == 0) { + if ((access & ACC_CONSTRUCTOR) == 0) { + frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName); + } else { + frame[frameIndex++] = 6; // Opcodes.UNINITIALIZED_THIS; + } + } + int i = 1; + loop: while (true) { + int j = i; + switch (descriptor.charAt(i++)) { + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + frame[frameIndex++] = 1; // Opcodes.INTEGER; + break; + case 'F': + frame[frameIndex++] = 2; // Opcodes.FLOAT; + break; + case 'J': + frame[frameIndex++] = 4; // Opcodes.LONG; + break; + case 'D': + frame[frameIndex++] = 3; // Opcodes.DOUBLE; + break; + case '[': + while (descriptor.charAt(i) == '[') { + ++i; + } + if (descriptor.charAt(i) == 'L') { + ++i; + while (descriptor.charAt(i) != ';') { + ++i; + } + } + frame[frameIndex++] = Frame.OBJECT + | cw.addType(descriptor.substring(j, ++i)); + break; + case 'L': + while (descriptor.charAt(i) != ';') { + ++i; + } + frame[frameIndex++] = Frame.OBJECT + | cw.addType(descriptor.substring(j + 1, i++)); + break; + default: + break loop; + } + } + frame[1] = frameIndex - 3; + endFrame(); + } + + /** * Starts the visit of a stack map frame. * - * @param offset the offset of the instruction to which the frame - * corresponds. - * @param nLocal the number of local variables in the frame. - * @param nStack the number of stack elements in the frame. - */ - private void startFrame(final int offset, final int nLocal, final int nStack) - { + * @param offset + * the offset of the instruction to which the frame corresponds. + * @param nLocal + * the number of local variables in the frame. + * @param nStack + * the number of stack elements in the frame. + * @return the index of the next element to be written in this frame. + */ + private int startFrame(final int offset, final int nLocal, final int nStack) { int n = 3 + nLocal + nStack; if (frame == null || frame.length < n) { frame = new int[n]; @@ -1641,7 +1658,7 @@ class MethodWriter extends MethodVisitor { frame[0] = offset; frame[1] = nLocal; frame[2] = nStack; - frameIndex = 3; + return 3; } /** @@ -1686,24 +1703,23 @@ class MethodWriter extends MethodVisitor { if (cstackSize == 0) { k = clocalsSize - localsSize; switch (k) { - case -3: - case -2: - case -1: - type = CHOP_FRAME; - localsSize = clocalsSize; - break; - case 0: - type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED; - break; - case 1: - case 2: - case 3: - type = APPEND_FRAME; - break; + case -3: + case -2: + case -1: + type = CHOP_FRAME; + localsSize = clocalsSize; + break; + case 0: + type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED; + break; + case 1: + case 2: + case 3: + type = APPEND_FRAME; + break; } } else if (clocalsSize == localsSize && cstackSize == 1) { - type = delta < 63 - ? SAME_LOCALS_1_STACK_ITEM_FRAME + type = delta < 63 ? SAME_LOCALS_1_STACK_ITEM_FRAME : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; } if (type != FULL_FRAME) { @@ -1718,36 +1734,34 @@ class MethodWriter extends MethodVisitor { } } switch (type) { - case SAME_FRAME: - stackMap.putByte(delta); - break; - case SAME_LOCALS_1_STACK_ITEM_FRAME: - stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); - writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); - break; - case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: - stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) - .putShort(delta); - writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); - break; - case SAME_FRAME_EXTENDED: - stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); - break; - case CHOP_FRAME: - stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); - break; - case APPEND_FRAME: - stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); - writeFrameTypes(3 + localsSize, 3 + clocalsSize); - break; - // case FULL_FRAME: - default: - stackMap.putByte(FULL_FRAME) - .putShort(delta) - .putShort(clocalsSize); - writeFrameTypes(3, 3 + clocalsSize); - stackMap.putShort(cstackSize); - writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); + case SAME_FRAME: + stackMap.putByte(delta); + break; + case SAME_LOCALS_1_STACK_ITEM_FRAME: + stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); + writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); + break; + case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: + stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED).putShort( + delta); + writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); + break; + case SAME_FRAME_EXTENDED: + stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); + break; + case CHOP_FRAME: + stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); + break; + case APPEND_FRAME: + stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); + writeFrameTypes(3 + localsSize, 3 + clocalsSize); + break; + // case FULL_FRAME: + default: + stackMap.putByte(FULL_FRAME).putShort(delta).putShort(clocalsSize); + writeFrameTypes(3, 3 + clocalsSize); + stackMap.putShort(cstackSize); + writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); } } @@ -1757,8 +1771,10 @@ class MethodWriter extends MethodVisitor { * in {@link Label} to the format used in StackMapTable attributes. In * particular, it converts type table indexes to constant pool indexes. * - * @param start index of the first type in {@link #frame} to write. - * @param end index of last type in {@link #frame} to write (exclusive). + * @param start + * index of the first type in {@link #frame} to write. + * @param end + * index of last type in {@link #frame} to write (exclusive). */ private void writeFrameTypes(final int start, final int end) { for (int i = start; i < end; ++i) { @@ -1767,15 +1783,15 @@ class MethodWriter extends MethodVisitor { if (d == 0) { int v = t & Frame.BASE_VALUE; switch (t & Frame.BASE_KIND) { - case Frame.OBJECT: - stackMap.putByte(7) - .putShort(cw.newClass(cw.typeTable[v].strVal1)); - break; - case Frame.UNINITIALIZED: - stackMap.putByte(8).putShort(cw.typeTable[v].intVal); - break; - default: - stackMap.putByte(v); + case Frame.OBJECT: + stackMap.putByte(7).putShort( + cw.newClass(cw.typeTable[v].strVal1)); + break; + case Frame.UNINITIALIZED: + stackMap.putByte(8).putShort(cw.typeTable[v].intVal); + break; + default: + stackMap.putByte(v); } } else { StringBuffer buf = new StringBuffer(); @@ -1789,29 +1805,29 @@ class MethodWriter extends MethodVisitor { buf.append(';'); } else { switch (t & 0xF) { - case 1: - buf.append('I'); - break; - case 2: - buf.append('F'); - break; - case 3: - buf.append('D'); - break; - case 9: - buf.append('Z'); - break; - case 10: - buf.append('B'); - break; - case 11: - buf.append('C'); - break; - case 12: - buf.append('S'); - break; - default: - buf.append('J'); + case 1: + buf.append('I'); + break; + case 2: + buf.append('F'); + break; + case 3: + buf.append('D'); + break; + case 9: + buf.append('Z'); + break; + case 10: + buf.append('B'); + break; + case 11: + buf.append('C'); + break; + case 12: + buf.append('S'); + break; + default: + buf.append('J'); } } stackMap.putByte(7).putShort(cw.newClass(buf.toString())); @@ -1875,10 +1891,7 @@ class MethodWriter extends MethodVisitor { size += 8 + stackMap.length; } if (cattrs != null) { - size += cattrs.getSize(cw, - code.data, - code.length, - maxStack, + size += cattrs.getSize(cw, code.data, code.length, maxStack, maxLocals); } } @@ -1886,11 +1899,12 @@ class MethodWriter extends MethodVisitor { cw.newUTF8("Exceptions"); size += 8 + 2 * exceptionCount; } - if ((access & Opcodes.ACC_SYNTHETIC) != 0 - && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) - { - cw.newUTF8("Synthetic"); - size += 6; + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if ((cw.version & 0xFFFF) < Opcodes.V1_5 + || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { + cw.newUTF8("Synthetic"); + size += 6; + } } if ((access & Opcodes.ACC_DEPRECATED) != 0) { cw.newUTF8("Deprecated"); @@ -1936,13 +1950,15 @@ class MethodWriter extends MethodVisitor { /** * Puts the bytecode of this method in the given byte vector. * - * @param out the byte vector into which the bytecode of this method must be - * copied. + * @param out + * the byte vector into which the bytecode of this method must be + * copied. */ final void put(final ByteVector out) { - int mask = Opcodes.ACC_DEPRECATED + final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; + int mask = ACC_CONSTRUCTOR | Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE - | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / (ClassWriter.ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC)); + | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); out.putShort(access & ~mask).putShort(name).putShort(desc); if (classReaderOffset != 0) { out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength); @@ -1955,10 +1971,11 @@ class MethodWriter extends MethodVisitor { if (exceptionCount > 0) { ++attributeCount; } - if ((access & Opcodes.ACC_SYNTHETIC) != 0 - && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) - { - ++attributeCount; + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if ((cw.version & 0xFFFF) < Opcodes.V1_5 + || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { + ++attributeCount; + } } if ((access & Opcodes.ACC_DEPRECATED) != 0) { ++attributeCount; @@ -2000,10 +2017,7 @@ class MethodWriter extends MethodVisitor { size += 8 + stackMap.length; } if (cattrs != null) { - size += cattrs.getSize(cw, - code.data, - code.length, - maxStack, + size += cattrs.getSize(cw, code.data, code.length, maxStack, maxLocals); } out.putShort(cw.newUTF8("Code")).putInt(size); @@ -2013,10 +2027,8 @@ class MethodWriter extends MethodVisitor { if (handlerCount > 0) { Handler h = firstHandler; while (h != null) { - out.putShort(h.start.position) - .putShort(h.end.position) - .putShort(h.handler.position) - .putShort(h.type); + out.putShort(h.start.position).putShort(h.end.position) + .putShort(h.handler.position).putShort(h.type); h = h.next; } } @@ -2063,24 +2075,24 @@ class MethodWriter extends MethodVisitor { } } if (exceptionCount > 0) { - out.putShort(cw.newUTF8("Exceptions")) - .putInt(2 * exceptionCount + 2); + out.putShort(cw.newUTF8("Exceptions")).putInt( + 2 * exceptionCount + 2); out.putShort(exceptionCount); for (int i = 0; i < exceptionCount; ++i) { out.putShort(exceptions[i]); } } - if ((access & Opcodes.ACC_SYNTHETIC) != 0 - && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) - { - out.putShort(cw.newUTF8("Synthetic")).putInt(0); + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if ((cw.version & 0xFFFF) < Opcodes.V1_5 + || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { + out.putShort(cw.newUTF8("Synthetic")).putInt(0); + } } if ((access & Opcodes.ACC_DEPRECATED) != 0) { out.putShort(cw.newUTF8("Deprecated")).putInt(0); } if (ClassReader.SIGNATURES && signature != null) { - out.putShort(cw.newUTF8("Signature")) - .putInt(2) + out.putShort(cw.newUTF8("Signature")).putInt(2) .putShort(cw.newUTF8(signature)); } if (ClassReader.ANNOTATIONS && annd != null) { @@ -2123,10 +2135,12 @@ class MethodWriter extends MethodVisitor { * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W * 32765. This, in turn, may require to increase the size of another jump * instruction, and so on... All these operations are handled automatically - * by this method. <p> <i>This method must be called after all the method - * that is being built has been visited</i>. In particular, the - * {@link Label Label} objects used to construct the method are no longer - * valid after this method has been called. + * by this method. + * <p> + * <i>This method must be called after all the method that is being built + * has been visited</i>. In particular, the {@link Label Label} objects used + * to construct the method are no longer valid after this method has been + * called. */ private void resizeInstructions() { byte[] b = code.data; // bytecode of the method @@ -2176,158 +2190,14 @@ class MethodWriter extends MethodVisitor { int insert = 0; // bytes to be added after this instruction switch (ClassWriter.TYPE[opcode]) { - case ClassWriter.NOARG_INSN: - case ClassWriter.IMPLVAR_INSN: - u += 1; - break; - case ClassWriter.LABEL_INSN: - if (opcode > 201) { - // converts temporary opcodes 202 to 217, 218 and - // 219 to IFEQ ... JSR (inclusive), IFNULL and - // IFNONNULL - opcode = opcode < 218 ? opcode - 49 : opcode - 20; - label = u + readUnsignedShort(b, u + 1); - } else { - label = u + readShort(b, u + 1); - } - newOffset = getNewOffset(allIndexes, allSizes, u, label); - if (newOffset < Short.MIN_VALUE - || newOffset > Short.MAX_VALUE) - { - if (!resize[u]) { - if (opcode == Opcodes.GOTO - || opcode == Opcodes.JSR) - { - // two additional bytes will be required to - // replace this GOTO or JSR instruction with - // a GOTO_W or a JSR_W - insert = 2; - } else { - // five additional bytes will be required to - // replace this IFxxx <l> instruction with - // IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx - // is the "opposite" opcode of IFxxx (i.e., - // IFNE for IFEQ) and where <l'> designates - // the instruction just after the GOTO_W. - insert = 5; - } - resize[u] = true; - } - } - u += 3; - break; - case ClassWriter.LABELW_INSN: - u += 5; - break; - case ClassWriter.TABL_INSN: - if (state == 1) { - // true number of bytes to be added (or removed) - // from this instruction = (future number of padding - // bytes - current number of padding byte) - - // previously over estimated variation = - // = ((3 - newOffset%4) - (3 - u%4)) - u%4 - // = (-newOffset%4 + u%4) - u%4 - // = -(newOffset & 3) - newOffset = getNewOffset(allIndexes, allSizes, 0, u); - insert = -(newOffset & 3); - } else if (!resize[u]) { - // over estimation of the number of bytes to be - // added to this instruction = 3 - current number - // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3 - insert = u & 3; - resize[u] = true; - } - // skips instruction - u = u + 4 - (u & 3); - u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12; - break; - case ClassWriter.LOOK_INSN: - if (state == 1) { - // like TABL_INSN - newOffset = getNewOffset(allIndexes, allSizes, 0, u); - insert = -(newOffset & 3); - } else if (!resize[u]) { - // like TABL_INSN - insert = u & 3; - resize[u] = true; - } - // skips instruction - u = u + 4 - (u & 3); - u += 8 * readInt(b, u + 4) + 8; - break; - case ClassWriter.WIDE_INSN: - opcode = b[u + 1] & 0xFF; - if (opcode == Opcodes.IINC) { - u += 6; - } else { - u += 4; - } - break; - case ClassWriter.VAR_INSN: - case ClassWriter.SBYTE_INSN: - case ClassWriter.LDC_INSN: - u += 2; - break; - case ClassWriter.SHORT_INSN: - case ClassWriter.LDCW_INSN: - case ClassWriter.FIELDORMETH_INSN: - case ClassWriter.TYPE_INSN: - case ClassWriter.IINC_INSN: - u += 3; - break; - case ClassWriter.ITFMETH_INSN: - case ClassWriter.INDYMETH_INSN: - u += 5; - break; - // case ClassWriter.MANA_INSN: - default: - u += 4; - break; - } - if (insert != 0) { - // adds a new (u, insert) entry in the allIndexes and - // allSizes arrays - int[] newIndexes = new int[allIndexes.length + 1]; - int[] newSizes = new int[allSizes.length + 1]; - System.arraycopy(allIndexes, - 0, - newIndexes, - 0, - allIndexes.length); - System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length); - newIndexes[allIndexes.length] = u; - newSizes[allSizes.length] = insert; - allIndexes = newIndexes; - allSizes = newSizes; - if (insert > 0) { - state = 3; - } - } - } - if (state < 3) { - --state; - } - } while (state != 0); - - // 2nd step: - // copies the bytecode of the method into a new bytevector, updates the - // offsets, and inserts (or removes) bytes as requested. - - ByteVector newCode = new ByteVector(code.length); - - u = 0; - while (u < code.length) { - int opcode = b[u] & 0xFF; - switch (ClassWriter.TYPE[opcode]) { case ClassWriter.NOARG_INSN: case ClassWriter.IMPLVAR_INSN: - newCode.putByte(opcode); u += 1; break; case ClassWriter.LABEL_INSN: if (opcode > 201) { - // changes temporary opcodes 202 to 217 (inclusive), 218 - // and 219 to IFEQ ... JSR (inclusive), IFNULL and + // converts temporary opcodes 202 to 217, 218 and + // 219 to IFEQ ... JSR (inclusive), IFNULL and // IFNONNULL opcode = opcode < 218 ? opcode - 49 : opcode - 20; label = u + readUnsignedShort(b, u + 1); @@ -2335,100 +2205,78 @@ class MethodWriter extends MethodVisitor { label = u + readShort(b, u + 1); } newOffset = getNewOffset(allIndexes, allSizes, u, label); - if (resize[u]) { - // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx - // <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is - // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) - // and where <l'> designates the instruction just after - // the GOTO_W. - if (opcode == Opcodes.GOTO) { - newCode.putByte(200); // GOTO_W - } else if (opcode == Opcodes.JSR) { - newCode.putByte(201); // JSR_W - } else { - newCode.putByte(opcode <= 166 - ? ((opcode + 1) ^ 1) - 1 - : opcode ^ 1); - newCode.putShort(8); // jump offset - newCode.putByte(200); // GOTO_W - // newOffset now computed from start of GOTO_W - newOffset -= 3; + if (newOffset < Short.MIN_VALUE + || newOffset > Short.MAX_VALUE) { + if (!resize[u]) { + if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) { + // two additional bytes will be required to + // replace this GOTO or JSR instruction with + // a GOTO_W or a JSR_W + insert = 2; + } else { + // five additional bytes will be required to + // replace this IFxxx <l> instruction with + // IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx + // is the "opposite" opcode of IFxxx (i.e., + // IFNE for IFEQ) and where <l'> designates + // the instruction just after the GOTO_W. + insert = 5; + } + resize[u] = true; } - newCode.putInt(newOffset); - } else { - newCode.putByte(opcode); - newCode.putShort(newOffset); } u += 3; break; case ClassWriter.LABELW_INSN: - label = u + readInt(b, u + 1); - newOffset = getNewOffset(allIndexes, allSizes, u, label); - newCode.putByte(opcode); - newCode.putInt(newOffset); u += 5; break; case ClassWriter.TABL_INSN: - // skips 0 to 3 padding bytes - v = u; - u = u + 4 - (v & 3); - // reads and copies instruction - newCode.putByte(Opcodes.TABLESWITCH); - newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); - label = v + readInt(b, u); - u += 4; - newOffset = getNewOffset(allIndexes, allSizes, v, label); - newCode.putInt(newOffset); - j = readInt(b, u); - u += 4; - newCode.putInt(j); - j = readInt(b, u) - j + 1; - u += 4; - newCode.putInt(readInt(b, u - 4)); - for (; j > 0; --j) { - label = v + readInt(b, u); - u += 4; - newOffset = getNewOffset(allIndexes, allSizes, v, label); - newCode.putInt(newOffset); + if (state == 1) { + // true number of bytes to be added (or removed) + // from this instruction = (future number of padding + // bytes - current number of padding byte) - + // previously over estimated variation = + // = ((3 - newOffset%4) - (3 - u%4)) - u%4 + // = (-newOffset%4 + u%4) - u%4 + // = -(newOffset & 3) + newOffset = getNewOffset(allIndexes, allSizes, 0, u); + insert = -(newOffset & 3); + } else if (!resize[u]) { + // over estimation of the number of bytes to be + // added to this instruction = 3 - current number + // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3 + insert = u & 3; + resize[u] = true; } + // skips instruction + u = u + 4 - (u & 3); + u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12; break; case ClassWriter.LOOK_INSN: - // skips 0 to 3 padding bytes - v = u; - u = u + 4 - (v & 3); - // reads and copies instruction - newCode.putByte(Opcodes.LOOKUPSWITCH); - newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); - label = v + readInt(b, u); - u += 4; - newOffset = getNewOffset(allIndexes, allSizes, v, label); - newCode.putInt(newOffset); - j = readInt(b, u); - u += 4; - newCode.putInt(j); - for (; j > 0; --j) { - newCode.putInt(readInt(b, u)); - u += 4; - label = v + readInt(b, u); - u += 4; - newOffset = getNewOffset(allIndexes, allSizes, v, label); - newCode.putInt(newOffset); + if (state == 1) { + // like TABL_INSN + newOffset = getNewOffset(allIndexes, allSizes, 0, u); + insert = -(newOffset & 3); + } else if (!resize[u]) { + // like TABL_INSN + insert = u & 3; + resize[u] = true; } + // skips instruction + u = u + 4 - (u & 3); + u += 8 * readInt(b, u + 4) + 8; break; case ClassWriter.WIDE_INSN: opcode = b[u + 1] & 0xFF; if (opcode == Opcodes.IINC) { - newCode.putByteArray(b, u, 6); u += 6; } else { - newCode.putByteArray(b, u, 4); u += 4; } break; case ClassWriter.VAR_INSN: case ClassWriter.SBYTE_INSN: case ClassWriter.LDC_INSN: - newCode.putByteArray(b, u, 2); u += 2; break; case ClassWriter.SHORT_INSN: @@ -2436,19 +2284,178 @@ class MethodWriter extends MethodVisitor { case ClassWriter.FIELDORMETH_INSN: case ClassWriter.TYPE_INSN: case ClassWriter.IINC_INSN: - newCode.putByteArray(b, u, 3); u += 3; break; case ClassWriter.ITFMETH_INSN: case ClassWriter.INDYMETH_INSN: - newCode.putByteArray(b, u, 5); u += 5; break; - // case MANA_INSN: + // case ClassWriter.MANA_INSN: default: - newCode.putByteArray(b, u, 4); u += 4; break; + } + if (insert != 0) { + // adds a new (u, insert) entry in the allIndexes and + // allSizes arrays + int[] newIndexes = new int[allIndexes.length + 1]; + int[] newSizes = new int[allSizes.length + 1]; + System.arraycopy(allIndexes, 0, newIndexes, 0, + allIndexes.length); + System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length); + newIndexes[allIndexes.length] = u; + newSizes[allSizes.length] = insert; + allIndexes = newIndexes; + allSizes = newSizes; + if (insert > 0) { + state = 3; + } + } + } + if (state < 3) { + --state; + } + } while (state != 0); + + // 2nd step: + // copies the bytecode of the method into a new bytevector, updates the + // offsets, and inserts (or removes) bytes as requested. + + ByteVector newCode = new ByteVector(code.length); + + u = 0; + while (u < code.length) { + int opcode = b[u] & 0xFF; + switch (ClassWriter.TYPE[opcode]) { + case ClassWriter.NOARG_INSN: + case ClassWriter.IMPLVAR_INSN: + newCode.putByte(opcode); + u += 1; + break; + case ClassWriter.LABEL_INSN: + if (opcode > 201) { + // changes temporary opcodes 202 to 217 (inclusive), 218 + // and 219 to IFEQ ... JSR (inclusive), IFNULL and + // IFNONNULL + opcode = opcode < 218 ? opcode - 49 : opcode - 20; + label = u + readUnsignedShort(b, u + 1); + } else { + label = u + readShort(b, u + 1); + } + newOffset = getNewOffset(allIndexes, allSizes, u, label); + if (resize[u]) { + // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx + // <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is + // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) + // and where <l'> designates the instruction just after + // the GOTO_W. + if (opcode == Opcodes.GOTO) { + newCode.putByte(200); // GOTO_W + } else if (opcode == Opcodes.JSR) { + newCode.putByte(201); // JSR_W + } else { + newCode.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 + : opcode ^ 1); + newCode.putShort(8); // jump offset + newCode.putByte(200); // GOTO_W + // newOffset now computed from start of GOTO_W + newOffset -= 3; + } + newCode.putInt(newOffset); + } else { + newCode.putByte(opcode); + newCode.putShort(newOffset); + } + u += 3; + break; + case ClassWriter.LABELW_INSN: + label = u + readInt(b, u + 1); + newOffset = getNewOffset(allIndexes, allSizes, u, label); + newCode.putByte(opcode); + newCode.putInt(newOffset); + u += 5; + break; + case ClassWriter.TABL_INSN: + // skips 0 to 3 padding bytes + v = u; + u = u + 4 - (v & 3); + // reads and copies instruction + newCode.putByte(Opcodes.TABLESWITCH); + newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); + label = v + readInt(b, u); + u += 4; + newOffset = getNewOffset(allIndexes, allSizes, v, label); + newCode.putInt(newOffset); + j = readInt(b, u); + u += 4; + newCode.putInt(j); + j = readInt(b, u) - j + 1; + u += 4; + newCode.putInt(readInt(b, u - 4)); + for (; j > 0; --j) { + label = v + readInt(b, u); + u += 4; + newOffset = getNewOffset(allIndexes, allSizes, v, label); + newCode.putInt(newOffset); + } + break; + case ClassWriter.LOOK_INSN: + // skips 0 to 3 padding bytes + v = u; + u = u + 4 - (v & 3); + // reads and copies instruction + newCode.putByte(Opcodes.LOOKUPSWITCH); + newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); + label = v + readInt(b, u); + u += 4; + newOffset = getNewOffset(allIndexes, allSizes, v, label); + newCode.putInt(newOffset); + j = readInt(b, u); + u += 4; + newCode.putInt(j); + for (; j > 0; --j) { + newCode.putInt(readInt(b, u)); + u += 4; + label = v + readInt(b, u); + u += 4; + newOffset = getNewOffset(allIndexes, allSizes, v, label); + newCode.putInt(newOffset); + } + break; + case ClassWriter.WIDE_INSN: + opcode = b[u + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + newCode.putByteArray(b, u, 6); + u += 6; + } else { + newCode.putByteArray(b, u, 4); + u += 4; + } + break; + case ClassWriter.VAR_INSN: + case ClassWriter.SBYTE_INSN: + case ClassWriter.LDC_INSN: + newCode.putByteArray(b, u, 2); + u += 2; + break; + case ClassWriter.SHORT_INSN: + case ClassWriter.LDCW_INSN: + case ClassWriter.FIELDORMETH_INSN: + case ClassWriter.TYPE_INSN: + case ClassWriter.IINC_INSN: + newCode.putByteArray(b, u, 3); + u += 3; + break; + case ClassWriter.ITFMETH_INSN: + case ClassWriter.INDYMETH_INSN: + newCode.putByteArray(b, u, 5); + u += 5; + break; + // case MANA_INSN: + default: + newCode.putByteArray(b, u, 4); + u += 4; + break; } } @@ -2471,8 +2478,7 @@ class MethodWriter extends MethodVisitor { * must therefore never have been called for this label. */ u = l.position - 3; - if ((l.status & Label.STORE) != 0 || (u >= 0 && resize[u])) - { + if ((l.status & Label.STORE) != 0 || (u >= 0 && resize[u])) { getNewOffset(allIndexes, allSizes, l); // TODO update offsets in UNINITIALIZED values visitFrame(l.frame); @@ -2528,10 +2534,11 @@ class MethodWriter extends MethodVisitor { b = lineNumber.data; u = 0; while (u < lineNumber.length) { - writeShort(b, u, getNewOffset(allIndexes, - allSizes, - 0, - readUnsignedShort(b, u))); + writeShort( + b, + u, + getNewOffset(allIndexes, allSizes, 0, + readUnsignedShort(b, u))); u += 4; } } @@ -2554,8 +2561,10 @@ class MethodWriter extends MethodVisitor { /** * Reads an unsigned short value in the given byte array. * - * @param b a byte array. - * @param index the start index of the value to be read. + * @param b + * a byte array. + * @param index + * the start index of the value to be read. * @return the read value. */ static int readUnsignedShort(final byte[] b, final int index) { @@ -2565,8 +2574,10 @@ class MethodWriter extends MethodVisitor { /** * Reads a signed short value in the given byte array. * - * @param b a byte array. - * @param index the start index of the value to be read. + * @param b + * a byte array. + * @param index + * the start index of the value to be read. * @return the read value. */ static short readShort(final byte[] b, final int index) { @@ -2576,8 +2587,10 @@ class MethodWriter extends MethodVisitor { /** * Reads a signed int value in the given byte array. * - * @param b a byte array. - * @param index the start index of the value to be read. + * @param b + * a byte array. + * @param index + * the start index of the value to be read. * @return the read value. */ static int readInt(final byte[] b, final int index) { @@ -2588,9 +2601,12 @@ class MethodWriter extends MethodVisitor { /** * Writes a short value in the given byte array. * - * @param b a byte array. - * @param index where the first byte of the short value must be written. - * @param s the value to be written in the given byte array. + * @param b + * a byte array. + * @param index + * where the first byte of the short value must be written. + * @param s + * the value to be written in the given byte array. */ static void writeShort(final byte[] b, final int index, final int s) { b[index] = (byte) (s >>> 8); @@ -2598,32 +2614,34 @@ class MethodWriter extends MethodVisitor { } /** - * Computes the future value of a bytecode offset. <p> Note: it is possible - * to have several entries for the same instruction in the <tt>indexes</tt> - * and <tt>sizes</tt>: two entries (index=a,size=b) and (index=a,size=b') - * are equivalent to a single entry (index=a,size=b+b'). + * Computes the future value of a bytecode offset. + * <p> + * Note: it is possible to have several entries for the same instruction in + * the <tt>indexes</tt> and <tt>sizes</tt>: two entries (index=a,size=b) and + * (index=a,size=b') are equivalent to a single entry (index=a,size=b+b'). * - * @param indexes current positions of the instructions to be resized. Each - * instruction must be designated by the index of its <i>last</i> - * byte, plus one (or, in other words, by the index of the <i>first</i> - * byte of the <i>next</i> instruction). - * @param sizes the number of bytes to be <i>added</i> to the above - * instructions. More precisely, for each i < <tt>len</tt>, - * <tt>sizes</tt>[i] bytes will be added at the end of the - * instruction designated by <tt>indexes</tt>[i] or, if - * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>| - * bytes of the instruction will be removed (the instruction size - * <i>must not</i> become negative or null). - * @param begin index of the first byte of the source instruction. - * @param end index of the first byte of the target instruction. + * @param indexes + * current positions of the instructions to be resized. Each + * instruction must be designated by the index of its <i>last</i> + * byte, plus one (or, in other words, by the index of the + * <i>first</i> byte of the <i>next</i> instruction). + * @param sizes + * the number of bytes to be <i>added</i> to the above + * instructions. More precisely, for each i < <tt>len</tt>, + * <tt>sizes</tt>[i] bytes will be added at the end of the + * instruction designated by <tt>indexes</tt>[i] or, if + * <tt>sizes</tt>[i] is negative, the <i>last</i> | + * <tt>sizes[i]</tt>| bytes of the instruction will be removed + * (the instruction size <i>must not</i> become negative or + * null). + * @param begin + * index of the first byte of the source instruction. + * @param end + * index of the first byte of the target instruction. * @return the future value of the given bytecode offset. */ - static int getNewOffset( - final int[] indexes, - final int[] sizes, - final int begin, - final int end) - { + static int getNewOffset(final int[] indexes, final int[] sizes, + final int begin, final int end) { int offset = end - begin; for (int i = 0; i < indexes.length; ++i) { if (begin < indexes[i] && indexes[i] <= end) { @@ -2640,24 +2658,25 @@ class MethodWriter extends MethodVisitor { /** * Updates the offset of the given label. * - * @param indexes current positions of the instructions to be resized. Each - * instruction must be designated by the index of its <i>last</i> - * byte, plus one (or, in other words, by the index of the <i>first</i> - * byte of the <i>next</i> instruction). - * @param sizes the number of bytes to be <i>added</i> to the above - * instructions. More precisely, for each i < <tt>len</tt>, - * <tt>sizes</tt>[i] bytes will be added at the end of the - * instruction designated by <tt>indexes</tt>[i] or, if - * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>| - * bytes of the instruction will be removed (the instruction size - * <i>must not</i> become negative or null). - * @param label the label whose offset must be updated. - */ - static void getNewOffset( - final int[] indexes, - final int[] sizes, - final Label label) - { + * @param indexes + * current positions of the instructions to be resized. Each + * instruction must be designated by the index of its <i>last</i> + * byte, plus one (or, in other words, by the index of the + * <i>first</i> byte of the <i>next</i> instruction). + * @param sizes + * the number of bytes to be <i>added</i> to the above + * instructions. More precisely, for each i < <tt>len</tt>, + * <tt>sizes</tt>[i] bytes will be added at the end of the + * instruction designated by <tt>indexes</tt>[i] or, if + * <tt>sizes</tt>[i] is negative, the <i>last</i> | + * <tt>sizes[i]</tt>| bytes of the instruction will be removed + * (the instruction size <i>must not</i> become negative or + * null). + * @param label + * the label whose offset must be updated. + */ + static void getNewOffset(final int[] indexes, final int[] sizes, + final Label label) { if ((label.status & Label.RESIZED) == 0) { label.position = getNewOffset(indexes, sizes, 0, label.position); label.status |= Label.RESIZED; diff --git a/src/asm/scala/tools/asm/Type.java b/src/asm/scala/tools/asm/Type.java index bf1107182a..7821a492e6 100644 --- a/src/asm/scala/tools/asm/Type.java +++ b/src/asm/scala/tools/asm/Type.java @@ -190,13 +190,16 @@ public class Type { /** * Constructs a reference type. * - * @param sort the sort of the reference type to be constructed. - * @param buf a buffer containing the descriptor of the previous type. - * @param off the offset of this descriptor in the previous buffer. - * @param len the length of this descriptor. - */ - private Type(final int sort, final char[] buf, final int off, final int len) - { + * @param sort + * the sort of the reference type to be constructed. + * @param buf + * a buffer containing the descriptor of the previous type. + * @param off + * the offset of this descriptor in the previous buffer. + * @param len + * the length of this descriptor. + */ + private Type(final int sort, final char[] buf, final int off, final int len) { this.sort = sort; this.buf = buf; this.off = off; @@ -206,7 +209,8 @@ public class Type { /** * Returns the Java type corresponding to the given type descriptor. * - * @param typeDescriptor a field or method type descriptor. + * @param typeDescriptor + * a field or method type descriptor. * @return the Java type corresponding to the given type descriptor. */ public static Type getType(final String typeDescriptor) { @@ -216,7 +220,8 @@ public class Type { /** * Returns the Java type corresponding to the given internal name. * - * @param internalName an internal name. + * @param internalName + * an internal name. * @return the Java type corresponding to the given internal name. */ public static Type getObjectType(final String internalName) { @@ -228,7 +233,8 @@ public class Type { * Returns the Java type corresponding to the given method descriptor. * Equivalent to <code>Type.getType(methodDescriptor)</code>. * - * @param methodDescriptor a method descriptor. + * @param methodDescriptor + * a method descriptor. * @return the Java type corresponding to the given method descriptor. */ public static Type getMethodType(final String methodDescriptor) { @@ -239,18 +245,23 @@ public class Type { * Returns the Java method type corresponding to the given argument and * return types. * - * @param returnType the return type of the method. - * @param argumentTypes the argument types of the method. - * @return the Java type corresponding to the given argument and return types. + * @param returnType + * the return type of the method. + * @param argumentTypes + * the argument types of the method. + * @return the Java type corresponding to the given argument and return + * types. */ - public static Type getMethodType(final Type returnType, final Type... argumentTypes) { + public static Type getMethodType(final Type returnType, + final Type... argumentTypes) { return getType(getMethodDescriptor(returnType, argumentTypes)); } /** * Returns the Java type corresponding to the given class. * - * @param c a class. + * @param c + * a class. * @return the Java type corresponding to the given class. */ public static Type getType(final Class<?> c) { @@ -282,7 +293,8 @@ public class Type { /** * Returns the Java method type corresponding to the given constructor. * - * @param c a {@link Constructor Constructor} object. + * @param c + * a {@link Constructor Constructor} object. * @return the Java method type corresponding to the given constructor. */ public static Type getType(final Constructor<?> c) { @@ -292,7 +304,8 @@ public class Type { /** * Returns the Java method type corresponding to the given method. * - * @param m a {@link Method Method} object. + * @param m + * a {@link Method Method} object. * @return the Java method type corresponding to the given method. */ public static Type getType(final Method m) { @@ -303,7 +316,8 @@ public class Type { * Returns the Java types corresponding to the argument types of the given * method descriptor. * - * @param methodDescriptor a method descriptor. + * @param methodDescriptor + * a method descriptor. * @return the Java types corresponding to the argument types of the given * method descriptor. */ @@ -338,7 +352,8 @@ public class Type { * Returns the Java types corresponding to the argument types of the given * method. * - * @param method a method. + * @param method + * a method. * @return the Java types corresponding to the argument types of the given * method. */ @@ -355,7 +370,8 @@ public class Type { * Returns the Java type corresponding to the return type of the given * method descriptor. * - * @param methodDescriptor a method descriptor. + * @param methodDescriptor + * a method descriptor. * @return the Java type corresponding to the return type of the given * method descriptor. */ @@ -368,7 +384,8 @@ public class Type { * Returns the Java type corresponding to the return type of the given * method. * - * @param method a method. + * @param method + * a method. * @return the Java type corresponding to the return type of the given * method. */ @@ -379,12 +396,13 @@ public class Type { /** * Computes the size of the arguments and of the return value of a method. * - * @param desc the descriptor of a method. + * @param desc + * the descriptor of a method. * @return the size of the arguments of the method (plus one for the * implicit this argument), argSize, and the size of its return * value, retSize, packed into a single int i = - * <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal - * to <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>). + * <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal to + * <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>). */ public static int getArgumentsAndReturnSizes(final String desc) { int n = 1; @@ -419,52 +437,54 @@ public class Type { * method descriptors, buf is supposed to contain nothing more than the * descriptor itself. * - * @param buf a buffer containing a type descriptor. - * @param off the offset of this descriptor in the previous buffer. + * @param buf + * a buffer containing a type descriptor. + * @param off + * the offset of this descriptor in the previous buffer. * @return the Java type corresponding to the given type descriptor. */ private static Type getType(final char[] buf, final int off) { int len; switch (buf[off]) { - case 'V': - return VOID_TYPE; - case 'Z': - return BOOLEAN_TYPE; - case 'C': - return CHAR_TYPE; - case 'B': - return BYTE_TYPE; - case 'S': - return SHORT_TYPE; - case 'I': - return INT_TYPE; - case 'F': - return FLOAT_TYPE; - case 'J': - return LONG_TYPE; - case 'D': - return DOUBLE_TYPE; - case '[': - len = 1; - while (buf[off + len] == '[') { - ++len; - } - if (buf[off + len] == 'L') { - ++len; - while (buf[off + len] != ';') { - ++len; - } - } - return new Type(ARRAY, buf, off, len + 1); - case 'L': - len = 1; + case 'V': + return VOID_TYPE; + case 'Z': + return BOOLEAN_TYPE; + case 'C': + return CHAR_TYPE; + case 'B': + return BYTE_TYPE; + case 'S': + return SHORT_TYPE; + case 'I': + return INT_TYPE; + case 'F': + return FLOAT_TYPE; + case 'J': + return LONG_TYPE; + case 'D': + return DOUBLE_TYPE; + case '[': + len = 1; + while (buf[off + len] == '[') { + ++len; + } + if (buf[off + len] == 'L') { + ++len; while (buf[off + len] != ';') { ++len; } - return new Type(OBJECT, buf, off + 1, len - 1); + } + return new Type(ARRAY, buf, off, len + 1); + case 'L': + len = 1; + while (buf[off + len] != ';') { + ++len; + } + return new Type(OBJECT, buf, off + 1, len - 1); // case '(': - default: - return new Type(METHOD, buf, 0, buf.length); + default: + return new Type(METHOD, buf, off, buf.length - off); } } @@ -475,11 +495,11 @@ public class Type { /** * Returns the sort of this Java type. * - * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, - * {@link #CHAR CHAR}, {@link #BYTE BYTE}, {@link #SHORT SHORT}, - * {@link #INT INT}, {@link #FLOAT FLOAT}, {@link #LONG LONG}, - * {@link #DOUBLE DOUBLE}, {@link #ARRAY ARRAY}, - * {@link #OBJECT OBJECT} or {@link #METHOD METHOD}. + * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR}, + * {@link #BYTE BYTE}, {@link #SHORT SHORT}, {@link #INT INT}, + * {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE}, + * {@link #ARRAY ARRAY}, {@link #OBJECT OBJECT} or {@link #METHOD + * METHOD}. */ public int getSort() { return sort; @@ -517,34 +537,34 @@ public class Type { */ public String getClassName() { switch (sort) { - case VOID: - return "void"; - case BOOLEAN: - return "boolean"; - case CHAR: - return "char"; - case BYTE: - return "byte"; - case SHORT: - return "short"; - case INT: - return "int"; - case FLOAT: - return "float"; - case LONG: - return "long"; - case DOUBLE: - return "double"; - case ARRAY: - StringBuffer b = new StringBuffer(getElementType().getClassName()); - for (int i = getDimensions(); i > 0; --i) { - b.append("[]"); - } - return b.toString(); - case OBJECT: - return new String(buf, off, len).replace('/', '.'); - default: - return null; + case VOID: + return "void"; + case BOOLEAN: + return "boolean"; + case CHAR: + return "char"; + case BYTE: + return "byte"; + case SHORT: + return "short"; + case INT: + return "int"; + case FLOAT: + return "float"; + case LONG: + return "long"; + case DOUBLE: + return "double"; + case ARRAY: + StringBuffer b = new StringBuffer(getElementType().getClassName()); + for (int i = getDimensions(); i > 0; --i) { + b.append("[]"); + } + return b.toString(); + case OBJECT: + return new String(buf, off, len).replace('/', '.'); + default: + return null; } } @@ -613,15 +633,15 @@ public class Type { * Returns the descriptor corresponding to the given argument and return * types. * - * @param returnType the return type of the method. - * @param argumentTypes the argument types of the method. + * @param returnType + * the return type of the method. + * @param argumentTypes + * the argument types of the method. * @return the descriptor corresponding to the given argument and return * types. */ - public static String getMethodDescriptor( - final Type returnType, - final Type... argumentTypes) - { + public static String getMethodDescriptor(final Type returnType, + final Type... argumentTypes) { StringBuffer buf = new StringBuffer(); buf.append('('); for (int i = 0; i < argumentTypes.length; ++i) { @@ -636,11 +656,13 @@ public class Type { * Appends the descriptor corresponding to this Java type to the given * string buffer. * - * @param buf the string buffer to which the descriptor must be appended. + * @param buf + * the string buffer to which the descriptor must be appended. */ private void getDescriptor(final StringBuffer buf) { if (this.buf == null) { - // descriptor is in byte 3 of 'off' for primitive types (buf == null) + // descriptor is in byte 3 of 'off' for primitive types (buf == + // null) buf.append((char) ((off & 0xFF000000) >>> 24)); } else if (sort == OBJECT) { buf.append('L'); @@ -661,7 +683,8 @@ public class Type { * class is its fully qualified name, as returned by Class.getName(), where * '.' are replaced by '/'. * - * @param c an object or array class. + * @param c + * an object or array class. * @return the internal name of the given class. */ public static String getInternalName(final Class<?> c) { @@ -671,7 +694,8 @@ public class Type { /** * Returns the descriptor corresponding to the given Java type. * - * @param c an object class, a primitive class or an array class. + * @param c + * an object class, a primitive class or an array class. * @return the descriptor corresponding to the given class. */ public static String getDescriptor(final Class<?> c) { @@ -683,7 +707,8 @@ public class Type { /** * Returns the descriptor corresponding to the given constructor. * - * @param c a {@link Constructor Constructor} object. + * @param c + * a {@link Constructor Constructor} object. * @return the descriptor of the given constructor. */ public static String getConstructorDescriptor(final Constructor<?> c) { @@ -699,7 +724,8 @@ public class Type { /** * Returns the descriptor corresponding to the given method. * - * @param m a {@link Method Method} object. + * @param m + * a {@link Method Method} object. * @return the descriptor of the given method. */ public static String getMethodDescriptor(final Method m) { @@ -717,8 +743,10 @@ public class Type { /** * Appends the descriptor of the given class to the given string buffer. * - * @param buf the string buffer to which the descriptor must be appended. - * @param c the class whose descriptor must be computed. + * @param buf + * the string buffer to which the descriptor must be appended. + * @param c + * the class whose descriptor must be computed. */ private static void getDescriptor(final StringBuffer buf, final Class<?> c) { Class<?> d = c; @@ -783,9 +811,10 @@ public class Type { * Returns a JVM instruction opcode adapted to this Java type. This method * must not be used for method types. * - * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, - * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL, - * ISHR, IUSHR, IAND, IOR, IXOR and IRETURN. + * @param opcode + * a JVM instruction opcode. This opcode must be one of ILOAD, + * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, + * ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN. * @return an opcode that is similar to the given opcode, but adapted to * this Java type. For example, if this type is <tt>float</tt> and * <tt>opcode</tt> is IRETURN, this method returns FRETURN. @@ -809,7 +838,8 @@ public class Type { /** * Tests if the given object is equal to this type. * - * @param o the object to be compared to this type. + * @param o + * the object to be compared to this type. * @return <tt>true</tt> if the given object is equal to this type. */ @Override diff --git a/src/asm/scala/tools/asm/signature/SignatureReader.java b/src/asm/scala/tools/asm/signature/SignatureReader.java index 22e6427e63..9c7c3880d9 100644 --- a/src/asm/scala/tools/asm/signature/SignatureReader.java +++ b/src/asm/scala/tools/asm/signature/SignatureReader.java @@ -46,8 +46,9 @@ public class SignatureReader { /** * Constructs a {@link SignatureReader} for the given signature. * - * @param signature A <i>ClassSignature</i>, <i>MethodTypeSignature</i>, - * or <i>FieldTypeSignature</i>. + * @param signature + * A <i>ClassSignature</i>, <i>MethodTypeSignature</i>, or + * <i>FieldTypeSignature</i>. */ public SignatureReader(final String signature) { this.signature = signature; @@ -58,15 +59,15 @@ public class SignatureReader { * {@link SignatureReader}. This signature is the one specified in the * constructor (see {@link #SignatureReader(String) SignatureReader}). This * method is intended to be called on a {@link SignatureReader} that was - * created using a <i>ClassSignature</i> (such as the + * created using a <i>ClassSignature</i> (such as the <code>signature</code> + * parameter of the {@link scala.tools.asm.ClassVisitor#visit + * ClassVisitor.visit} method) or a <i>MethodTypeSignature</i> (such as the * <code>signature</code> parameter of the - * {@link org.objectweb.asm.ClassVisitor#visit ClassVisitor.visit} method) - * or a <i>MethodTypeSignature</i> (such as the <code>signature</code> - * parameter of the - * {@link org.objectweb.asm.ClassVisitor#visitMethod ClassVisitor.visitMethod} - * method). + * {@link scala.tools.asm.ClassVisitor#visitMethod + * ClassVisitor.visitMethod} method). * - * @param v the visitor that must visit this signature. + * @param v + * the visitor that must visit this signature. */ public void accept(final SignatureVisitor v) { String signature = this.signature; @@ -118,12 +119,12 @@ public class SignatureReader { * method is intended to be called on a {@link SignatureReader} that was * created using a <i>FieldTypeSignature</i>, such as the * <code>signature</code> parameter of the - * {@link org.objectweb.asm.ClassVisitor#visitField - * ClassVisitor.visitField} or {@link - * org.objectweb.asm.MethodVisitor#visitLocalVariable + * {@link scala.tools.asm.ClassVisitor#visitField ClassVisitor.visitField} + * or {@link scala.tools.asm.MethodVisitor#visitLocalVariable * MethodVisitor.visitLocalVariable} methods. * - * @param v the visitor that must visit this signature. + * @param v + * the visitor that must visit this signature. */ public void acceptType(final SignatureVisitor v) { parseType(this.signature, 0, v); @@ -132,98 +133,96 @@ public class SignatureReader { /** * Parses a field type signature and makes the given visitor visit it. * - * @param signature a string containing the signature that must be parsed. - * @param pos index of the first character of the signature to parsed. - * @param v the visitor that must visit this signature. + * @param signature + * a string containing the signature that must be parsed. + * @param pos + * index of the first character of the signature to parsed. + * @param v + * the visitor that must visit this signature. * @return the index of the first character after the parsed signature. */ - private static int parseType( - final String signature, - int pos, - final SignatureVisitor v) - { + private static int parseType(final String signature, int pos, + final SignatureVisitor v) { char c; int start, end; boolean visited, inner; String name; switch (c = signature.charAt(pos++)) { - case 'Z': - case 'C': - case 'B': - case 'S': - case 'I': - case 'F': - case 'J': - case 'D': - case 'V': - v.visitBaseType(c); - return pos; + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + case 'F': + case 'J': + case 'D': + case 'V': + v.visitBaseType(c); + return pos; - case '[': - return parseType(signature, pos, v.visitArrayType()); + case '[': + return parseType(signature, pos, v.visitArrayType()); - case 'T': - end = signature.indexOf(';', pos); - v.visitTypeVariable(signature.substring(pos, end)); - return end + 1; + case 'T': + end = signature.indexOf(';', pos); + v.visitTypeVariable(signature.substring(pos, end)); + return end + 1; - default: // case 'L': - start = pos; - visited = false; - inner = false; - for (;;) { - switch (c = signature.charAt(pos++)) { - case '.': - case ';': - if (!visited) { - name = signature.substring(start, pos - 1); - if (inner) { - v.visitInnerClassType(name); - } else { - v.visitClassType(name); - } - } - if (c == ';') { - v.visitEnd(); - return pos; - } - start = pos; - visited = false; - inner = true; - break; + default: // case 'L': + start = pos; + visited = false; + inner = false; + for (;;) { + switch (c = signature.charAt(pos++)) { + case '.': + case ';': + if (!visited) { + name = signature.substring(start, pos - 1); + if (inner) { + v.visitInnerClassType(name); + } else { + v.visitClassType(name); + } + } + if (c == ';') { + v.visitEnd(); + return pos; + } + start = pos; + visited = false; + inner = true; + break; - case '<': - name = signature.substring(start, pos - 1); - if (inner) { - v.visitInnerClassType(name); - } else { - v.visitClassType(name); - } - visited = true; - top: for (;;) { - switch (c = signature.charAt(pos)) { - case '>': - break top; - case '*': - ++pos; - v.visitTypeArgument(); - break; - case '+': - case '-': - pos = parseType(signature, - pos + 1, - v.visitTypeArgument(c)); - break; - default: - pos = parseType(signature, - pos, - v.visitTypeArgument('=')); - break; - } - } + case '<': + name = signature.substring(start, pos - 1); + if (inner) { + v.visitInnerClassType(name); + } else { + v.visitClassType(name); + } + visited = true; + top: for (;;) { + switch (c = signature.charAt(pos)) { + case '>': + break top; + case '*': + ++pos; + v.visitTypeArgument(); + break; + case '+': + case '-': + pos = parseType(signature, pos + 1, + v.visitTypeArgument(c)); + break; + default: + pos = parseType(signature, pos, + v.visitTypeArgument('=')); + break; + } } } + } } } } diff --git a/src/asm/scala/tools/asm/signature/SignatureVisitor.java b/src/asm/scala/tools/asm/signature/SignatureVisitor.java index 2fc364e374..f38f81f53b 100644 --- a/src/asm/scala/tools/asm/signature/SignatureVisitor.java +++ b/src/asm/scala/tools/asm/signature/SignatureVisitor.java @@ -35,21 +35,21 @@ import scala.tools.asm.Opcodes; * A visitor to visit a generic signature. The methods of this interface must be * called in one of the three following orders (the last one is the only valid * order for a {@link SignatureVisitor} that is returned by a method of this - * interface): <ul> <li><i>ClassSignature</i> = ( - * <tt>visitFormalTypeParameter</tt> - * <tt>visitClassBound</tt>? - * <tt>visitInterfaceBound</tt>* )* ( <tt>visitSuperClass</tt> - * <tt>visitInterface</tt>* )</li> + * interface): + * <ul> + * <li><i>ClassSignature</i> = ( <tt>visitFormalTypeParameter</tt> + * <tt>visitClassBound</tt>? <tt>visitInterfaceBound</tt>* )* ( + * <tt>visitSuperClass</tt> <tt>visitInterface</tt>* )</li> * <li><i>MethodSignature</i> = ( <tt>visitFormalTypeParameter</tt> - * <tt>visitClassBound</tt>? - * <tt>visitInterfaceBound</tt>* )* ( <tt>visitParameterType</tt>* - * <tt>visitReturnType</tt> - * <tt>visitExceptionType</tt>* )</li> <li><i>TypeSignature</i> = - * <tt>visitBaseType</tt> | <tt>visitTypeVariable</tt> | - * <tt>visitArrayType</tt> | ( + * <tt>visitClassBound</tt>? <tt>visitInterfaceBound</tt>* )* ( + * <tt>visitParameterType</tt>* <tt>visitReturnType</tt> + * <tt>visitExceptionType</tt>* )</li> + * <li><i>TypeSignature</i> = <tt>visitBaseType</tt> | + * <tt>visitTypeVariable</tt> | <tt>visitArrayType</tt> | ( * <tt>visitClassType</tt> <tt>visitTypeArgument</tt>* ( - * <tt>visitInnerClassType</tt> <tt>visitTypeArgument</tt>* )* - * <tt>visitEnd</tt> ) )</li> </ul> + * <tt>visitInnerClassType</tt> <tt>visitTypeArgument</tt>* )* <tt>visitEnd</tt> + * ) )</li> + * </ul> * * @author Thomas Hallgren * @author Eric Bruneton @@ -80,8 +80,9 @@ public abstract class SignatureVisitor { /** * Constructs a new {@link SignatureVisitor}. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. */ public SignatureVisitor(final int api) { this.api = api; @@ -90,7 +91,8 @@ public abstract class SignatureVisitor { /** * Visits a formal type parameter. * - * @param name the name of the formal parameter. + * @param name + * the name of the formal parameter. */ public void visitFormalTypeParameter(String name) { } @@ -162,8 +164,9 @@ public abstract class SignatureVisitor { /** * Visits a signature corresponding to a primitive type. * - * @param descriptor the descriptor of the primitive type, or 'V' for - * <tt>void</tt>. + * @param descriptor + * the descriptor of the primitive type, or 'V' for <tt>void</tt> + * . */ public void visitBaseType(char descriptor) { } @@ -171,7 +174,8 @@ public abstract class SignatureVisitor { /** * Visits a signature corresponding to a type variable. * - * @param name the name of the type variable. + * @param name + * the name of the type variable. */ public void visitTypeVariable(String name) { } @@ -190,7 +194,8 @@ public abstract class SignatureVisitor { * Starts the visit of a signature corresponding to a class or interface * type. * - * @param name the internal name of the class or interface. + * @param name + * the internal name of the class or interface. */ public void visitClassType(String name) { } @@ -198,7 +203,8 @@ public abstract class SignatureVisitor { /** * Visits an inner class. * - * @param name the local name of the inner class in its enclosing class. + * @param name + * the local name of the inner class in its enclosing class. */ public void visitInnerClassType(String name) { } @@ -213,7 +219,8 @@ public abstract class SignatureVisitor { /** * Visits a type argument of the last visited class or inner class type. * - * @param wildcard '+', '-' or '='. + * @param wildcard + * '+', '-' or '='. * @return a non null visitor to visit the signature of the type argument. */ public SignatureVisitor visitTypeArgument(char wildcard) { diff --git a/src/asm/scala/tools/asm/signature/SignatureWriter.java b/src/asm/scala/tools/asm/signature/SignatureWriter.java index a59fdfde2b..ebf4fe07b4 100644 --- a/src/asm/scala/tools/asm/signature/SignatureWriter.java +++ b/src/asm/scala/tools/asm/signature/SignatureWriter.java @@ -224,4 +224,4 @@ public class SignatureWriter extends SignatureVisitor { } argumentStack /= 2; } -}
\ No newline at end of file +} diff --git a/src/asm/scala/tools/asm/tree/AbstractInsnNode.java b/src/asm/scala/tools/asm/tree/AbstractInsnNode.java index 471f842ffc..411eead3c7 100644 --- a/src/asm/scala/tools/asm/tree/AbstractInsnNode.java +++ b/src/asm/scala/tools/asm/tree/AbstractInsnNode.java @@ -148,7 +148,8 @@ public abstract class AbstractInsnNode { /** * Constructs a new {@link AbstractInsnNode}. * - * @param opcode the opcode of the instruction to be constructed. + * @param opcode + * the opcode of the instruction to be constructed. */ protected AbstractInsnNode(final int opcode) { this.opcode = opcode; @@ -197,38 +198,47 @@ public abstract class AbstractInsnNode { /** * Makes the given code visitor visit this instruction. * - * @param cv a code visitor. + * @param cv + * a code visitor. */ public abstract void accept(final MethodVisitor cv); /** * Returns a copy of this instruction. * - * @param labels a map from LabelNodes to cloned LabelNodes. + * @param labels + * a map from LabelNodes to cloned LabelNodes. * @return a copy of this instruction. The returned instruction does not * belong to any {@link InsnList}. */ - public abstract AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels); + public abstract AbstractInsnNode clone( + final Map<LabelNode, LabelNode> labels); /** * Returns the clone of the given label. * - * @param label a label. - * @param map a map from LabelNodes to cloned LabelNodes. + * @param label + * a label. + * @param map + * a map from LabelNodes to cloned LabelNodes. * @return the clone of the given label. */ - static LabelNode clone(final LabelNode label, final Map<LabelNode, LabelNode> map) { + static LabelNode clone(final LabelNode label, + final Map<LabelNode, LabelNode> map) { return map.get(label); } /** * Returns the clones of the given labels. * - * @param labels a list of labels. - * @param map a map from LabelNodes to cloned LabelNodes. + * @param labels + * a list of labels. + * @param map + * a map from LabelNodes to cloned LabelNodes. * @return the clones of the given labels. */ - static LabelNode[] clone(final List<LabelNode> labels, final Map<LabelNode, LabelNode> map) { + static LabelNode[] clone(final List<LabelNode> labels, + final Map<LabelNode, LabelNode> map) { LabelNode[] clones = new LabelNode[labels.size()]; for (int i = 0; i < clones.length; ++i) { clones[i] = map.get(labels.get(i)); diff --git a/src/asm/scala/tools/asm/tree/AnnotationNode.java b/src/asm/scala/tools/asm/tree/AnnotationNode.java index 9f132550e6..1f4beef9f7 100644 --- a/src/asm/scala/tools/asm/tree/AnnotationNode.java +++ b/src/asm/scala/tools/asm/tree/AnnotationNode.java @@ -52,11 +52,11 @@ public class AnnotationNode extends AnnotationVisitor { * as two consecutive elements in the list. The name is a {@link String}, * and the value may be a {@link Byte}, {@link Boolean}, {@link Character}, * {@link Short}, {@link Integer}, {@link Long}, {@link Float}, - * {@link Double}, {@link String} or {@link org.objectweb.asm.Type}, or an + * {@link Double}, {@link String} or {@link scala.tools.asm.Type}, or an * two elements String array (for enumeration values), a * {@link AnnotationNode}, or a {@link List} of values of one of the - * preceding types. The list may be <tt>null</tt> if there is no name - * value pair. + * preceding types. The list may be <tt>null</tt> if there is no name value + * pair. */ public List<Object> values; @@ -65,7 +65,8 @@ public class AnnotationNode extends AnnotationVisitor { * constructor</i>. Instead, they must use the * {@link #AnnotationNode(int, String)} version. * - * @param desc the class descriptor of the annotation class. + * @param desc + * the class descriptor of the annotation class. */ public AnnotationNode(final String desc) { this(Opcodes.ASM4, desc); @@ -74,9 +75,11 @@ public class AnnotationNode extends AnnotationVisitor { /** * Constructs a new {@link AnnotationNode}. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. - * @param desc the class descriptor of the annotation class. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param desc + * the class descriptor of the annotation class. */ public AnnotationNode(final int api, final String desc) { super(api); @@ -86,7 +89,8 @@ public class AnnotationNode extends AnnotationVisitor { /** * Constructs a new {@link AnnotationNode} to visit an array value. * - * @param values where the visited values must be stored. + * @param values + * where the visited values must be stored. */ AnnotationNode(final List<Object> values) { super(Opcodes.ASM4); @@ -109,11 +113,8 @@ public class AnnotationNode extends AnnotationVisitor { } @Override - public void visitEnum( - final String name, - final String desc, - final String value) - { + public void visitEnum(final String name, final String desc, + final String value) { if (values == null) { values = new ArrayList<Object>(this.desc != null ? 2 : 1); } @@ -124,10 +125,8 @@ public class AnnotationNode extends AnnotationVisitor { } @Override - public AnnotationVisitor visitAnnotation( - final String name, - final String desc) - { + public AnnotationVisitor visitAnnotation(final String name, + final String desc) { if (values == null) { values = new ArrayList<Object>(this.desc != null ? 2 : 1); } @@ -166,7 +165,8 @@ public class AnnotationNode extends AnnotationVisitor { * recursively, do not contain elements that were introduced in more recent * versions of the ASM API than the given version. * - * @param api an ASM API version. Must be one of {@link Opcodes#ASM4}. + * @param api + * an ASM API version. Must be one of {@link Opcodes#ASM4}. */ public void check(final int api) { // nothing to do @@ -175,7 +175,8 @@ public class AnnotationNode extends AnnotationVisitor { /** * Makes the given visitor visit this annotation. * - * @param av an annotation visitor. Maybe <tt>null</tt>. + * @param av + * an annotation visitor. Maybe <tt>null</tt>. */ public void accept(final AnnotationVisitor av) { if (av != null) { @@ -193,15 +194,15 @@ public class AnnotationNode extends AnnotationVisitor { /** * Makes the given visitor visit a given annotation value. * - * @param av an annotation visitor. Maybe <tt>null</tt>. - * @param name the value name. - * @param value the actual value. + * @param av + * an annotation visitor. Maybe <tt>null</tt>. + * @param name + * the value name. + * @param value + * the actual value. */ - static void accept( - final AnnotationVisitor av, - final String name, - final Object value) - { + static void accept(final AnnotationVisitor av, final String name, + final Object value) { if (av != null) { if (value instanceof String[]) { String[] typeconst = (String[]) value; diff --git a/src/asm/scala/tools/asm/tree/ClassNode.java b/src/asm/scala/tools/asm/tree/ClassNode.java index 64effae698..c3d999985a 100644 --- a/src/asm/scala/tools/asm/tree/ClassNode.java +++ b/src/asm/scala/tools/asm/tree/ClassNode.java @@ -53,33 +53,33 @@ public class ClassNode extends ClassVisitor { public int version; /** - * The class's access flags (see {@link org.objectweb.asm.Opcodes}). This + * The class's access flags (see {@link scala.tools.asm.Opcodes}). This * field also indicates if the class is deprecated. */ public int access; /** * The internal name of the class (see - * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). + * {@link scala.tools.asm.Type#getInternalName() getInternalName}). */ public String name; /** - * The signature of the class. Mayt be <tt>null</tt>. + * The signature of the class. May be <tt>null</tt>. */ public String signature; /** * The internal of name of the super class (see - * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). For - * interfaces, the super class is {@link Object}. May be <tt>null</tt>, - * but only for the {@link Object} class. + * {@link scala.tools.asm.Type#getInternalName() getInternalName}). For + * interfaces, the super class is {@link Object}. May be <tt>null</tt>, but + * only for the {@link Object} class. */ public String superName; /** * The internal names of the class's interfaces (see - * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). This + * {@link scala.tools.asm.Type#getInternalName() getInternalName}). This * list is a list of {@link String} objects. */ public List<String> interfaces; @@ -91,7 +91,7 @@ public class ClassNode extends ClassVisitor { public String sourceFile; /** - * Debug information to compute the correspondance between source and + * Debug information to compute the correspondence between source and * compiled elements of the class. May be <tt>null</tt>. */ public String sourceDebug; @@ -109,8 +109,8 @@ public class ClassNode extends ClassVisitor { public String outerMethod; /** - * The descriptor of the method that contains the class, or <tt>null</tt> - * if the class is not enclosed in a method. + * The descriptor of the method that contains the class, or <tt>null</tt> if + * the class is not enclosed in a method. */ public String outerMethodDesc; @@ -118,7 +118,7 @@ public class ClassNode extends ClassVisitor { * The runtime visible annotations of this class. This list is a list of * {@link AnnotationNode} objects. May be <tt>null</tt>. * - * @associates org.objectweb.asm.tree.AnnotationNode + * @associates scala.tools.asm.tree.AnnotationNode * @label visible */ public List<AnnotationNode> visibleAnnotations; @@ -127,7 +127,7 @@ public class ClassNode extends ClassVisitor { * The runtime invisible annotations of this class. This list is a list of * {@link AnnotationNode} objects. May be <tt>null</tt>. * - * @associates org.objectweb.asm.tree.AnnotationNode + * @associates scala.tools.asm.tree.AnnotationNode * @label invisible */ public List<AnnotationNode> invisibleAnnotations; @@ -136,7 +136,7 @@ public class ClassNode extends ClassVisitor { * The non standard attributes of this class. This list is a list of * {@link Attribute} objects. May be <tt>null</tt>. * - * @associates org.objectweb.asm.Attribute + * @associates scala.tools.asm.Attribute */ public List<Attribute> attrs; @@ -144,7 +144,7 @@ public class ClassNode extends ClassVisitor { * Informations about the inner classes of this class. This list is a list * of {@link InnerClassNode} objects. * - * @associates org.objectweb.asm.tree.InnerClassNode + * @associates scala.tools.asm.tree.InnerClassNode */ public List<InnerClassNode> innerClasses; @@ -152,7 +152,7 @@ public class ClassNode extends ClassVisitor { * The fields of this class. This list is a list of {@link FieldNode} * objects. * - * @associates org.objectweb.asm.tree.FieldNode + * @associates scala.tools.asm.tree.FieldNode */ public List<FieldNode> fields; @@ -160,7 +160,7 @@ public class ClassNode extends ClassVisitor { * The methods of this class. This list is a list of {@link MethodNode} * objects. * - * @associates org.objectweb.asm.tree.MethodNode + * @associates scala.tools.asm.tree.MethodNode */ public List<MethodNode> methods; @@ -176,8 +176,9 @@ public class ClassNode extends ClassVisitor { /** * Constructs a new {@link ClassNode}. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. */ public ClassNode(final int api) { super(api); @@ -192,14 +193,9 @@ public class ClassNode extends ClassVisitor { // ------------------------------------------------------------------------ @Override - public void visit( - final int version, - final int access, - final String name, - final String signature, - final String superName, - final String[] interfaces) - { + public void visit(final int version, final int access, final String name, + final String signature, final String superName, + final String[] interfaces) { this.version = version; this.access = access; this.name = name; @@ -217,21 +213,16 @@ public class ClassNode extends ClassVisitor { } @Override - public void visitOuterClass( - final String owner, - final String name, - final String desc) - { + public void visitOuterClass(final String owner, final String name, + final String desc) { outerClass = owner; outerMethod = name; outerMethodDesc = desc; } @Override - public AnnotationVisitor visitAnnotation( - final String desc, - final boolean visible) - { + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { AnnotationNode an = new AnnotationNode(desc); if (visible) { if (visibleAnnotations == null) { @@ -256,44 +247,25 @@ public class ClassNode extends ClassVisitor { } @Override - public void visitInnerClass( - final String name, - final String outerName, - final String innerName, - final int access) - { - InnerClassNode icn = new InnerClassNode(name, - outerName, - innerName, + public void visitInnerClass(final String name, final String outerName, + final String innerName, final int access) { + InnerClassNode icn = new InnerClassNode(name, outerName, innerName, access); innerClasses.add(icn); } @Override - public FieldVisitor visitField( - final int access, - final String name, - final String desc, - final String signature, - final Object value) - { + public FieldVisitor visitField(final int access, final String name, + final String desc, final String signature, final Object value) { FieldNode fn = new FieldNode(access, name, desc, signature, value); fields.add(fn); return fn; } @Override - public MethodVisitor visitMethod( - final int access, - final String name, - final String desc, - final String signature, - final String[] exceptions) - { - MethodNode mn = new MethodNode(access, - name, - desc, - signature, + public MethodVisitor visitMethod(final int access, final String name, + final String desc, final String signature, final String[] exceptions) { + MethodNode mn = new MethodNode(access, name, desc, signature, exceptions); methods.add(mn); return mn; @@ -313,7 +285,8 @@ public class ClassNode extends ClassVisitor { * contain elements that were introduced in more recent versions of the ASM * API than the given version. * - * @param api an ASM API version. Must be one of {@link Opcodes#ASM4}. + * @param api + * an ASM API version. Must be one of {@link Opcodes#ASM4}. */ public void check(final int api) { // nothing to do @@ -322,7 +295,8 @@ public class ClassNode extends ClassVisitor { /** * Makes the given class visitor visit this class. * - * @param cv a class visitor. + * @param cv + * a class visitor. */ public void accept(final ClassVisitor cv) { // visits header diff --git a/src/asm/scala/tools/asm/tree/FieldInsnNode.java b/src/asm/scala/tools/asm/tree/FieldInsnNode.java index 6b7a6a142a..0c94f18adf 100644 --- a/src/asm/scala/tools/asm/tree/FieldInsnNode.java +++ b/src/asm/scala/tools/asm/tree/FieldInsnNode.java @@ -43,7 +43,7 @@ public class FieldInsnNode extends AbstractInsnNode { /** * The internal name of the field's owner class (see - * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). + * {@link scala.tools.asm.Type#getInternalName() getInternalName}). */ public String owner; @@ -53,26 +53,27 @@ public class FieldInsnNode extends AbstractInsnNode { public String name; /** - * The field's descriptor (see {@link org.objectweb.asm.Type}). + * The field's descriptor (see {@link scala.tools.asm.Type}). */ public String desc; /** * Constructs a new {@link FieldInsnNode}. * - * @param opcode the opcode of the type instruction to be constructed. This - * opcode must be GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. - * @param owner the internal name of the field's owner class (see - * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). - * @param name the field's name. - * @param desc the field's descriptor (see {@link org.objectweb.asm.Type}). + * @param opcode + * the opcode of the type instruction to be constructed. This + * opcode must be GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. + * @param owner + * the internal name of the field's owner class (see + * {@link scala.tools.asm.Type#getInternalName() + * getInternalName}). + * @param name + * the field's name. + * @param desc + * the field's descriptor (see {@link scala.tools.asm.Type}). */ - public FieldInsnNode( - final int opcode, - final String owner, - final String name, - final String desc) - { + public FieldInsnNode(final int opcode, final String owner, + final String name, final String desc) { super(opcode); this.owner = owner; this.name = name; @@ -82,8 +83,9 @@ public class FieldInsnNode extends AbstractInsnNode { /** * Sets the opcode of this instruction. * - * @param opcode the new instruction opcode. This opcode must be GETSTATIC, - * PUTSTATIC, GETFIELD or PUTFIELD. + * @param opcode + * the new instruction opcode. This opcode must be GETSTATIC, + * PUTSTATIC, GETFIELD or PUTFIELD. */ public void setOpcode(final int opcode) { this.opcode = opcode; diff --git a/src/asm/scala/tools/asm/tree/FieldNode.java b/src/asm/scala/tools/asm/tree/FieldNode.java index 9a1e17033c..61b614ec59 100644 --- a/src/asm/scala/tools/asm/tree/FieldNode.java +++ b/src/asm/scala/tools/asm/tree/FieldNode.java @@ -46,7 +46,7 @@ import scala.tools.asm.Opcodes; public class FieldNode extends FieldVisitor { /** - * The field's access flags (see {@link org.objectweb.asm.Opcodes}). This + * The field's access flags (see {@link scala.tools.asm.Opcodes}). This * field also indicates if the field is synthetic and/or deprecated. */ public int access; @@ -57,7 +57,7 @@ public class FieldNode extends FieldVisitor { public String name; /** - * The field's descriptor (see {@link org.objectweb.asm.Type}). + * The field's descriptor (see {@link scala.tools.asm.Type}). */ public String desc; @@ -67,8 +67,8 @@ public class FieldNode extends FieldVisitor { public String signature; /** - * The field's initial value. This field, which may be <tt>null</tt> if - * the field does not have an initial value, must be an {@link Integer}, a + * The field's initial value. This field, which may be <tt>null</tt> if the + * field does not have an initial value, must be an {@link Integer}, a * {@link Float}, a {@link Long}, a {@link Double} or a {@link String}. */ public Object value; @@ -77,7 +77,7 @@ public class FieldNode extends FieldVisitor { * The runtime visible annotations of this field. This list is a list of * {@link AnnotationNode} objects. May be <tt>null</tt>. * - * @associates org.objectweb.asm.tree.AnnotationNode + * @associates scala.tools.asm.tree.AnnotationNode * @label visible */ public List<AnnotationNode> visibleAnnotations; @@ -86,7 +86,7 @@ public class FieldNode extends FieldVisitor { * The runtime invisible annotations of this field. This list is a list of * {@link AnnotationNode} objects. May be <tt>null</tt>. * - * @associates org.objectweb.asm.tree.AnnotationNode + * @associates scala.tools.asm.tree.AnnotationNode * @label invisible */ public List<AnnotationNode> invisibleAnnotations; @@ -95,7 +95,7 @@ public class FieldNode extends FieldVisitor { * The non standard attributes of this field. This list is a list of * {@link Attribute} objects. May be <tt>null</tt>. * - * @associates org.objectweb.asm.Attribute + * @associates scala.tools.asm.Attribute */ public List<Attribute> attrs; @@ -104,25 +104,25 @@ public class FieldNode extends FieldVisitor { * constructor</i>. Instead, they must use the * {@link #FieldNode(int, int, String, String, String, Object)} version. * - * @param access the field's access flags (see - * {@link org.objectweb.asm.Opcodes}). This parameter also indicates - * if the field is synthetic and/or deprecated. - * @param name the field's name. - * @param desc the field's descriptor (see {@link org.objectweb.asm.Type - * Type}). - * @param signature the field's signature. - * @param value the field's initial value. This parameter, which may be - * <tt>null</tt> if the field does not have an initial value, must be - * an {@link Integer}, a {@link Float}, a {@link Long}, a - * {@link Double} or a {@link String}. + * @param access + * the field's access flags (see + * {@link scala.tools.asm.Opcodes}). This parameter also + * indicates if the field is synthetic and/or deprecated. + * @param name + * the field's name. + * @param desc + * the field's descriptor (see {@link scala.tools.asm.Type + * Type}). + * @param signature + * the field's signature. + * @param value + * the field's initial value. This parameter, which may be + * <tt>null</tt> if the field does not have an initial value, + * must be an {@link Integer}, a {@link Float}, a {@link Long}, a + * {@link Double} or a {@link String}. */ - public FieldNode( - final int access, - final String name, - final String desc, - final String signature, - final Object value) - { + public FieldNode(final int access, final String name, final String desc, + final String signature, final Object value) { this(Opcodes.ASM4, access, name, desc, signature, value); } @@ -131,28 +131,28 @@ public class FieldNode extends FieldVisitor { * constructor</i>. Instead, they must use the * {@link #FieldNode(int, int, String, String, String, Object)} version. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. - * @param access the field's access flags (see - * {@link org.objectweb.asm.Opcodes}). This parameter also indicates - * if the field is synthetic and/or deprecated. - * @param name the field's name. - * @param desc the field's descriptor (see {@link org.objectweb.asm.Type - * Type}). - * @param signature the field's signature. - * @param value the field's initial value. This parameter, which may be - * <tt>null</tt> if the field does not have an initial value, must be - * an {@link Integer}, a {@link Float}, a {@link Long}, a - * {@link Double} or a {@link String}. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param access + * the field's access flags (see + * {@link scala.tools.asm.Opcodes}). This parameter also + * indicates if the field is synthetic and/or deprecated. + * @param name + * the field's name. + * @param desc + * the field's descriptor (see {@link scala.tools.asm.Type + * Type}). + * @param signature + * the field's signature. + * @param value + * the field's initial value. This parameter, which may be + * <tt>null</tt> if the field does not have an initial value, + * must be an {@link Integer}, a {@link Float}, a {@link Long}, a + * {@link Double} or a {@link String}. */ - public FieldNode( - final int api, - final int access, - final String name, - final String desc, - final String signature, - final Object value) - { + public FieldNode(final int api, final int access, final String name, + final String desc, final String signature, final Object value) { super(api); this.access = access; this.name = name; @@ -166,10 +166,8 @@ public class FieldNode extends FieldVisitor { // ------------------------------------------------------------------------ @Override - public AnnotationVisitor visitAnnotation( - final String desc, - final boolean visible) - { + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { AnnotationNode an = new AnnotationNode(desc); if (visible) { if (visibleAnnotations == null) { @@ -207,7 +205,8 @@ public class FieldNode extends FieldVisitor { * contain elements that were introduced in more recent versions of the ASM * API than the given version. * - * @param api an ASM API version. Must be one of {@link Opcodes#ASM4}. + * @param api + * an ASM API version. Must be one of {@link Opcodes#ASM4}. */ public void check(final int api) { // nothing to do @@ -216,7 +215,8 @@ public class FieldNode extends FieldVisitor { /** * Makes the given class visitor visit this field. * - * @param cv a class visitor. + * @param cv + * a class visitor. */ public void accept(final ClassVisitor cv) { FieldVisitor fv = cv.visitField(access, name, desc, signature, value); diff --git a/src/asm/scala/tools/asm/tree/FrameNode.java b/src/asm/scala/tools/asm/tree/FrameNode.java index 66825de0ac..f13fc66749 100644 --- a/src/asm/scala/tools/asm/tree/FrameNode.java +++ b/src/asm/scala/tools/asm/tree/FrameNode.java @@ -45,8 +45,9 @@ import scala.tools.asm.Opcodes; * the target of a jump instruction, or that starts an exception handler block. * The stack map frame types must describe the values of the local variables and * of the operand stack elements <i>just before</i> <b>i</b> is executed. <br> - * <br> (*) this is mandatory only for classes whose version is greater than or - * equal to {@link Opcodes#V1_6 V1_6}. + * <br> + * (*) this is mandatory only for classes whose version is greater than or equal + * to {@link Opcodes#V1_6 V1_6}. * * @author Eric Bruneton */ @@ -83,48 +84,48 @@ public class FrameNode extends AbstractInsnNode { /** * Constructs a new {@link FrameNode}. * - * @param type the type of this frame. Must be {@link Opcodes#F_NEW} for - * expanded frames, or {@link Opcodes#F_FULL}, - * {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, - * {@link Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, - * {@link Opcodes#F_SAME1} for compressed frames. - * @param nLocal number of local variables of this stack map frame. - * @param local the types of the local variables of this stack map frame. - * Elements of this list can be Integer, String or LabelNode objects - * (for primitive, reference and uninitialized types respectively - - * see {@link MethodVisitor}). - * @param nStack number of operand stack elements of this stack map frame. - * @param stack the types of the operand stack elements of this stack map - * frame. Elements of this list can be Integer, String or LabelNode - * objects (for primitive, reference and uninitialized types - * respectively - see {@link MethodVisitor}). + * @param type + * the type of this frame. Must be {@link Opcodes#F_NEW} for + * expanded frames, or {@link Opcodes#F_FULL}, + * {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, + * {@link Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, + * {@link Opcodes#F_SAME1} for compressed frames. + * @param nLocal + * number of local variables of this stack map frame. + * @param local + * the types of the local variables of this stack map frame. + * Elements of this list can be Integer, String or LabelNode + * objects (for primitive, reference and uninitialized types + * respectively - see {@link MethodVisitor}). + * @param nStack + * number of operand stack elements of this stack map frame. + * @param stack + * the types of the operand stack elements of this stack map + * frame. Elements of this list can be Integer, String or + * LabelNode objects (for primitive, reference and uninitialized + * types respectively - see {@link MethodVisitor}). */ - public FrameNode( - final int type, - final int nLocal, - final Object[] local, - final int nStack, - final Object[] stack) - { + public FrameNode(final int type, final int nLocal, final Object[] local, + final int nStack, final Object[] stack) { super(-1); this.type = type; switch (type) { - case Opcodes.F_NEW: - case Opcodes.F_FULL: - this.local = asList(nLocal, local); - this.stack = asList(nStack, stack); - break; - case Opcodes.F_APPEND: - this.local = asList(nLocal, local); - break; - case Opcodes.F_CHOP: - this.local = Arrays.asList(new Object[nLocal]); - break; - case Opcodes.F_SAME: - break; - case Opcodes.F_SAME1: - this.stack = asList(1, stack); - break; + case Opcodes.F_NEW: + case Opcodes.F_FULL: + this.local = asList(nLocal, local); + this.stack = asList(nStack, stack); + break; + case Opcodes.F_APPEND: + this.local = asList(nLocal, local); + break; + case Opcodes.F_CHOP: + this.local = Arrays.asList(new Object[nLocal]); + break; + case Opcodes.F_SAME: + break; + case Opcodes.F_SAME1: + this.stack = asList(1, stack); + break; } } @@ -136,31 +137,29 @@ public class FrameNode extends AbstractInsnNode { /** * Makes the given visitor visit this stack map frame. * - * @param mv a method visitor. + * @param mv + * a method visitor. */ @Override public void accept(final MethodVisitor mv) { switch (type) { - case Opcodes.F_NEW: - case Opcodes.F_FULL: - mv.visitFrame(type, - local.size(), - asArray(local), - stack.size(), - asArray(stack)); - break; - case Opcodes.F_APPEND: - mv.visitFrame(type, local.size(), asArray(local), 0, null); - break; - case Opcodes.F_CHOP: - mv.visitFrame(type, local.size(), null, 0, null); - break; - case Opcodes.F_SAME: - mv.visitFrame(type, 0, null, 0, null); - break; - case Opcodes.F_SAME1: - mv.visitFrame(type, 0, null, 1, asArray(stack)); - break; + case Opcodes.F_NEW: + case Opcodes.F_FULL: + mv.visitFrame(type, local.size(), asArray(local), stack.size(), + asArray(stack)); + break; + case Opcodes.F_APPEND: + mv.visitFrame(type, local.size(), asArray(local), 0, null); + break; + case Opcodes.F_CHOP: + mv.visitFrame(type, local.size(), null, 0, null); + break; + case Opcodes.F_SAME: + mv.visitFrame(type, 0, null, 0, null); + break; + case Opcodes.F_SAME1: + mv.visitFrame(type, 0, null, 1, asArray(stack)); + break; } } diff --git a/src/asm/scala/tools/asm/tree/IincInsnNode.java b/src/asm/scala/tools/asm/tree/IincInsnNode.java index 75ac40884d..f9adf2e38c 100644 --- a/src/asm/scala/tools/asm/tree/IincInsnNode.java +++ b/src/asm/scala/tools/asm/tree/IincInsnNode.java @@ -54,8 +54,10 @@ public class IincInsnNode extends AbstractInsnNode { /** * Constructs a new {@link IincInsnNode}. * - * @param var index of the local variable to be incremented. - * @param incr increment amount to increment the local variable by. + * @param var + * index of the local variable to be incremented. + * @param incr + * increment amount to increment the local variable by. */ public IincInsnNode(final int var, final int incr) { super(Opcodes.IINC); @@ -77,4 +79,4 @@ public class IincInsnNode extends AbstractInsnNode { public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) { return new IincInsnNode(var, incr); } -}
\ No newline at end of file +} diff --git a/src/asm/scala/tools/asm/tree/InnerClassNode.java b/src/asm/scala/tools/asm/tree/InnerClassNode.java index 4579488921..aa3810c759 100644 --- a/src/asm/scala/tools/asm/tree/InnerClassNode.java +++ b/src/asm/scala/tools/asm/tree/InnerClassNode.java @@ -40,14 +40,14 @@ public class InnerClassNode { /** * The internal name of an inner class (see - * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). + * {@link scala.tools.asm.Type#getInternalName() getInternalName}). */ public String name; /** * The internal name of the class to which the inner class belongs (see - * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). May - * be <tt>null</tt>. + * {@link scala.tools.asm.Type#getInternalName() getInternalName}). May be + * <tt>null</tt>. */ public String outerName; @@ -66,24 +66,23 @@ public class InnerClassNode { /** * Constructs a new {@link InnerClassNode}. * - * @param name the internal name of an inner class (see - * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). - * @param outerName the internal name of the class to which the inner class - * belongs (see - * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). - * May be <tt>null</tt>. - * @param innerName the (simple) name of the inner class inside its - * enclosing class. May be <tt>null</tt> for anonymous inner - * classes. - * @param access the access flags of the inner class as originally declared - * in the enclosing class. + * @param name + * the internal name of an inner class (see + * {@link scala.tools.asm.Type#getInternalName() + * getInternalName}). + * @param outerName + * the internal name of the class to which the inner class + * belongs (see {@link scala.tools.asm.Type#getInternalName() + * getInternalName}). May be <tt>null</tt>. + * @param innerName + * the (simple) name of the inner class inside its enclosing + * class. May be <tt>null</tt> for anonymous inner classes. + * @param access + * the access flags of the inner class as originally declared in + * the enclosing class. */ - public InnerClassNode( - final String name, - final String outerName, - final String innerName, - final int access) - { + public InnerClassNode(final String name, final String outerName, + final String innerName, final int access) { this.name = name; this.outerName = outerName; this.innerName = innerName; @@ -93,7 +92,8 @@ public class InnerClassNode { /** * Makes the given class visitor visit this inner class. * - * @param cv a class visitor. + * @param cv + * a class visitor. */ public void accept(final ClassVisitor cv) { cv.visitInnerClass(name, outerName, innerName, access); diff --git a/src/asm/scala/tools/asm/tree/InsnList.java b/src/asm/scala/tools/asm/tree/InsnList.java index dedd3bba73..55d83c2e8b 100644 --- a/src/asm/scala/tools/asm/tree/InsnList.java +++ b/src/asm/scala/tools/asm/tree/InsnList.java @@ -73,8 +73,8 @@ public class InsnList { /** * Returns the first instruction in this list. * - * @return the first instruction in this list, or <tt>null</tt> if the - * list is empty. + * @return the first instruction in this list, or <tt>null</tt> if the list + * is empty. */ public AbstractInsnNode getFirst() { return first; @@ -96,9 +96,11 @@ public class InsnList { * time it is called. Once the cache is built, this method run in constant * time. This cache is invalidated by all the methods that modify the list. * - * @param index the index of the instruction that must be returned. + * @param index + * the index of the instruction that must be returned. * @return the instruction whose index is given. - * @throws IndexOutOfBoundsException if (index < 0 || index >= size()). + * @throws IndexOutOfBoundsException + * if (index < 0 || index >= size()). */ public AbstractInsnNode get(final int index) { if (index < 0 || index >= size) { @@ -111,11 +113,12 @@ public class InsnList { } /** - * Returns <tt>true</tt> if the given instruction belongs to this list. - * This method always scans the instructions of this list until it finds the + * Returns <tt>true</tt> if the given instruction belongs to this list. This + * method always scans the instructions of this list until it finds the * given instruction or reaches the end of the list. * - * @param insn an instruction. + * @param insn + * an instruction. * @return <tt>true</tt> if the given instruction belongs to this list. */ public boolean contains(final AbstractInsnNode insn) { @@ -133,7 +136,8 @@ public class InsnList { * constant time. The cache is invalidated by all the methods that modify * the list. * - * @param insn an instruction <i>of this list</i>. + * @param insn + * an instruction <i>of this list</i>. * @return the index of the given instruction in this list. <i>The result of * this method is undefined if the given instruction does not belong * to this list</i>. Use {@link #contains contains} to test if an @@ -149,7 +153,8 @@ public class InsnList { /** * Makes the given visitor visit all of the instructions in this list. * - * @param mv the method visitor that must visit the instructions. + * @param mv + * the method visitor that must visit the instructions. */ public void accept(final MethodVisitor mv) { AbstractInsnNode insn = first; @@ -198,9 +203,11 @@ public class InsnList { /** * Replaces an instruction of this list with another instruction. * - * @param location an instruction <i>of this list</i>. - * @param insn another instruction, <i>which must not belong to any - * {@link InsnList}</i>. + * @param location + * an instruction <i>of this list</i>. + * @param insn + * another instruction, <i>which must not belong to any + * {@link InsnList}</i>. */ public void set(final AbstractInsnNode location, final AbstractInsnNode insn) { AbstractInsnNode next = location.next; @@ -232,8 +239,9 @@ public class InsnList { /** * Adds the given instruction to the end of this list. * - * @param insn an instruction, <i>which must not belong to any - * {@link InsnList}</i>. + * @param insn + * an instruction, <i>which must not belong to any + * {@link InsnList}</i>. */ public void add(final AbstractInsnNode insn) { ++size; @@ -252,8 +260,9 @@ public class InsnList { /** * Adds the given instructions to the end of this list. * - * @param insns an instruction list, which is cleared during the process. - * This list must be different from 'this'. + * @param insns + * an instruction list, which is cleared during the process. This + * list must be different from 'this'. */ public void add(final InsnList insns) { if (insns.size == 0) { @@ -276,8 +285,9 @@ public class InsnList { /** * Inserts the given instruction at the begining of this list. * - * @param insn an instruction, <i>which must not belong to any - * {@link InsnList}</i>. + * @param insn + * an instruction, <i>which must not belong to any + * {@link InsnList}</i>. */ public void insert(final AbstractInsnNode insn) { ++size; @@ -296,8 +306,9 @@ public class InsnList { /** * Inserts the given instructions at the begining of this list. * - * @param insns an instruction list, which is cleared during the process. - * This list must be different from 'this'. + * @param insns + * an instruction list, which is cleared during the process. This + * list must be different from 'this'. */ public void insert(final InsnList insns) { if (insns.size == 0) { @@ -320,12 +331,15 @@ public class InsnList { /** * Inserts the given instruction after the specified instruction. * - * @param location an instruction <i>of this list</i> after which insn must be - * inserted. - * @param insn the instruction to be inserted, <i>which must not belong to - * any {@link InsnList}</i>. + * @param location + * an instruction <i>of this list</i> after which insn must be + * inserted. + * @param insn + * the instruction to be inserted, <i>which must not belong to + * any {@link InsnList}</i>. */ - public void insert(final AbstractInsnNode location, final AbstractInsnNode insn) { + public void insert(final AbstractInsnNode location, + final AbstractInsnNode insn) { ++size; AbstractInsnNode next = location.next; if (next == null) { @@ -343,10 +357,12 @@ public class InsnList { /** * Inserts the given instructions after the specified instruction. * - * @param location an instruction <i>of this list</i> after which the - * instructions must be inserted. - * @param insns the instruction list to be inserted, which is cleared during - * the process. This list must be different from 'this'. + * @param location + * an instruction <i>of this list</i> after which the + * instructions must be inserted. + * @param insns + * the instruction list to be inserted, which is cleared during + * the process. This list must be different from 'this'. */ public void insert(final AbstractInsnNode location, final InsnList insns) { if (insns.size == 0) { @@ -371,12 +387,15 @@ public class InsnList { /** * Inserts the given instruction before the specified instruction. * - * @param location an instruction <i>of this list</i> before which insn must be - * inserted. - * @param insn the instruction to be inserted, <i>which must not belong to - * any {@link InsnList}</i>. + * @param location + * an instruction <i>of this list</i> before which insn must be + * inserted. + * @param insn + * the instruction to be inserted, <i>which must not belong to + * any {@link InsnList}</i>. */ - public void insertBefore(final AbstractInsnNode location, final AbstractInsnNode insn) { + public void insertBefore(final AbstractInsnNode location, + final AbstractInsnNode insn) { ++size; AbstractInsnNode prev = location.prev; if (prev == null) { @@ -394,37 +413,39 @@ public class InsnList { /** * Inserts the given instructions before the specified instruction. * - * @param location an instruction <i>of this list</i> before which the instructions - * must be inserted. - * @param insns the instruction list to be inserted, which is cleared during - * the process. This list must be different from 'this'. + * @param location + * an instruction <i>of this list</i> before which the + * instructions must be inserted. + * @param insns + * the instruction list to be inserted, which is cleared during + * the process. This list must be different from 'this'. */ - public void insertBefore(final AbstractInsnNode location, final InsnList insns) { + public void insertBefore(final AbstractInsnNode location, + final InsnList insns) { if (insns.size == 0) { return; } size += insns.size; AbstractInsnNode ifirst = insns.first; AbstractInsnNode ilast = insns.last; - AbstractInsnNode prev = location .prev; + AbstractInsnNode prev = location.prev; if (prev == null) { first = ifirst; } else { prev.next = ifirst; } - location .prev = ilast; - ilast.next = location ; + location.prev = ilast; + ilast.next = location; ifirst.prev = prev; cache = null; insns.removeAll(false); } - - /** * Removes the given instruction from this list. * - * @param insn the instruction <i>of this list</i> that must be removed. + * @param insn + * the instruction <i>of this list</i> that must be removed. */ public void remove(final AbstractInsnNode insn) { --size; @@ -456,8 +477,9 @@ public class InsnList { /** * Removes all of the instructions of this list. * - * @param mark if the instructions must be marked as no longer belonging to - * any {@link InsnList}. + * @param mark + * if the instructions must be marked as no longer belonging to + * any {@link InsnList}. */ void removeAll(final boolean mark) { if (mark) { @@ -499,14 +521,14 @@ public class InsnList { } // this class is not generified because it will create bridges - private final class InsnListIterator implements ListIterator/*<AbstractInsnNode>*/ { + private final class InsnListIterator implements ListIterator { AbstractInsnNode next; AbstractInsnNode prev; InsnListIterator(int index) { - if(index==size()) { + if (index == size()) { next = null; prev = getLast(); } else { diff --git a/src/asm/scala/tools/asm/tree/InsnNode.java b/src/asm/scala/tools/asm/tree/InsnNode.java index d4664d23c2..4d5288cafa 100644 --- a/src/asm/scala/tools/asm/tree/InsnNode.java +++ b/src/asm/scala/tools/asm/tree/InsnNode.java @@ -43,20 +43,22 @@ public class InsnNode extends AbstractInsnNode { /** * Constructs a new {@link InsnNode}. * - * @param opcode the opcode of the instruction to be constructed. This - * opcode must be NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, - * ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, - * FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD, - * FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, - * FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, - * DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP, IADD, LADD, - * FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, - * LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, - * ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, - * LXOR, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, - * I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, - * FRETURN, DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, - * MONITORENTER, or MONITOREXIT. + * @param opcode + * the opcode of the instruction to be constructed. This opcode + * must be NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, + * ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, + * FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, + * LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, + * IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, + * SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, + * DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, + * IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM, + * FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, + * IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D, + * L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S, + * LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN, + * DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, + * or MONITOREXIT. */ public InsnNode(final int opcode) { super(opcode); @@ -70,7 +72,8 @@ public class InsnNode extends AbstractInsnNode { /** * Makes the given visitor visit this instruction. * - * @param mv a method visitor. + * @param mv + * a method visitor. */ @Override public void accept(final MethodVisitor mv) { diff --git a/src/asm/scala/tools/asm/tree/IntInsnNode.java b/src/asm/scala/tools/asm/tree/IntInsnNode.java index b61270c786..e0aeed4bc8 100644 --- a/src/asm/scala/tools/asm/tree/IntInsnNode.java +++ b/src/asm/scala/tools/asm/tree/IntInsnNode.java @@ -48,9 +48,11 @@ public class IntInsnNode extends AbstractInsnNode { /** * Constructs a new {@link IntInsnNode}. * - * @param opcode the opcode of the instruction to be constructed. This - * opcode must be BIPUSH, SIPUSH or NEWARRAY. - * @param operand the operand of the instruction to be constructed. + * @param opcode + * the opcode of the instruction to be constructed. This opcode + * must be BIPUSH, SIPUSH or NEWARRAY. + * @param operand + * the operand of the instruction to be constructed. */ public IntInsnNode(final int opcode, final int operand) { super(opcode); @@ -60,8 +62,9 @@ public class IntInsnNode extends AbstractInsnNode { /** * Sets the opcode of this instruction. * - * @param opcode the new instruction opcode. This opcode must be BIPUSH, - * SIPUSH or NEWARRAY. + * @param opcode + * the new instruction opcode. This opcode must be BIPUSH, SIPUSH + * or NEWARRAY. */ public void setOpcode(final int opcode) { this.opcode = opcode; diff --git a/src/asm/scala/tools/asm/tree/InvokeDynamicInsnNode.java b/src/asm/scala/tools/asm/tree/InvokeDynamicInsnNode.java index d993b5a054..7ee84b875b 100644 --- a/src/asm/scala/tools/asm/tree/InvokeDynamicInsnNode.java +++ b/src/asm/scala/tools/asm/tree/InvokeDynamicInsnNode.java @@ -65,17 +65,17 @@ public class InvokeDynamicInsnNode extends AbstractInsnNode { /** * Constructs a new {@link InvokeDynamicInsnNode}. * - * @param name invokedynamic name. - * @param desc invokedynamic descriptor (see {@link org.objectweb.asm.Type}). - * @param bsm the bootstrap method. - * @param bsmArgs the boostrap constant arguments. + * @param name + * invokedynamic name. + * @param desc + * invokedynamic descriptor (see {@link scala.tools.asm.Type}). + * @param bsm + * the bootstrap method. + * @param bsmArgs + * the boostrap constant arguments. */ - public InvokeDynamicInsnNode( - final String name, - final String desc, - final Handle bsm, - final Object... bsmArgs) - { + public InvokeDynamicInsnNode(final String name, final String desc, + final Handle bsm, final Object... bsmArgs) { super(Opcodes.INVOKEDYNAMIC); this.name = name; this.desc = desc; @@ -97,4 +97,4 @@ public class InvokeDynamicInsnNode extends AbstractInsnNode { public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) { return new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs); } -}
\ No newline at end of file +} diff --git a/src/asm/scala/tools/asm/tree/JumpInsnNode.java b/src/asm/scala/tools/asm/tree/JumpInsnNode.java index 339ebbd2d0..81e1e09deb 100644 --- a/src/asm/scala/tools/asm/tree/JumpInsnNode.java +++ b/src/asm/scala/tools/asm/tree/JumpInsnNode.java @@ -50,13 +50,15 @@ public class JumpInsnNode extends AbstractInsnNode { /** * Constructs a new {@link JumpInsnNode}. * - * @param opcode the opcode of the type instruction to be constructed. This - * opcode must be IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, - * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, - * IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL. - * @param label the operand of the instruction to be constructed. This - * operand is a label that designates the instruction to which the - * jump instruction may jump. + * @param opcode + * the opcode of the type instruction to be constructed. This + * opcode must be IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, + * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, + * IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL. + * @param label + * the operand of the instruction to be constructed. This operand + * is a label that designates the instruction to which the jump + * instruction may jump. */ public JumpInsnNode(final int opcode, final LabelNode label) { super(opcode); @@ -66,10 +68,11 @@ public class JumpInsnNode extends AbstractInsnNode { /** * Sets the opcode of this instruction. * - * @param opcode the new instruction opcode. This opcode must be IFEQ, IFNE, - * IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, - * IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, - * IFNULL or IFNONNULL. + * @param opcode + * the new instruction opcode. This opcode must be IFEQ, IFNE, + * IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, + * IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, + * JSR, IFNULL or IFNONNULL. */ public void setOpcode(final int opcode) { this.opcode = opcode; diff --git a/src/asm/scala/tools/asm/tree/LabelNode.java b/src/asm/scala/tools/asm/tree/LabelNode.java index 523a8d6442..44c48c1160 100644 --- a/src/asm/scala/tools/asm/tree/LabelNode.java +++ b/src/asm/scala/tools/asm/tree/LabelNode.java @@ -75,4 +75,4 @@ public class LabelNode extends AbstractInsnNode { public void resetLabel() { label = null; } -}
\ No newline at end of file +} diff --git a/src/asm/scala/tools/asm/tree/LdcInsnNode.java b/src/asm/scala/tools/asm/tree/LdcInsnNode.java index f8d115acd5..4e328f9b39 100644 --- a/src/asm/scala/tools/asm/tree/LdcInsnNode.java +++ b/src/asm/scala/tools/asm/tree/LdcInsnNode.java @@ -44,16 +44,17 @@ public class LdcInsnNode extends AbstractInsnNode { /** * The constant to be loaded on the stack. This parameter must be a non null * {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a - * {@link String} or a {@link org.objectweb.asm.Type}. + * {@link String} or a {@link scala.tools.asm.Type}. */ public Object cst; /** * Constructs a new {@link LdcInsnNode}. * - * @param cst the constant to be loaded on the stack. This parameter must be - * a non null {@link Integer}, a {@link Float}, a {@link Long}, a - * {@link Double} or a {@link String}. + * @param cst + * the constant to be loaded on the stack. This parameter must be + * a non null {@link Integer}, a {@link Float}, a {@link Long}, a + * {@link Double} or a {@link String}. */ public LdcInsnNode(final Object cst) { super(Opcodes.LDC); @@ -74,4 +75,4 @@ public class LdcInsnNode extends AbstractInsnNode { public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) { return new LdcInsnNode(cst); } -}
\ No newline at end of file +} diff --git a/src/asm/scala/tools/asm/tree/LineNumberNode.java b/src/asm/scala/tools/asm/tree/LineNumberNode.java index acc83c8d30..9947aa70a9 100644 --- a/src/asm/scala/tools/asm/tree/LineNumberNode.java +++ b/src/asm/scala/tools/asm/tree/LineNumberNode.java @@ -55,9 +55,11 @@ public class LineNumberNode extends AbstractInsnNode { /** * Constructs a new {@link LineNumberNode}. * - * @param line a line number. This number refers to the source file from - * which the class was compiled. - * @param start the first instruction corresponding to this line number. + * @param line + * a line number. This number refers to the source file from + * which the class was compiled. + * @param start + * the first instruction corresponding to this line number. */ public LineNumberNode(final int line, final LabelNode start) { super(-1); diff --git a/src/asm/scala/tools/asm/tree/LocalVariableNode.java b/src/asm/scala/tools/asm/tree/LocalVariableNode.java index 51cbd3ca00..0d8e27356f 100644 --- a/src/asm/scala/tools/asm/tree/LocalVariableNode.java +++ b/src/asm/scala/tools/asm/tree/LocalVariableNode.java @@ -73,24 +73,24 @@ public class LocalVariableNode { /** * Constructs a new {@link LocalVariableNode}. * - * @param name the name of a local variable. - * @param desc the type descriptor of this local variable. - * @param signature the signature of this local variable. May be - * <tt>null</tt>. - * @param start the first instruction corresponding to the scope of this - * local variable (inclusive). - * @param end the last instruction corresponding to the scope of this local - * variable (exclusive). - * @param index the local variable's index. + * @param name + * the name of a local variable. + * @param desc + * the type descriptor of this local variable. + * @param signature + * the signature of this local variable. May be <tt>null</tt>. + * @param start + * the first instruction corresponding to the scope of this local + * variable (inclusive). + * @param end + * the last instruction corresponding to the scope of this local + * variable (exclusive). + * @param index + * the local variable's index. */ - public LocalVariableNode( - final String name, - final String desc, - final String signature, - final LabelNode start, - final LabelNode end, - final int index) - { + public LocalVariableNode(final String name, final String desc, + final String signature, final LabelNode start, final LabelNode end, + final int index) { this.name = name; this.desc = desc; this.signature = signature; @@ -102,14 +102,11 @@ public class LocalVariableNode { /** * Makes the given visitor visit this local variable declaration. * - * @param mv a method visitor. + * @param mv + * a method visitor. */ public void accept(final MethodVisitor mv) { - mv.visitLocalVariable(name, - desc, - signature, - start.getLabel(), - end.getLabel(), - index); + mv.visitLocalVariable(name, desc, signature, start.getLabel(), + end.getLabel(), index); } } diff --git a/src/asm/scala/tools/asm/tree/LookupSwitchInsnNode.java b/src/asm/scala/tools/asm/tree/LookupSwitchInsnNode.java index 6d0f971c29..d2479b4814 100644 --- a/src/asm/scala/tools/asm/tree/LookupSwitchInsnNode.java +++ b/src/asm/scala/tools/asm/tree/LookupSwitchInsnNode.java @@ -64,20 +64,21 @@ public class LookupSwitchInsnNode extends AbstractInsnNode { /** * Constructs a new {@link LookupSwitchInsnNode}. * - * @param dflt beginning of the default handler block. - * @param keys the values of the keys. - * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is - * the beginning of the handler block for the <tt>keys[i]</tt> key. + * @param dflt + * beginning of the default handler block. + * @param keys + * the values of the keys. + * @param labels + * beginnings of the handler blocks. <tt>labels[i]</tt> is the + * beginning of the handler block for the <tt>keys[i]</tt> key. */ - public LookupSwitchInsnNode( - final LabelNode dflt, - final int[] keys, - final LabelNode[] labels) - { + public LookupSwitchInsnNode(final LabelNode dflt, final int[] keys, + final LabelNode[] labels) { super(Opcodes.LOOKUPSWITCH); this.dflt = dflt; this.keys = new ArrayList<Integer>(keys == null ? 0 : keys.length); - this.labels = new ArrayList<LabelNode>(labels == null ? 0 : labels.length); + this.labels = new ArrayList<LabelNode>(labels == null ? 0 + : labels.length); if (keys != null) { for (int i = 0; i < keys.length; ++i) { this.keys.add(new Integer(keys[i])); diff --git a/src/asm/scala/tools/asm/tree/MethodInsnNode.java b/src/asm/scala/tools/asm/tree/MethodInsnNode.java index c3036bc6b4..bf09f556d8 100644 --- a/src/asm/scala/tools/asm/tree/MethodInsnNode.java +++ b/src/asm/scala/tools/asm/tree/MethodInsnNode.java @@ -43,7 +43,7 @@ public class MethodInsnNode extends AbstractInsnNode { /** * The internal name of the method's owner class (see - * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). + * {@link scala.tools.asm.Type#getInternalName() getInternalName}). */ public String owner; @@ -53,27 +53,28 @@ public class MethodInsnNode extends AbstractInsnNode { public String name; /** - * The method's descriptor (see {@link org.objectweb.asm.Type}). + * The method's descriptor (see {@link scala.tools.asm.Type}). */ public String desc; /** * Constructs a new {@link MethodInsnNode}. * - * @param opcode the opcode of the type instruction to be constructed. This - * opcode must be INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or - * INVOKEINTERFACE. - * @param owner the internal name of the method's owner class (see - * {@link org.objectweb.asm.Type#getInternalName() getInternalName}). - * @param name the method's name. - * @param desc the method's descriptor (see {@link org.objectweb.asm.Type}). + * @param opcode + * the opcode of the type instruction to be constructed. This + * opcode must be INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or + * INVOKEINTERFACE. + * @param owner + * the internal name of the method's owner class (see + * {@link scala.tools.asm.Type#getInternalName() + * getInternalName}). + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link scala.tools.asm.Type}). */ - public MethodInsnNode( - final int opcode, - final String owner, - final String name, - final String desc) - { + public MethodInsnNode(final int opcode, final String owner, + final String name, final String desc) { super(opcode); this.owner = owner; this.name = name; @@ -83,8 +84,9 @@ public class MethodInsnNode extends AbstractInsnNode { /** * Sets the opcode of this instruction. * - * @param opcode the new instruction opcode. This opcode must be - * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE. + * @param opcode + * the new instruction opcode. This opcode must be INVOKEVIRTUAL, + * INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE. */ public void setOpcode(final int opcode) { this.opcode = opcode; @@ -104,4 +106,4 @@ public class MethodInsnNode extends AbstractInsnNode { public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) { return new MethodInsnNode(opcode, owner, name, desc); } -}
\ No newline at end of file +} diff --git a/src/asm/scala/tools/asm/tree/MethodNode.java b/src/asm/scala/tools/asm/tree/MethodNode.java index 70ec39e058..5f9c778e0c 100644 --- a/src/asm/scala/tools/asm/tree/MethodNode.java +++ b/src/asm/scala/tools/asm/tree/MethodNode.java @@ -81,7 +81,7 @@ public class MethodNode extends MethodVisitor { * The runtime visible annotations of this method. This list is a list of * {@link AnnotationNode} objects. May be <tt>null</tt>. * - * @associates org.objectweb.asm.tree.AnnotationNode + * @associates scala.tools.asm.tree.AnnotationNode * @label visible */ public List<AnnotationNode> visibleAnnotations; @@ -90,7 +90,7 @@ public class MethodNode extends MethodVisitor { * The runtime invisible annotations of this method. This list is a list of * {@link AnnotationNode} objects. May be <tt>null</tt>. * - * @associates org.objectweb.asm.tree.AnnotationNode + * @associates scala.tools.asm.tree.AnnotationNode * @label invisible */ public List<AnnotationNode> invisibleAnnotations; @@ -99,7 +99,7 @@ public class MethodNode extends MethodVisitor { * The non standard attributes of this method. This list is a list of * {@link Attribute} objects. May be <tt>null</tt>. * - * @associates org.objectweb.asm.Attribute + * @associates scala.tools.asm.Attribute */ public List<Attribute> attrs; @@ -117,7 +117,7 @@ public class MethodNode extends MethodVisitor { * The runtime visible parameter annotations of this method. These lists are * lists of {@link AnnotationNode} objects. May be <tt>null</tt>. * - * @associates org.objectweb.asm.tree.AnnotationNode + * @associates scala.tools.asm.tree.AnnotationNode * @label invisible parameters */ public List<AnnotationNode>[] visibleParameterAnnotations; @@ -126,7 +126,7 @@ public class MethodNode extends MethodVisitor { * The runtime invisible parameter annotations of this method. These lists * are lists of {@link AnnotationNode} objects. May be <tt>null</tt>. * - * @associates org.objectweb.asm.tree.AnnotationNode + * @associates scala.tools.asm.tree.AnnotationNode * @label visible parameters */ public List<AnnotationNode>[] invisibleParameterAnnotations; @@ -135,7 +135,7 @@ public class MethodNode extends MethodVisitor { * The instructions of this method. This list is a list of * {@link AbstractInsnNode} objects. * - * @associates org.objectweb.asm.tree.AbstractInsnNode + * @associates scala.tools.asm.tree.AbstractInsnNode * @label instructions */ public InsnList instructions; @@ -144,7 +144,7 @@ public class MethodNode extends MethodVisitor { * The try catch blocks of this method. This list is a list of * {@link TryCatchBlockNode} objects. * - * @associates org.objectweb.asm.tree.TryCatchBlockNode + * @associates scala.tools.asm.tree.TryCatchBlockNode */ public List<TryCatchBlockNode> tryCatchBlocks; @@ -162,7 +162,7 @@ public class MethodNode extends MethodVisitor { * The local variables of this method. This list is a list of * {@link LocalVariableNode} objects. May be <tt>null</tt> * - * @associates org.objectweb.asm.tree.LocalVariableNode + * @associates scala.tools.asm.tree.LocalVariableNode */ public List<LocalVariableNode> localVariables; @@ -170,7 +170,7 @@ public class MethodNode extends MethodVisitor { * If the accept method has been called on this object. */ private boolean visited; - + /** * Constructs an uninitialized {@link MethodNode}. <i>Subclasses must not * use this constructor</i>. Instead, they must use the @@ -183,8 +183,9 @@ public class MethodNode extends MethodVisitor { /** * Constructs an uninitialized {@link MethodNode}. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. */ public MethodNode(final int api) { super(api); @@ -196,56 +197,55 @@ public class MethodNode extends MethodVisitor { * constructor</i>. Instead, they must use the * {@link #MethodNode(int, int, String, String, String, String[])} version. * - * @param access the method's access flags (see {@link Opcodes}). This - * parameter also indicates if the method is synthetic and/or - * deprecated. - * @param name the method's name. - * @param desc the method's descriptor (see {@link Type}). - * @param signature the method's signature. May be <tt>null</tt>. - * @param exceptions the internal names of the method's exception classes - * (see {@link Type#getInternalName() getInternalName}). May be - * <tt>null</tt>. + * @param access + * the method's access flags (see {@link Opcodes}). This + * parameter also indicates if the method is synthetic and/or + * deprecated. + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link Type}). + * @param signature + * the method's signature. May be <tt>null</tt>. + * @param exceptions + * the internal names of the method's exception classes (see + * {@link Type#getInternalName() getInternalName}). May be + * <tt>null</tt>. */ - public MethodNode( - final int access, - final String name, - final String desc, - final String signature, - final String[] exceptions) - { + public MethodNode(final int access, final String name, final String desc, + final String signature, final String[] exceptions) { this(Opcodes.ASM4, access, name, desc, signature, exceptions); } /** * Constructs a new {@link MethodNode}. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. - * @param access the method's access flags (see {@link Opcodes}). This - * parameter also indicates if the method is synthetic and/or - * deprecated. - * @param name the method's name. - * @param desc the method's descriptor (see {@link Type}). - * @param signature the method's signature. May be <tt>null</tt>. - * @param exceptions the internal names of the method's exception classes - * (see {@link Type#getInternalName() getInternalName}). May be - * <tt>null</tt>. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param access + * the method's access flags (see {@link Opcodes}). This + * parameter also indicates if the method is synthetic and/or + * deprecated. + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link Type}). + * @param signature + * the method's signature. May be <tt>null</tt>. + * @param exceptions + * the internal names of the method's exception classes (see + * {@link Type#getInternalName() getInternalName}). May be + * <tt>null</tt>. */ - public MethodNode( - final int api, - final int access, - final String name, - final String desc, - final String signature, - final String[] exceptions) - { + public MethodNode(final int api, final int access, final String name, + final String desc, final String signature, final String[] exceptions) { super(api); this.access = access; this.name = name; this.desc = desc; this.signature = signature; - this.exceptions = new ArrayList<String>(exceptions == null - ? 0 + this.exceptions = new ArrayList<String>(exceptions == null ? 0 : exceptions.length); boolean isAbstract = (access & Opcodes.ACC_ABSTRACT) != 0; if (!isAbstract) { @@ -274,10 +274,8 @@ public class MethodNode extends MethodVisitor { } @Override - public AnnotationVisitor visitAnnotation( - final String desc, - final boolean visible) - { + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { AnnotationNode an = new AnnotationNode(desc); if (visible) { if (visibleAnnotations == null) { @@ -294,28 +292,27 @@ public class MethodNode extends MethodVisitor { } @Override - public AnnotationVisitor visitParameterAnnotation( - final int parameter, - final String desc, - final boolean visible) - { + public AnnotationVisitor visitParameterAnnotation(final int parameter, + final String desc, final boolean visible) { AnnotationNode an = new AnnotationNode(desc); if (visible) { if (visibleParameterAnnotations == null) { int params = Type.getArgumentTypes(this.desc).length; - visibleParameterAnnotations = (List<AnnotationNode>[])new List<?>[params]; + visibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params]; } if (visibleParameterAnnotations[parameter] == null) { - visibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(1); + visibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>( + 1); } visibleParameterAnnotations[parameter].add(an); } else { if (invisibleParameterAnnotations == null) { int params = Type.getArgumentTypes(this.desc).length; - invisibleParameterAnnotations = (List<AnnotationNode>[])new List<?>[params]; + invisibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params]; } if (invisibleParameterAnnotations[parameter] == null) { - invisibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(1); + invisibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>( + 1); } invisibleParameterAnnotations[parameter].add(an); } @@ -335,17 +332,10 @@ public class MethodNode extends MethodVisitor { } @Override - public void visitFrame( - final int type, - final int nLocal, - final Object[] local, - final int nStack, - final Object[] stack) - { - instructions.add(new FrameNode(type, nLocal, local == null - ? null - : getLabelNodes(local), nStack, stack == null - ? null + public void visitFrame(final int type, final int nLocal, + final Object[] local, final int nStack, final Object[] stack) { + instructions.add(new FrameNode(type, nLocal, local == null ? null + : getLabelNodes(local), nStack, stack == null ? null : getLabelNodes(stack))); } @@ -370,32 +360,20 @@ public class MethodNode extends MethodVisitor { } @Override - public void visitFieldInsn( - final int opcode, - final String owner, - final String name, - final String desc) - { + public void visitFieldInsn(final int opcode, final String owner, + final String name, final String desc) { instructions.add(new FieldInsnNode(opcode, owner, name, desc)); } @Override - public void visitMethodInsn( - final int opcode, - final String owner, - final String name, - final String desc) - { + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { instructions.add(new MethodInsnNode(opcode, owner, name, desc)); } @Override - public void visitInvokeDynamicInsn( - String name, - String desc, - Handle bsm, - Object... bsmArgs) - { + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, + Object... bsmArgs) { instructions.add(new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs)); } @@ -420,26 +398,16 @@ public class MethodNode extends MethodVisitor { } @Override - public void visitTableSwitchInsn( - final int min, - final int max, - final Label dflt, - final Label... labels) - { - instructions.add(new TableSwitchInsnNode(min, - max, - getLabelNode(dflt), + public void visitTableSwitchInsn(final int min, final int max, + final Label dflt, final Label... labels) { + instructions.add(new TableSwitchInsnNode(min, max, getLabelNode(dflt), getLabelNodes(labels))); } @Override - public void visitLookupSwitchInsn( - final Label dflt, - final int[] keys, - final Label[] labels) - { - instructions.add(new LookupSwitchInsnNode(getLabelNode(dflt), - keys, + public void visitLookupSwitchInsn(final Label dflt, final int[] keys, + final Label[] labels) { + instructions.add(new LookupSwitchInsnNode(getLabelNode(dflt), keys, getLabelNodes(labels))); } @@ -449,33 +417,18 @@ public class MethodNode extends MethodVisitor { } @Override - public void visitTryCatchBlock( - final Label start, - final Label end, - final Label handler, - final String type) - { + public void visitTryCatchBlock(final Label start, final Label end, + final Label handler, final String type) { tryCatchBlocks.add(new TryCatchBlockNode(getLabelNode(start), - getLabelNode(end), - getLabelNode(handler), - type)); + getLabelNode(end), getLabelNode(handler), type)); } @Override - public void visitLocalVariable( - final String name, - final String desc, - final String signature, - final Label start, - final Label end, - final int index) - { - localVariables.add(new LocalVariableNode(name, - desc, - signature, - getLabelNode(start), - getLabelNode(end), - index)); + public void visitLocalVariable(final String name, final String desc, + final String signature, final Label start, final Label end, + final int index) { + localVariables.add(new LocalVariableNode(name, desc, signature, + getLabelNode(start), getLabelNode(end), index)); } @Override @@ -499,12 +452,13 @@ public class MethodNode extends MethodVisitor { * the {@link Label#info} field to store associations between labels and * label nodes. * - * @param l a Label. + * @param l + * a Label. * @return the LabelNode corresponding to l. */ protected LabelNode getLabelNode(final Label l) { if (!(l.info instanceof LabelNode)) { - l.info = new LabelNode(l); + l.info = new LabelNode(); } return (LabelNode) l.info; } @@ -539,7 +493,8 @@ public class MethodNode extends MethodVisitor { * recursively, do not contain elements that were introduced in more recent * versions of the ASM API than the given version. * - * @param api an ASM API version. Must be one of {@link Opcodes#ASM4}. + * @param api + * an ASM API version. Must be one of {@link Opcodes#ASM4}. */ public void check(final int api) { // nothing to do @@ -548,15 +503,13 @@ public class MethodNode extends MethodVisitor { /** * Makes the given class visitor visit this method. * - * @param cv a class visitor. + * @param cv + * a class visitor. */ public void accept(final ClassVisitor cv) { String[] exceptions = new String[this.exceptions.size()]; this.exceptions.toArray(exceptions); - MethodVisitor mv = cv.visitMethod(access, - name, - desc, - signature, + MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); if (mv != null) { accept(mv); @@ -566,7 +519,8 @@ public class MethodNode extends MethodVisitor { /** * Makes the given method visitor visit this method. * - * @param mv a method visitor. + * @param mv + * a method visitor. */ public void accept(final MethodVisitor mv) { // visits the method attributes @@ -588,8 +542,7 @@ public class MethodNode extends MethodVisitor { AnnotationNode an = invisibleAnnotations.get(i); an.accept(mv.visitAnnotation(an.desc, false)); } - n = visibleParameterAnnotations == null - ? 0 + n = visibleParameterAnnotations == null ? 0 : visibleParameterAnnotations.length; for (i = 0; i < n; ++i) { List<?> l = visibleParameterAnnotations[i]; @@ -601,8 +554,7 @@ public class MethodNode extends MethodVisitor { an.accept(mv.visitParameterAnnotation(i, an.desc, true)); } } - n = invisibleParameterAnnotations == null - ? 0 + n = invisibleParameterAnnotations == null ? 0 : invisibleParameterAnnotations.length; for (i = 0; i < n; ++i) { List<?> l = invisibleParameterAnnotations[i]; diff --git a/src/asm/scala/tools/asm/tree/MultiANewArrayInsnNode.java b/src/asm/scala/tools/asm/tree/MultiANewArrayInsnNode.java index 9dfba77335..fe5e8832b3 100644 --- a/src/asm/scala/tools/asm/tree/MultiANewArrayInsnNode.java +++ b/src/asm/scala/tools/asm/tree/MultiANewArrayInsnNode.java @@ -42,7 +42,7 @@ import scala.tools.asm.Opcodes; public class MultiANewArrayInsnNode extends AbstractInsnNode { /** - * An array type descriptor (see {@link org.objectweb.asm.Type}). + * An array type descriptor (see {@link scala.tools.asm.Type}). */ public String desc; @@ -54,8 +54,10 @@ public class MultiANewArrayInsnNode extends AbstractInsnNode { /** * Constructs a new {@link MultiANewArrayInsnNode}. * - * @param desc an array type descriptor (see {@link org.objectweb.asm.Type}). - * @param dims number of dimensions of the array to allocate. + * @param desc + * an array type descriptor (see {@link scala.tools.asm.Type}). + * @param dims + * number of dimensions of the array to allocate. */ public MultiANewArrayInsnNode(final String desc, final int dims) { super(Opcodes.MULTIANEWARRAY); @@ -78,4 +80,4 @@ public class MultiANewArrayInsnNode extends AbstractInsnNode { return new MultiANewArrayInsnNode(desc, dims); } -}
\ No newline at end of file +} diff --git a/src/asm/scala/tools/asm/tree/TableSwitchInsnNode.java b/src/asm/scala/tools/asm/tree/TableSwitchInsnNode.java index 929ad9b32b..9b3c2a3437 100644 --- a/src/asm/scala/tools/asm/tree/TableSwitchInsnNode.java +++ b/src/asm/scala/tools/asm/tree/TableSwitchInsnNode.java @@ -69,18 +69,18 @@ public class TableSwitchInsnNode extends AbstractInsnNode { /** * Constructs a new {@link TableSwitchInsnNode}. * - * @param min the minimum key value. - * @param max the maximum key value. - * @param dflt beginning of the default handler block. - * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is - * the beginning of the handler block for the <tt>min + i</tt> key. + * @param min + * the minimum key value. + * @param max + * the maximum key value. + * @param dflt + * beginning of the default handler block. + * @param labels + * beginnings of the handler blocks. <tt>labels[i]</tt> is the + * beginning of the handler block for the <tt>min + i</tt> key. */ - public TableSwitchInsnNode( - final int min, - final int max, - final LabelNode dflt, - final LabelNode... labels) - { + public TableSwitchInsnNode(final int min, final int max, + final LabelNode dflt, final LabelNode... labels) { super(Opcodes.TABLESWITCH); this.min = min; this.max = max; @@ -107,9 +107,7 @@ public class TableSwitchInsnNode extends AbstractInsnNode { @Override public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) { - return new TableSwitchInsnNode(min, - max, - clone(dflt, labels), - clone(this.labels, labels)); + return new TableSwitchInsnNode(min, max, clone(dflt, labels), clone( + this.labels, labels)); } -}
\ No newline at end of file +} diff --git a/src/asm/scala/tools/asm/tree/TryCatchBlockNode.java b/src/asm/scala/tools/asm/tree/TryCatchBlockNode.java index 375b4cfcb9..ab4fa97c34 100644 --- a/src/asm/scala/tools/asm/tree/TryCatchBlockNode.java +++ b/src/asm/scala/tools/asm/tree/TryCatchBlockNode.java @@ -62,19 +62,19 @@ public class TryCatchBlockNode { /** * Constructs a new {@link TryCatchBlockNode}. * - * @param start beginning of the exception handler's scope (inclusive). - * @param end end of the exception handler's scope (exclusive). - * @param handler beginning of the exception handler's code. - * @param type internal name of the type of exceptions handled by the - * handler, or <tt>null</tt> to catch any exceptions (for "finally" - * blocks). + * @param start + * beginning of the exception handler's scope (inclusive). + * @param end + * end of the exception handler's scope (exclusive). + * @param handler + * beginning of the exception handler's code. + * @param type + * internal name of the type of exceptions handled by the + * handler, or <tt>null</tt> to catch any exceptions (for + * "finally" blocks). */ - public TryCatchBlockNode( - final LabelNode start, - final LabelNode end, - final LabelNode handler, - final String type) - { + public TryCatchBlockNode(final LabelNode start, final LabelNode end, + final LabelNode handler, final String type) { this.start = start; this.end = end; this.handler = handler; @@ -84,11 +84,11 @@ public class TryCatchBlockNode { /** * Makes the given visitor visit this try catch block. * - * @param mv a method visitor. + * @param mv + * a method visitor. */ public void accept(final MethodVisitor mv) { - mv.visitTryCatchBlock(start.getLabel(), end.getLabel(), handler == null - ? null - : handler.getLabel(), type); + mv.visitTryCatchBlock(start.getLabel(), end.getLabel(), + handler == null ? null : handler.getLabel(), type); } } diff --git a/src/asm/scala/tools/asm/tree/TypeInsnNode.java b/src/asm/scala/tools/asm/tree/TypeInsnNode.java index 0b2666c498..3210dd60e6 100644 --- a/src/asm/scala/tools/asm/tree/TypeInsnNode.java +++ b/src/asm/scala/tools/asm/tree/TypeInsnNode.java @@ -43,17 +43,19 @@ public class TypeInsnNode extends AbstractInsnNode { /** * The operand of this instruction. This operand is an internal name (see - * {@link org.objectweb.asm.Type}). + * {@link scala.tools.asm.Type}). */ public String desc; /** * Constructs a new {@link TypeInsnNode}. * - * @param opcode the opcode of the type instruction to be constructed. This - * opcode must be NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. - * @param desc the operand of the instruction to be constructed. This - * operand is an internal name (see {@link org.objectweb.asm.Type}). + * @param opcode + * the opcode of the type instruction to be constructed. This + * opcode must be NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. + * @param desc + * the operand of the instruction to be constructed. This operand + * is an internal name (see {@link scala.tools.asm.Type}). */ public TypeInsnNode(final int opcode, final String desc) { super(opcode); @@ -63,8 +65,9 @@ public class TypeInsnNode extends AbstractInsnNode { /** * Sets the opcode of this instruction. * - * @param opcode the new instruction opcode. This opcode must be NEW, - * ANEWARRAY, CHECKCAST or INSTANCEOF. + * @param opcode + * the new instruction opcode. This opcode must be NEW, + * ANEWARRAY, CHECKCAST or INSTANCEOF. */ public void setOpcode(final int opcode) { this.opcode = opcode; @@ -84,4 +87,4 @@ public class TypeInsnNode extends AbstractInsnNode { public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) { return new TypeInsnNode(opcode, desc); } -}
\ No newline at end of file +} diff --git a/src/asm/scala/tools/asm/tree/VarInsnNode.java b/src/asm/scala/tools/asm/tree/VarInsnNode.java index 89f572db59..5dd9ef6726 100644 --- a/src/asm/scala/tools/asm/tree/VarInsnNode.java +++ b/src/asm/scala/tools/asm/tree/VarInsnNode.java @@ -51,11 +51,13 @@ public class VarInsnNode extends AbstractInsnNode { /** * Constructs a new {@link VarInsnNode}. * - * @param opcode the opcode of the local variable instruction to be - * constructed. This opcode must be ILOAD, LLOAD, FLOAD, DLOAD, - * ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET. - * @param var the operand of the instruction to be constructed. This operand - * is the index of a local variable. + * @param opcode + * the opcode of the local variable instruction to be + * constructed. This opcode must be ILOAD, LLOAD, FLOAD, DLOAD, + * ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET. + * @param var + * the operand of the instruction to be constructed. This operand + * is the index of a local variable. */ public VarInsnNode(final int opcode, final int var) { super(opcode); @@ -65,9 +67,10 @@ public class VarInsnNode extends AbstractInsnNode { /** * Sets the opcode of this instruction. * - * @param opcode the new instruction opcode. This opcode must be ILOAD, - * LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE - * or RET. + * @param opcode + * the new instruction opcode. This opcode must be ILOAD, LLOAD, + * FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or + * RET. */ public void setOpcode(final int opcode) { this.opcode = opcode; @@ -87,4 +90,4 @@ public class VarInsnNode extends AbstractInsnNode { public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) { return new VarInsnNode(opcode, var); } -}
\ No newline at end of file +} diff --git a/src/asm/scala/tools/asm/tree/analysis/Analyzer.java b/src/asm/scala/tools/asm/tree/analysis/Analyzer.java index df387b0b8e..0134555f10 100644 --- a/src/asm/scala/tools/asm/tree/analysis/Analyzer.java +++ b/src/asm/scala/tools/asm/tree/analysis/Analyzer.java @@ -51,9 +51,10 @@ import scala.tools.asm.tree.VarInsnNode; * A semantic bytecode analyzer. <i>This class does not fully check that JSR and * RET instructions are valid.</i> * - * @param <V> type of the Value used for the analysis. + * @param <V> + * type of the Value used for the analysis. * - * @author Eric Bruneton + * @author Eric Bruneton */ public class Analyzer<V extends Value> implements Opcodes { @@ -78,8 +79,9 @@ public class Analyzer<V extends Value> implements Opcodes { /** * Constructs a new {@link Analyzer}. * - * @param interpreter the interpreter to be used to symbolically interpret - * the bytecode instructions. + * @param interpreter + * the interpreter to be used to symbolically interpret the + * bytecode instructions. */ public Analyzer(final Interpreter<V> interpreter) { this.interpreter = interpreter; @@ -88,26 +90,28 @@ public class Analyzer<V extends Value> implements Opcodes { /** * Analyzes the given method. * - * @param owner the internal name of the class to which the method belongs. - * @param m the method to be analyzed. + * @param owner + * the internal name of the class to which the method belongs. + * @param m + * the method to be analyzed. * @return the symbolic state of the execution stack frame at each bytecode * instruction of the method. The size of the returned array is * equal to the number of instructions (and labels) of the method. A * given frame is <tt>null</tt> if and only if the corresponding * instruction cannot be reached (dead code). - * @throws AnalyzerException if a problem occurs during the analysis. + * @throws AnalyzerException + * if a problem occurs during the analysis. */ public Frame<V>[] analyze(final String owner, final MethodNode m) - throws AnalyzerException - { + throws AnalyzerException { if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) { - frames = (Frame<V>[])new Frame<?>[0]; + frames = (Frame<V>[]) new Frame<?>[0]; return frames; } n = m.instructions.size(); insns = m.instructions; - handlers = (List<TryCatchBlockNode>[])new List<?>[n]; - frames = (Frame<V>[])new Frame<?>[n]; + handlers = (List<TryCatchBlockNode>[]) new List<?>[n]; + frames = (Frame<V>[]) new Frame<?>[n]; subroutines = new Subroutine[n]; queued = new boolean[n]; queue = new int[n]; @@ -188,8 +192,7 @@ public class Analyzer<V extends Value> implements Opcodes { if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE - || insnType == AbstractInsnNode.FRAME) - { + || insnType == AbstractInsnNode.FRAME) { merge(insn + 1, f, subroutine); newControlFlowEdge(insn, insn + 1); } else { @@ -205,8 +208,7 @@ public class Analyzer<V extends Value> implements Opcodes { int jump = insns.indexOf(j.label); if (insnOpcode == JSR) { merge(jump, current, new Subroutine(j.label, - m.maxLocals, - j)); + m.maxLocals, j)); } else { merge(jump, current, subroutine); } @@ -235,31 +237,27 @@ public class Analyzer<V extends Value> implements Opcodes { } } else if (insnOpcode == RET) { if (subroutine == null) { - throw new AnalyzerException(insnNode, "RET instruction outside of a sub routine"); + throw new AnalyzerException(insnNode, + "RET instruction outside of a sub routine"); } for (int i = 0; i < subroutine.callers.size(); ++i) { JumpInsnNode caller = subroutine.callers.get(i); int call = insns.indexOf(caller); if (frames[call] != null) { - merge(call + 1, - frames[call], - current, - subroutines[call], - subroutine.access); + merge(call + 1, frames[call], current, + subroutines[call], subroutine.access); newControlFlowEdge(insn, call + 1); } } } else if (insnOpcode != ATHROW - && (insnOpcode < IRETURN || insnOpcode > RETURN)) - { + && (insnOpcode < IRETURN || insnOpcode > RETURN)) { if (subroutine != null) { if (insnNode instanceof VarInsnNode) { int var = ((VarInsnNode) insnNode).var; subroutine.access[var] = true; if (insnOpcode == LLOAD || insnOpcode == DLOAD || insnOpcode == LSTORE - || insnOpcode == DSTORE) - { + || insnOpcode == DSTORE) { subroutine.access[var + 1] = true; } } else if (insnNode instanceof IincInsnNode) { @@ -292,23 +290,23 @@ public class Analyzer<V extends Value> implements Opcodes { } } } catch (AnalyzerException e) { - throw new AnalyzerException(e.node, "Error at instruction " + insn - + ": " + e.getMessage(), e); + throw new AnalyzerException(e.node, "Error at instruction " + + insn + ": " + e.getMessage(), e); } catch (Exception e) { - throw new AnalyzerException(insnNode, "Error at instruction " + insn - + ": " + e.getMessage(), e); + throw new AnalyzerException(insnNode, "Error at instruction " + + insn + ": " + e.getMessage(), e); } } return frames; } - private void findSubroutine(int insn, final Subroutine sub, final List<AbstractInsnNode> calls) - throws AnalyzerException - { + private void findSubroutine(int insn, final Subroutine sub, + final List<AbstractInsnNode> calls) throws AnalyzerException { while (true) { if (insn < 0 || insn >= n) { - throw new AnalyzerException(null, "Execution can fall off end of the code"); + throw new AnalyzerException(null, + "Execution can fall off end of the code"); } if (subroutines[insn] != null) { return; @@ -352,18 +350,18 @@ public class Analyzer<V extends Value> implements Opcodes { // if insn does not falls through to the next instruction, return. switch (node.getOpcode()) { - case GOTO: - case RET: - case TABLESWITCH: - case LOOKUPSWITCH: - case IRETURN: - case LRETURN: - case FRETURN: - case DRETURN: - case ARETURN: - case RETURN: - case ATHROW: - return; + case GOTO: + case RET: + case TABLESWITCH: + case LOOKUPSWITCH: + case IRETURN: + case LRETURN: + case FRETURN: + case DRETURN: + case ARETURN: + case RETURN: + case ATHROW: + return; } insn++; } @@ -387,8 +385,9 @@ public class Analyzer<V extends Value> implements Opcodes { /** * Returns the exception handlers for the given instruction. * - * @param insn the index of an instruction of the last recently analyzed - * method. + * @param insn + * the index of an instruction of the last recently analyzed + * method. * @return a list of {@link TryCatchBlockNode} objects. */ public List<TryCatchBlockNode> getHandlers(final int insn) { @@ -400,9 +399,12 @@ public class Analyzer<V extends Value> implements Opcodes { * execution of control flow analysis loop in #analyze. The default * implementation of this method does nothing. * - * @param owner the internal name of the class to which the method belongs. - * @param m the method to be analyzed. - * @throws AnalyzerException if a problem occurs. + * @param owner + * the internal name of the class to which the method belongs. + * @param m + * the method to be analyzed. + * @throws AnalyzerException + * if a problem occurs. */ protected void init(String owner, MethodNode m) throws AnalyzerException { } @@ -410,8 +412,10 @@ public class Analyzer<V extends Value> implements Opcodes { /** * Constructs a new frame with the given size. * - * @param nLocals the maximum number of local variables of the frame. - * @param nStack the maximum stack size of the frame. + * @param nLocals + * the maximum number of local variables of the frame. + * @param nStack + * the maximum stack size of the frame. * @return the created frame. */ protected Frame<V> newFrame(final int nLocals, final int nStack) { @@ -421,7 +425,8 @@ public class Analyzer<V extends Value> implements Opcodes { /** * Constructs a new frame that is identical to the given frame. * - * @param src a frame. + * @param src + * a frame. * @return the created frame. */ protected Frame<V> newFrame(final Frame<? extends V> src) { @@ -434,8 +439,10 @@ public class Analyzer<V extends Value> implements Opcodes { * control flow graph of a method (this method is called by the * {@link #analyze analyze} method during its visit of the method's code). * - * @param insn an instruction index. - * @param successor index of a successor instruction. + * @param insn + * an instruction index. + * @param successor + * index of a successor instruction. */ protected void newControlFlowEdge(final int insn, final int successor) { } @@ -447,16 +454,16 @@ public class Analyzer<V extends Value> implements Opcodes { * method is called by the {@link #analyze analyze} method during its visit * of the method's code). * - * @param insn an instruction index. - * @param successor index of a successor instruction. + * @param insn + * an instruction index. + * @param successor + * index of a successor instruction. * @return true if this edge must be considered in the data flow analysis * performed by this analyzer, or false otherwise. The default * implementation of this method always returns true. */ - protected boolean newControlFlowExceptionEdge( - final int insn, - final int successor) - { + protected boolean newControlFlowExceptionEdge(final int insn, + final int successor) { return true; } @@ -469,28 +476,25 @@ public class Analyzer<V extends Value> implements Opcodes { * the {@link #analyze analyze} method during its visit of the method's * code). * - * @param insn an instruction index. - * @param tcb TryCatchBlockNode corresponding to this edge. + * @param insn + * an instruction index. + * @param tcb + * TryCatchBlockNode corresponding to this edge. * @return true if this edge must be considered in the data flow analysis * performed by this analyzer, or false otherwise. The default * implementation of this method delegates to * {@link #newControlFlowExceptionEdge(int, int) * newControlFlowExceptionEdge(int, int)}. */ - protected boolean newControlFlowExceptionEdge( - final int insn, - final TryCatchBlockNode tcb) - { + protected boolean newControlFlowExceptionEdge(final int insn, + final TryCatchBlockNode tcb) { return newControlFlowExceptionEdge(insn, insns.indexOf(tcb.handler)); } // ------------------------------------------------------------------------- - private void merge( - final int insn, - final Frame<V> frame, - final Subroutine subroutine) throws AnalyzerException - { + private void merge(final int insn, final Frame<V> frame, + final Subroutine subroutine) throws AnalyzerException { Frame<V> oldFrame = frames[insn]; Subroutine oldSubroutine = subroutines[insn]; boolean changes; @@ -518,13 +522,9 @@ public class Analyzer<V extends Value> implements Opcodes { } } - private void merge( - final int insn, - final Frame<V> beforeJSR, - final Frame<V> afterRET, - final Subroutine subroutineBeforeJSR, - final boolean[] access) throws AnalyzerException - { + private void merge(final int insn, final Frame<V> beforeJSR, + final Frame<V> afterRET, final Subroutine subroutineBeforeJSR, + final boolean[] access) throws AnalyzerException { Frame<V> oldFrame = frames[insn]; Subroutine oldSubroutine = subroutines[insn]; boolean changes; diff --git a/src/asm/scala/tools/asm/tree/analysis/AnalyzerException.java b/src/asm/scala/tools/asm/tree/analysis/AnalyzerException.java index a89bb3513f..5e3f51f21a 100644 --- a/src/asm/scala/tools/asm/tree/analysis/AnalyzerException.java +++ b/src/asm/scala/tools/asm/tree/analysis/AnalyzerException.java @@ -46,17 +46,14 @@ public class AnalyzerException extends Exception { this.node = node; } - public AnalyzerException(final AbstractInsnNode node, final String msg, final Throwable exception) { + public AnalyzerException(final AbstractInsnNode node, final String msg, + final Throwable exception) { super(msg, exception); this.node = node; } - public AnalyzerException( - final AbstractInsnNode node, - final String msg, - final Object expected, - final Value encountered) - { + public AnalyzerException(final AbstractInsnNode node, final String msg, + final Object expected, final Value encountered) { super((msg == null ? "Expected " : msg + ": expected ") + expected + ", but found " + encountered); this.node = node; diff --git a/src/asm/scala/tools/asm/tree/analysis/BasicInterpreter.java b/src/asm/scala/tools/asm/tree/analysis/BasicInterpreter.java index 64ddcc11e6..8d6653c1c5 100644 --- a/src/asm/scala/tools/asm/tree/analysis/BasicInterpreter.java +++ b/src/asm/scala/tools/asm/tree/analysis/BasicInterpreter.java @@ -50,8 +50,7 @@ import scala.tools.asm.tree.TypeInsnNode; * @author Bing Ran */ public class BasicInterpreter extends Interpreter<BasicValue> implements - Opcodes -{ + Opcodes { public BasicInterpreter() { super(ASM4); @@ -67,292 +66,286 @@ public class BasicInterpreter extends Interpreter<BasicValue> implements return BasicValue.UNINITIALIZED_VALUE; } switch (type.getSort()) { - case Type.VOID: - return null; - case Type.BOOLEAN: - case Type.CHAR: - case Type.BYTE: - case Type.SHORT: - case Type.INT: - return BasicValue.INT_VALUE; - case Type.FLOAT: - return BasicValue.FLOAT_VALUE; - case Type.LONG: - return BasicValue.LONG_VALUE; - case Type.DOUBLE: - return BasicValue.DOUBLE_VALUE; - case Type.ARRAY: - case Type.OBJECT: - return BasicValue.REFERENCE_VALUE; - default: - throw new Error("Internal error"); + case Type.VOID: + return null; + case Type.BOOLEAN: + case Type.CHAR: + case Type.BYTE: + case Type.SHORT: + case Type.INT: + return BasicValue.INT_VALUE; + case Type.FLOAT: + return BasicValue.FLOAT_VALUE; + case Type.LONG: + return BasicValue.LONG_VALUE; + case Type.DOUBLE: + return BasicValue.DOUBLE_VALUE; + case Type.ARRAY: + case Type.OBJECT: + return BasicValue.REFERENCE_VALUE; + default: + throw new Error("Internal error"); } } @Override public BasicValue newOperation(final AbstractInsnNode insn) - throws AnalyzerException - { + throws AnalyzerException { switch (insn.getOpcode()) { - case ACONST_NULL: - return newValue(Type.getObjectType("null")); - case ICONST_M1: - case ICONST_0: - case ICONST_1: - case ICONST_2: - case ICONST_3: - case ICONST_4: - case ICONST_5: + case ACONST_NULL: + return newValue(Type.getObjectType("null")); + case ICONST_M1: + case ICONST_0: + case ICONST_1: + case ICONST_2: + case ICONST_3: + case ICONST_4: + case ICONST_5: + return BasicValue.INT_VALUE; + case LCONST_0: + case LCONST_1: + return BasicValue.LONG_VALUE; + case FCONST_0: + case FCONST_1: + case FCONST_2: + return BasicValue.FLOAT_VALUE; + case DCONST_0: + case DCONST_1: + return BasicValue.DOUBLE_VALUE; + case BIPUSH: + case SIPUSH: + return BasicValue.INT_VALUE; + case LDC: + Object cst = ((LdcInsnNode) insn).cst; + if (cst instanceof Integer) { return BasicValue.INT_VALUE; - case LCONST_0: - case LCONST_1: - return BasicValue.LONG_VALUE; - case FCONST_0: - case FCONST_1: - case FCONST_2: + } else if (cst instanceof Float) { return BasicValue.FLOAT_VALUE; - case DCONST_0: - case DCONST_1: + } else if (cst instanceof Long) { + return BasicValue.LONG_VALUE; + } else if (cst instanceof Double) { return BasicValue.DOUBLE_VALUE; - case BIPUSH: - case SIPUSH: - return BasicValue.INT_VALUE; - case LDC: - Object cst = ((LdcInsnNode) insn).cst; - if (cst instanceof Integer) { - return BasicValue.INT_VALUE; - } else if (cst instanceof Float) { - return BasicValue.FLOAT_VALUE; - } else if (cst instanceof Long) { - return BasicValue.LONG_VALUE; - } else if (cst instanceof Double) { - return BasicValue.DOUBLE_VALUE; - } else if (cst instanceof String) { - return newValue(Type.getObjectType("java/lang/String")); - } else if (cst instanceof Type) { - int sort = ((Type) cst).getSort(); - if (sort == Type.OBJECT || sort == Type.ARRAY) { - return newValue(Type.getObjectType("java/lang/Class")); - } else if (sort == Type.METHOD) { - return newValue(Type.getObjectType("java/lang/invoke/MethodType")); - } else { - throw new IllegalArgumentException("Illegal LDC constant " + cst); - } - } else if (cst instanceof Handle) { - return newValue(Type.getObjectType("java/lang/invoke/MethodHandle")); + } else if (cst instanceof String) { + return newValue(Type.getObjectType("java/lang/String")); + } else if (cst instanceof Type) { + int sort = ((Type) cst).getSort(); + if (sort == Type.OBJECT || sort == Type.ARRAY) { + return newValue(Type.getObjectType("java/lang/Class")); + } else if (sort == Type.METHOD) { + return newValue(Type + .getObjectType("java/lang/invoke/MethodType")); } else { - throw new IllegalArgumentException("Illegal LDC constant " + cst); + throw new IllegalArgumentException("Illegal LDC constant " + + cst); } - case JSR: - return BasicValue.RETURNADDRESS_VALUE; - case GETSTATIC: - return newValue(Type.getType(((FieldInsnNode) insn).desc)); - case NEW: - return newValue(Type.getObjectType(((TypeInsnNode) insn).desc)); - default: - throw new Error("Internal error."); + } else if (cst instanceof Handle) { + return newValue(Type + .getObjectType("java/lang/invoke/MethodHandle")); + } else { + throw new IllegalArgumentException("Illegal LDC constant " + + cst); + } + case JSR: + return BasicValue.RETURNADDRESS_VALUE; + case GETSTATIC: + return newValue(Type.getType(((FieldInsnNode) insn).desc)); + case NEW: + return newValue(Type.getObjectType(((TypeInsnNode) insn).desc)); + default: + throw new Error("Internal error."); } } @Override - public BasicValue copyOperation(final AbstractInsnNode insn, final BasicValue value) - throws AnalyzerException - { + public BasicValue copyOperation(final AbstractInsnNode insn, + final BasicValue value) throws AnalyzerException { return value; } @Override - public BasicValue unaryOperation(final AbstractInsnNode insn, final BasicValue value) - throws AnalyzerException - { + public BasicValue unaryOperation(final AbstractInsnNode insn, + final BasicValue value) throws AnalyzerException { switch (insn.getOpcode()) { - case INEG: - case IINC: - case L2I: - case F2I: - case D2I: - case I2B: - case I2C: - case I2S: - return BasicValue.INT_VALUE; - case FNEG: - case I2F: - case L2F: - case D2F: - return BasicValue.FLOAT_VALUE; - case LNEG: - case I2L: - case F2L: - case D2L: - return BasicValue.LONG_VALUE; - case DNEG: - case I2D: - case L2D: - case F2D: - return BasicValue.DOUBLE_VALUE; - case IFEQ: - case IFNE: - case IFLT: - case IFGE: - case IFGT: - case IFLE: - case TABLESWITCH: - case LOOKUPSWITCH: - case IRETURN: - case LRETURN: - case FRETURN: - case DRETURN: - case ARETURN: - case PUTSTATIC: - return null; - case GETFIELD: - return newValue(Type.getType(((FieldInsnNode) insn).desc)); - case NEWARRAY: - switch (((IntInsnNode) insn).operand) { - case T_BOOLEAN: - return newValue(Type.getType("[Z")); - case T_CHAR: - return newValue(Type.getType("[C")); - case T_BYTE: - return newValue(Type.getType("[B")); - case T_SHORT: - return newValue(Type.getType("[S")); - case T_INT: - return newValue(Type.getType("[I")); - case T_FLOAT: - return newValue(Type.getType("[F")); - case T_DOUBLE: - return newValue(Type.getType("[D")); - case T_LONG: - return newValue(Type.getType("[J")); - default: - throw new AnalyzerException(insn, "Invalid array type"); - } - case ANEWARRAY: - String desc = ((TypeInsnNode) insn).desc; - return newValue(Type.getType("[" + Type.getObjectType(desc))); - case ARRAYLENGTH: - return BasicValue.INT_VALUE; - case ATHROW: - return null; - case CHECKCAST: - desc = ((TypeInsnNode) insn).desc; - return newValue(Type.getObjectType(desc)); - case INSTANCEOF: - return BasicValue.INT_VALUE; - case MONITORENTER: - case MONITOREXIT: - case IFNULL: - case IFNONNULL: - return null; + case INEG: + case IINC: + case L2I: + case F2I: + case D2I: + case I2B: + case I2C: + case I2S: + return BasicValue.INT_VALUE; + case FNEG: + case I2F: + case L2F: + case D2F: + return BasicValue.FLOAT_VALUE; + case LNEG: + case I2L: + case F2L: + case D2L: + return BasicValue.LONG_VALUE; + case DNEG: + case I2D: + case L2D: + case F2D: + return BasicValue.DOUBLE_VALUE; + case IFEQ: + case IFNE: + case IFLT: + case IFGE: + case IFGT: + case IFLE: + case TABLESWITCH: + case LOOKUPSWITCH: + case IRETURN: + case LRETURN: + case FRETURN: + case DRETURN: + case ARETURN: + case PUTSTATIC: + return null; + case GETFIELD: + return newValue(Type.getType(((FieldInsnNode) insn).desc)); + case NEWARRAY: + switch (((IntInsnNode) insn).operand) { + case T_BOOLEAN: + return newValue(Type.getType("[Z")); + case T_CHAR: + return newValue(Type.getType("[C")); + case T_BYTE: + return newValue(Type.getType("[B")); + case T_SHORT: + return newValue(Type.getType("[S")); + case T_INT: + return newValue(Type.getType("[I")); + case T_FLOAT: + return newValue(Type.getType("[F")); + case T_DOUBLE: + return newValue(Type.getType("[D")); + case T_LONG: + return newValue(Type.getType("[J")); default: - throw new Error("Internal error."); + throw new AnalyzerException(insn, "Invalid array type"); + } + case ANEWARRAY: + String desc = ((TypeInsnNode) insn).desc; + return newValue(Type.getType("[" + Type.getObjectType(desc))); + case ARRAYLENGTH: + return BasicValue.INT_VALUE; + case ATHROW: + return null; + case CHECKCAST: + desc = ((TypeInsnNode) insn).desc; + return newValue(Type.getObjectType(desc)); + case INSTANCEOF: + return BasicValue.INT_VALUE; + case MONITORENTER: + case MONITOREXIT: + case IFNULL: + case IFNONNULL: + return null; + default: + throw new Error("Internal error."); } } @Override - public BasicValue binaryOperation( - final AbstractInsnNode insn, - final BasicValue value1, - final BasicValue value2) throws AnalyzerException - { + public BasicValue binaryOperation(final AbstractInsnNode insn, + final BasicValue value1, final BasicValue value2) + throws AnalyzerException { switch (insn.getOpcode()) { - case IALOAD: - case BALOAD: - case CALOAD: - case SALOAD: - case IADD: - case ISUB: - case IMUL: - case IDIV: - case IREM: - case ISHL: - case ISHR: - case IUSHR: - case IAND: - case IOR: - case IXOR: - return BasicValue.INT_VALUE; - case FALOAD: - case FADD: - case FSUB: - case FMUL: - case FDIV: - case FREM: - return BasicValue.FLOAT_VALUE; - case LALOAD: - case LADD: - case LSUB: - case LMUL: - case LDIV: - case LREM: - case LSHL: - case LSHR: - case LUSHR: - case LAND: - case LOR: - case LXOR: - return BasicValue.LONG_VALUE; - case DALOAD: - case DADD: - case DSUB: - case DMUL: - case DDIV: - case DREM: - return BasicValue.DOUBLE_VALUE; - case AALOAD: - return BasicValue.REFERENCE_VALUE; - case LCMP: - case FCMPL: - case FCMPG: - case DCMPL: - case DCMPG: - return BasicValue.INT_VALUE; - case IF_ICMPEQ: - case IF_ICMPNE: - case IF_ICMPLT: - case IF_ICMPGE: - case IF_ICMPGT: - case IF_ICMPLE: - case IF_ACMPEQ: - case IF_ACMPNE: - case PUTFIELD: - return null; - default: - throw new Error("Internal error."); + case IALOAD: + case BALOAD: + case CALOAD: + case SALOAD: + case IADD: + case ISUB: + case IMUL: + case IDIV: + case IREM: + case ISHL: + case ISHR: + case IUSHR: + case IAND: + case IOR: + case IXOR: + return BasicValue.INT_VALUE; + case FALOAD: + case FADD: + case FSUB: + case FMUL: + case FDIV: + case FREM: + return BasicValue.FLOAT_VALUE; + case LALOAD: + case LADD: + case LSUB: + case LMUL: + case LDIV: + case LREM: + case LSHL: + case LSHR: + case LUSHR: + case LAND: + case LOR: + case LXOR: + return BasicValue.LONG_VALUE; + case DALOAD: + case DADD: + case DSUB: + case DMUL: + case DDIV: + case DREM: + return BasicValue.DOUBLE_VALUE; + case AALOAD: + return BasicValue.REFERENCE_VALUE; + case LCMP: + case FCMPL: + case FCMPG: + case DCMPL: + case DCMPG: + return BasicValue.INT_VALUE; + case IF_ICMPEQ: + case IF_ICMPNE: + case IF_ICMPLT: + case IF_ICMPGE: + case IF_ICMPGT: + case IF_ICMPLE: + case IF_ACMPEQ: + case IF_ACMPNE: + case PUTFIELD: + return null; + default: + throw new Error("Internal error."); } } @Override - public BasicValue ternaryOperation( - final AbstractInsnNode insn, - final BasicValue value1, - final BasicValue value2, - final BasicValue value3) throws AnalyzerException - { + public BasicValue ternaryOperation(final AbstractInsnNode insn, + final BasicValue value1, final BasicValue value2, + final BasicValue value3) throws AnalyzerException { return null; } @Override - public BasicValue naryOperation(final AbstractInsnNode insn, final List<? extends BasicValue> values) - throws AnalyzerException - { + public BasicValue naryOperation(final AbstractInsnNode insn, + final List<? extends BasicValue> values) throws AnalyzerException { int opcode = insn.getOpcode(); if (opcode == MULTIANEWARRAY) { return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc)); - } else if (opcode == INVOKEDYNAMIC){ - return newValue(Type.getReturnType(((InvokeDynamicInsnNode) insn).desc)); + } else if (opcode == INVOKEDYNAMIC) { + return newValue(Type + .getReturnType(((InvokeDynamicInsnNode) insn).desc)); } else { return newValue(Type.getReturnType(((MethodInsnNode) insn).desc)); } } @Override - public void returnOperation( - final AbstractInsnNode insn, - final BasicValue value, - final BasicValue expected) throws AnalyzerException - { + public void returnOperation(final AbstractInsnNode insn, + final BasicValue value, final BasicValue expected) + throws AnalyzerException { } @Override diff --git a/src/asm/scala/tools/asm/tree/analysis/BasicValue.java b/src/asm/scala/tools/asm/tree/analysis/BasicValue.java index 6c449db9b0..439941fb9f 100644 --- a/src/asm/scala/tools/asm/tree/analysis/BasicValue.java +++ b/src/asm/scala/tools/asm/tree/analysis/BasicValue.java @@ -48,11 +48,14 @@ public class BasicValue implements Value { public static final BasicValue LONG_VALUE = new BasicValue(Type.LONG_TYPE); - public static final BasicValue DOUBLE_VALUE = new BasicValue(Type.DOUBLE_TYPE); + public static final BasicValue DOUBLE_VALUE = new BasicValue( + Type.DOUBLE_TYPE); - public static final BasicValue REFERENCE_VALUE = new BasicValue(Type.getObjectType("java/lang/Object")); + public static final BasicValue REFERENCE_VALUE = new BasicValue( + Type.getObjectType("java/lang/Object")); - public static final BasicValue RETURNADDRESS_VALUE = new BasicValue(Type.VOID_TYPE); + public static final BasicValue RETURNADDRESS_VALUE = new BasicValue( + Type.VOID_TYPE); private final Type type; diff --git a/src/asm/scala/tools/asm/tree/analysis/BasicVerifier.java b/src/asm/scala/tools/asm/tree/analysis/BasicVerifier.java index 9297dd9294..71666edb74 100644 --- a/src/asm/scala/tools/asm/tree/analysis/BasicVerifier.java +++ b/src/asm/scala/tools/asm/tree/analysis/BasicVerifier.java @@ -55,47 +55,41 @@ public class BasicVerifier extends BasicInterpreter { } @Override - public BasicValue copyOperation(final AbstractInsnNode insn, final BasicValue value) - throws AnalyzerException - { + public BasicValue copyOperation(final AbstractInsnNode insn, + final BasicValue value) throws AnalyzerException { Value expected; switch (insn.getOpcode()) { - case ILOAD: - case ISTORE: - expected = BasicValue.INT_VALUE; - break; - case FLOAD: - case FSTORE: - expected = BasicValue.FLOAT_VALUE; - break; - case LLOAD: - case LSTORE: - expected = BasicValue.LONG_VALUE; - break; - case DLOAD: - case DSTORE: - expected = BasicValue.DOUBLE_VALUE; - break; - case ALOAD: - if (!value.isReference()) { - throw new AnalyzerException(insn, - null, - "an object reference", - value); - } - return value; - case ASTORE: - if (!value.isReference() - && !BasicValue.RETURNADDRESS_VALUE.equals(value)) - { - throw new AnalyzerException(insn, - null, - "an object reference or a return address", - value); - } - return value; - default: - return value; + case ILOAD: + case ISTORE: + expected = BasicValue.INT_VALUE; + break; + case FLOAD: + case FSTORE: + expected = BasicValue.FLOAT_VALUE; + break; + case LLOAD: + case LSTORE: + expected = BasicValue.LONG_VALUE; + break; + case DLOAD: + case DSTORE: + expected = BasicValue.DOUBLE_VALUE; + break; + case ALOAD: + if (!value.isReference()) { + throw new AnalyzerException(insn, null, "an object reference", + value); + } + return value; + case ASTORE: + if (!value.isReference() + && !BasicValue.RETURNADDRESS_VALUE.equals(value)) { + throw new AnalyzerException(insn, null, + "an object reference or a return address", value); + } + return value; + default: + return value; } if (!expected.equals(value)) { throw new AnalyzerException(insn, null, expected, value); @@ -104,91 +98,85 @@ public class BasicVerifier extends BasicInterpreter { } @Override - public BasicValue unaryOperation(final AbstractInsnNode insn, final BasicValue value) - throws AnalyzerException - { + public BasicValue unaryOperation(final AbstractInsnNode insn, + final BasicValue value) throws AnalyzerException { BasicValue expected; switch (insn.getOpcode()) { - case INEG: - case IINC: - case I2F: - case I2L: - case I2D: - case I2B: - case I2C: - case I2S: - case IFEQ: - case IFNE: - case IFLT: - case IFGE: - case IFGT: - case IFLE: - case TABLESWITCH: - case LOOKUPSWITCH: - case IRETURN: - case NEWARRAY: - case ANEWARRAY: - expected = BasicValue.INT_VALUE; - break; - case FNEG: - case F2I: - case F2L: - case F2D: - case FRETURN: - expected = BasicValue.FLOAT_VALUE; - break; - case LNEG: - case L2I: - case L2F: - case L2D: - case LRETURN: - expected = BasicValue.LONG_VALUE; - break; - case DNEG: - case D2I: - case D2F: - case D2L: - case DRETURN: - expected = BasicValue.DOUBLE_VALUE; - break; - case GETFIELD: - expected = newValue(Type.getObjectType(((FieldInsnNode) insn).owner)); - break; - case CHECKCAST: - if (!value.isReference()) { - throw new AnalyzerException(insn, - null, - "an object reference", - value); - } - return super.unaryOperation(insn, value); - case ARRAYLENGTH: - if (!isArrayValue(value)) { - throw new AnalyzerException(insn, - null, - "an array reference", - value); - } - return super.unaryOperation(insn, value); - case ARETURN: - case ATHROW: - case INSTANCEOF: - case MONITORENTER: - case MONITOREXIT: - case IFNULL: - case IFNONNULL: - if (!value.isReference()) { - throw new AnalyzerException(insn, - null, - "an object reference", - value); - } - return super.unaryOperation(insn, value); - case PUTSTATIC: - expected = newValue(Type.getType(((FieldInsnNode) insn).desc)); - break; - default: - throw new Error("Internal error."); + case INEG: + case IINC: + case I2F: + case I2L: + case I2D: + case I2B: + case I2C: + case I2S: + case IFEQ: + case IFNE: + case IFLT: + case IFGE: + case IFGT: + case IFLE: + case TABLESWITCH: + case LOOKUPSWITCH: + case IRETURN: + case NEWARRAY: + case ANEWARRAY: + expected = BasicValue.INT_VALUE; + break; + case FNEG: + case F2I: + case F2L: + case F2D: + case FRETURN: + expected = BasicValue.FLOAT_VALUE; + break; + case LNEG: + case L2I: + case L2F: + case L2D: + case LRETURN: + expected = BasicValue.LONG_VALUE; + break; + case DNEG: + case D2I: + case D2F: + case D2L: + case DRETURN: + expected = BasicValue.DOUBLE_VALUE; + break; + case GETFIELD: + expected = newValue(Type + .getObjectType(((FieldInsnNode) insn).owner)); + break; + case CHECKCAST: + if (!value.isReference()) { + throw new AnalyzerException(insn, null, "an object reference", + value); + } + return super.unaryOperation(insn, value); + case ARRAYLENGTH: + if (!isArrayValue(value)) { + throw new AnalyzerException(insn, null, "an array reference", + value); + } + return super.unaryOperation(insn, value); + case ARETURN: + case ATHROW: + case INSTANCEOF: + case MONITORENTER: + case MONITOREXIT: + case IFNULL: + case IFNONNULL: + if (!value.isReference()) { + throw new AnalyzerException(insn, null, "an object reference", + value); + } + return super.unaryOperation(insn, value); + case PUTSTATIC: + expected = newValue(Type.getType(((FieldInsnNode) insn).desc)); + break; + default: + throw new Error("Internal error."); } if (!isSubTypeOf(value, expected)) { throw new AnalyzerException(insn, null, expected, value); @@ -197,125 +185,125 @@ public class BasicVerifier extends BasicInterpreter { } @Override - public BasicValue binaryOperation( - final AbstractInsnNode insn, - final BasicValue value1, - final BasicValue value2) throws AnalyzerException - { + public BasicValue binaryOperation(final AbstractInsnNode insn, + final BasicValue value1, final BasicValue value2) + throws AnalyzerException { BasicValue expected1; BasicValue expected2; switch (insn.getOpcode()) { - case IALOAD: - expected1 = newValue(Type.getType("[I")); - expected2 = BasicValue.INT_VALUE; - break; - case BALOAD: - if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) { - expected1 = newValue(Type.getType("[Z")); - } else { - expected1 = newValue(Type.getType("[B")); - } - expected2 = BasicValue.INT_VALUE; - break; - case CALOAD: - expected1 = newValue(Type.getType("[C")); - expected2 = BasicValue.INT_VALUE; - break; - case SALOAD: - expected1 = newValue(Type.getType("[S")); - expected2 = BasicValue.INT_VALUE; - break; - case LALOAD: - expected1 = newValue(Type.getType("[J")); - expected2 = BasicValue.INT_VALUE; - break; - case FALOAD: - expected1 = newValue(Type.getType("[F")); - expected2 = BasicValue.INT_VALUE; - break; - case DALOAD: - expected1 = newValue(Type.getType("[D")); - expected2 = BasicValue.INT_VALUE; - break; - case AALOAD: - expected1 = newValue(Type.getType("[Ljava/lang/Object;")); - expected2 = BasicValue.INT_VALUE; - break; - case IADD: - case ISUB: - case IMUL: - case IDIV: - case IREM: - case ISHL: - case ISHR: - case IUSHR: - case IAND: - case IOR: - case IXOR: - case IF_ICMPEQ: - case IF_ICMPNE: - case IF_ICMPLT: - case IF_ICMPGE: - case IF_ICMPGT: - case IF_ICMPLE: - expected1 = BasicValue.INT_VALUE; - expected2 = BasicValue.INT_VALUE; - break; - case FADD: - case FSUB: - case FMUL: - case FDIV: - case FREM: - case FCMPL: - case FCMPG: - expected1 = BasicValue.FLOAT_VALUE; - expected2 = BasicValue.FLOAT_VALUE; - break; - case LADD: - case LSUB: - case LMUL: - case LDIV: - case LREM: - case LAND: - case LOR: - case LXOR: - case LCMP: - expected1 = BasicValue.LONG_VALUE; - expected2 = BasicValue.LONG_VALUE; - break; - case LSHL: - case LSHR: - case LUSHR: - expected1 = BasicValue.LONG_VALUE; - expected2 = BasicValue.INT_VALUE; - break; - case DADD: - case DSUB: - case DMUL: - case DDIV: - case DREM: - case DCMPL: - case DCMPG: - expected1 = BasicValue.DOUBLE_VALUE; - expected2 = BasicValue.DOUBLE_VALUE; - break; - case IF_ACMPEQ: - case IF_ACMPNE: - expected1 = BasicValue.REFERENCE_VALUE; - expected2 = BasicValue.REFERENCE_VALUE; - break; - case PUTFIELD: - FieldInsnNode fin = (FieldInsnNode) insn; - expected1 = newValue(Type.getObjectType(fin.owner)); - expected2 = newValue(Type.getType(fin.desc)); - break; - default: - throw new Error("Internal error."); + case IALOAD: + expected1 = newValue(Type.getType("[I")); + expected2 = BasicValue.INT_VALUE; + break; + case BALOAD: + if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) { + expected1 = newValue(Type.getType("[Z")); + } else { + expected1 = newValue(Type.getType("[B")); + } + expected2 = BasicValue.INT_VALUE; + break; + case CALOAD: + expected1 = newValue(Type.getType("[C")); + expected2 = BasicValue.INT_VALUE; + break; + case SALOAD: + expected1 = newValue(Type.getType("[S")); + expected2 = BasicValue.INT_VALUE; + break; + case LALOAD: + expected1 = newValue(Type.getType("[J")); + expected2 = BasicValue.INT_VALUE; + break; + case FALOAD: + expected1 = newValue(Type.getType("[F")); + expected2 = BasicValue.INT_VALUE; + break; + case DALOAD: + expected1 = newValue(Type.getType("[D")); + expected2 = BasicValue.INT_VALUE; + break; + case AALOAD: + expected1 = newValue(Type.getType("[Ljava/lang/Object;")); + expected2 = BasicValue.INT_VALUE; + break; + case IADD: + case ISUB: + case IMUL: + case IDIV: + case IREM: + case ISHL: + case ISHR: + case IUSHR: + case IAND: + case IOR: + case IXOR: + case IF_ICMPEQ: + case IF_ICMPNE: + case IF_ICMPLT: + case IF_ICMPGE: + case IF_ICMPGT: + case IF_ICMPLE: + expected1 = BasicValue.INT_VALUE; + expected2 = BasicValue.INT_VALUE; + break; + case FADD: + case FSUB: + case FMUL: + case FDIV: + case FREM: + case FCMPL: + case FCMPG: + expected1 = BasicValue.FLOAT_VALUE; + expected2 = BasicValue.FLOAT_VALUE; + break; + case LADD: + case LSUB: + case LMUL: + case LDIV: + case LREM: + case LAND: + case LOR: + case LXOR: + case LCMP: + expected1 = BasicValue.LONG_VALUE; + expected2 = BasicValue.LONG_VALUE; + break; + case LSHL: + case LSHR: + case LUSHR: + expected1 = BasicValue.LONG_VALUE; + expected2 = BasicValue.INT_VALUE; + break; + case DADD: + case DSUB: + case DMUL: + case DDIV: + case DREM: + case DCMPL: + case DCMPG: + expected1 = BasicValue.DOUBLE_VALUE; + expected2 = BasicValue.DOUBLE_VALUE; + break; + case IF_ACMPEQ: + case IF_ACMPNE: + expected1 = BasicValue.REFERENCE_VALUE; + expected2 = BasicValue.REFERENCE_VALUE; + break; + case PUTFIELD: + FieldInsnNode fin = (FieldInsnNode) insn; + expected1 = newValue(Type.getObjectType(fin.owner)); + expected2 = newValue(Type.getType(fin.desc)); + break; + default: + throw new Error("Internal error."); } if (!isSubTypeOf(value1, expected1)) { - throw new AnalyzerException(insn, "First argument", expected1, value1); + throw new AnalyzerException(insn, "First argument", expected1, + value1); } else if (!isSubTypeOf(value2, expected2)) { - throw new AnalyzerException(insn, "Second argument", expected2, value2); + throw new AnalyzerException(insn, "Second argument", expected2, + value2); } if (insn.getOpcode() == AALOAD) { return getElementValue(value1); @@ -325,79 +313,73 @@ public class BasicVerifier extends BasicInterpreter { } @Override - public BasicValue ternaryOperation( - final AbstractInsnNode insn, - final BasicValue value1, - final BasicValue value2, - final BasicValue value3) throws AnalyzerException - { + public BasicValue ternaryOperation(final AbstractInsnNode insn, + final BasicValue value1, final BasicValue value2, + final BasicValue value3) throws AnalyzerException { BasicValue expected1; BasicValue expected3; switch (insn.getOpcode()) { - case IASTORE: - expected1 = newValue(Type.getType("[I")); - expected3 = BasicValue.INT_VALUE; - break; - case BASTORE: - if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) { - expected1 = newValue(Type.getType("[Z")); - } else { - expected1 = newValue(Type.getType("[B")); - } - expected3 = BasicValue.INT_VALUE; - break; - case CASTORE: - expected1 = newValue(Type.getType("[C")); - expected3 = BasicValue.INT_VALUE; - break; - case SASTORE: - expected1 = newValue(Type.getType("[S")); - expected3 = BasicValue.INT_VALUE; - break; - case LASTORE: - expected1 = newValue(Type.getType("[J")); - expected3 = BasicValue.LONG_VALUE; - break; - case FASTORE: - expected1 = newValue(Type.getType("[F")); - expected3 = BasicValue.FLOAT_VALUE; - break; - case DASTORE: - expected1 = newValue(Type.getType("[D")); - expected3 = BasicValue.DOUBLE_VALUE; - break; - case AASTORE: - expected1 = value1; - expected3 = BasicValue.REFERENCE_VALUE; - break; - default: - throw new Error("Internal error."); + case IASTORE: + expected1 = newValue(Type.getType("[I")); + expected3 = BasicValue.INT_VALUE; + break; + case BASTORE: + if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) { + expected1 = newValue(Type.getType("[Z")); + } else { + expected1 = newValue(Type.getType("[B")); + } + expected3 = BasicValue.INT_VALUE; + break; + case CASTORE: + expected1 = newValue(Type.getType("[C")); + expected3 = BasicValue.INT_VALUE; + break; + case SASTORE: + expected1 = newValue(Type.getType("[S")); + expected3 = BasicValue.INT_VALUE; + break; + case LASTORE: + expected1 = newValue(Type.getType("[J")); + expected3 = BasicValue.LONG_VALUE; + break; + case FASTORE: + expected1 = newValue(Type.getType("[F")); + expected3 = BasicValue.FLOAT_VALUE; + break; + case DASTORE: + expected1 = newValue(Type.getType("[D")); + expected3 = BasicValue.DOUBLE_VALUE; + break; + case AASTORE: + expected1 = value1; + expected3 = BasicValue.REFERENCE_VALUE; + break; + default: + throw new Error("Internal error."); } if (!isSubTypeOf(value1, expected1)) { - throw new AnalyzerException(insn, "First argument", "a " + expected1 - + " array reference", value1); + throw new AnalyzerException(insn, "First argument", "a " + + expected1 + " array reference", value1); } else if (!BasicValue.INT_VALUE.equals(value2)) { throw new AnalyzerException(insn, "Second argument", - BasicValue.INT_VALUE, - value2); + BasicValue.INT_VALUE, value2); } else if (!isSubTypeOf(value3, expected3)) { - throw new AnalyzerException(insn, "Third argument", expected3, value3); + throw new AnalyzerException(insn, "Third argument", expected3, + value3); } return null; } @Override - public BasicValue naryOperation(final AbstractInsnNode insn, final List<? extends BasicValue> values) - throws AnalyzerException - { + public BasicValue naryOperation(final AbstractInsnNode insn, + final List<? extends BasicValue> values) throws AnalyzerException { int opcode = insn.getOpcode(); if (opcode == MULTIANEWARRAY) { for (int i = 0; i < values.size(); ++i) { if (!BasicValue.INT_VALUE.equals(values.get(i))) { - throw new AnalyzerException(insn, - null, - BasicValue.INT_VALUE, - values.get(i)); + throw new AnalyzerException(insn, null, + BasicValue.INT_VALUE, values.get(i)); } } } else { @@ -407,22 +389,18 @@ public class BasicVerifier extends BasicInterpreter { Type owner = Type.getObjectType(((MethodInsnNode) insn).owner); if (!isSubTypeOf(values.get(i++), newValue(owner))) { throw new AnalyzerException(insn, "Method owner", - newValue(owner), - values.get(0)); + newValue(owner), values.get(0)); } } - String desc = (opcode == INVOKEDYNAMIC)? - ((InvokeDynamicInsnNode) insn).desc: - ((MethodInsnNode) insn).desc; + String desc = (opcode == INVOKEDYNAMIC) ? ((InvokeDynamicInsnNode) insn).desc + : ((MethodInsnNode) insn).desc; Type[] args = Type.getArgumentTypes(desc); while (i < values.size()) { BasicValue expected = newValue(args[j++]); BasicValue encountered = values.get(i++); if (!isSubTypeOf(encountered, expected)) { - throw new AnalyzerException(insn, - "Argument " + j, - expected, - encountered); + throw new AnalyzerException(insn, "Argument " + j, + expected, encountered); } } } @@ -430,16 +408,12 @@ public class BasicVerifier extends BasicInterpreter { } @Override - public void returnOperation( - final AbstractInsnNode insn, - final BasicValue value, - final BasicValue expected) throws AnalyzerException - { + public void returnOperation(final AbstractInsnNode insn, + final BasicValue value, final BasicValue expected) + throws AnalyzerException { if (!isSubTypeOf(value, expected)) { - throw new AnalyzerException(insn, - "Incompatible return type", - expected, - value); + throw new AnalyzerException(insn, "Incompatible return type", + expected, value); } } @@ -448,12 +422,12 @@ public class BasicVerifier extends BasicInterpreter { } protected BasicValue getElementValue(final BasicValue objectArrayValue) - throws AnalyzerException - { + throws AnalyzerException { return BasicValue.REFERENCE_VALUE; } - protected boolean isSubTypeOf(final BasicValue value, final BasicValue expected) { + protected boolean isSubTypeOf(final BasicValue value, + final BasicValue expected) { return value.equals(expected); } } diff --git a/src/asm/scala/tools/asm/tree/analysis/Frame.java b/src/asm/scala/tools/asm/tree/analysis/Frame.java index fe19c2c9ae..0d92edc4d6 100644 --- a/src/asm/scala/tools/asm/tree/analysis/Frame.java +++ b/src/asm/scala/tools/asm/tree/analysis/Frame.java @@ -44,10 +44,11 @@ import scala.tools.asm.tree.VarInsnNode; /** * A symbolic execution stack frame. A stack frame contains a set of local * variable slots, and an operand stack. Warning: long and double values are - * represented by <i>two</i> slots in local variables, and by <i>one</i> slot - * in the operand stack. + * represented by <i>two</i> slots in local variables, and by <i>one</i> slot in + * the operand stack. * - * @param <V> type of the Value used for the analysis. + * @param <V> + * type of the Value used for the analysis. * * @author Eric Bruneton */ @@ -77,8 +78,10 @@ public class Frame<V extends Value> { /** * Constructs a new frame with the given size. * - * @param nLocals the maximum number of local variables of the frame. - * @param nStack the maximum stack size of the frame. + * @param nLocals + * the maximum number of local variables of the frame. + * @param nStack + * the maximum stack size of the frame. */ public Frame(final int nLocals, final int nStack) { this.values = (V[]) new Value[nLocals + nStack]; @@ -88,7 +91,8 @@ public class Frame<V extends Value> { /** * Constructs a new frame that is identical to the given frame. * - * @param src a frame. + * @param src + * a frame. */ public Frame(final Frame<? extends V> src) { this(src.locals, src.values.length - src.locals); @@ -98,7 +102,8 @@ public class Frame<V extends Value> { /** * Copies the state of the given frame into this frame. * - * @param src a frame. + * @param src + * a frame. * @return this frame. */ public Frame<V> init(final Frame<? extends V> src) { @@ -111,8 +116,9 @@ public class Frame<V extends Value> { /** * Sets the expected return type of the analyzed method. * - * @param v the expected return type of the analyzed method, or - * <tt>null</tt> if the method returns void. + * @param v + * the expected return type of the analyzed method, or + * <tt>null</tt> if the method returns void. */ public void setReturn(final V v) { returnValue = v; @@ -130,13 +136,16 @@ public class Frame<V extends Value> { /** * Returns the value of the given local variable. * - * @param i a local variable index. + * @param i + * a local variable index. * @return the value of the given local variable. - * @throws IndexOutOfBoundsException if the variable does not exist. + * @throws IndexOutOfBoundsException + * if the variable does not exist. */ public V getLocal(final int i) throws IndexOutOfBoundsException { if (i >= locals) { - throw new IndexOutOfBoundsException("Trying to access an inexistant local variable"); + throw new IndexOutOfBoundsException( + "Trying to access an inexistant local variable"); } return values[i]; } @@ -144,15 +153,18 @@ public class Frame<V extends Value> { /** * Sets the value of the given local variable. * - * @param i a local variable index. - * @param value the new value of this local variable. - * @throws IndexOutOfBoundsException if the variable does not exist. + * @param i + * a local variable index. + * @param value + * the new value of this local variable. + * @throws IndexOutOfBoundsException + * if the variable does not exist. */ public void setLocal(final int i, final V value) - throws IndexOutOfBoundsException - { + throws IndexOutOfBoundsException { if (i >= locals) { - throw new IndexOutOfBoundsException("Trying to access an inexistant local variable "+i); + throw new IndexOutOfBoundsException( + "Trying to access an inexistant local variable " + i); } values[i] = value; } @@ -170,10 +182,11 @@ public class Frame<V extends Value> { /** * Returns the value of the given operand stack slot. * - * @param i the index of an operand stack slot. + * @param i + * the index of an operand stack slot. * @return the value of the given operand stack slot. - * @throws IndexOutOfBoundsException if the operand stack slot does not - * exist. + * @throws IndexOutOfBoundsException + * if the operand stack slot does not exist. */ public V getStack(final int i) throws IndexOutOfBoundsException { return values[i + locals]; @@ -190,11 +203,13 @@ public class Frame<V extends Value> { * Pops a value from the operand stack of this frame. * * @return the value that has been popped from the stack. - * @throws IndexOutOfBoundsException if the operand stack is empty. + * @throws IndexOutOfBoundsException + * if the operand stack is empty. */ public V pop() throws IndexOutOfBoundsException { if (top == 0) { - throw new IndexOutOfBoundsException("Cannot pop operand off an empty stack."); + throw new IndexOutOfBoundsException( + "Cannot pop operand off an empty stack."); } return values[--top + locals]; } @@ -202,466 +217,469 @@ public class Frame<V extends Value> { /** * Pushes a value into the operand stack of this frame. * - * @param value the value that must be pushed into the stack. - * @throws IndexOutOfBoundsException if the operand stack is full. + * @param value + * the value that must be pushed into the stack. + * @throws IndexOutOfBoundsException + * if the operand stack is full. */ public void push(final V value) throws IndexOutOfBoundsException { if (top + locals >= values.length) { - throw new IndexOutOfBoundsException("Insufficient maximum stack size."); + throw new IndexOutOfBoundsException( + "Insufficient maximum stack size."); } values[top++ + locals] = value; } - public void execute( - final AbstractInsnNode insn, - final Interpreter<V> interpreter) throws AnalyzerException - { + public void execute(final AbstractInsnNode insn, + final Interpreter<V> interpreter) throws AnalyzerException { V value1, value2, value3, value4; List<V> values; int var; switch (insn.getOpcode()) { - case Opcodes.NOP: - break; - case Opcodes.ACONST_NULL: - case Opcodes.ICONST_M1: - case Opcodes.ICONST_0: - case Opcodes.ICONST_1: - case Opcodes.ICONST_2: - case Opcodes.ICONST_3: - case Opcodes.ICONST_4: - case Opcodes.ICONST_5: - case Opcodes.LCONST_0: - case Opcodes.LCONST_1: - case Opcodes.FCONST_0: - case Opcodes.FCONST_1: - case Opcodes.FCONST_2: - case Opcodes.DCONST_0: - case Opcodes.DCONST_1: - case Opcodes.BIPUSH: - case Opcodes.SIPUSH: - case Opcodes.LDC: - push(interpreter.newOperation(insn)); - break; - case Opcodes.ILOAD: - case Opcodes.LLOAD: - case Opcodes.FLOAD: - case Opcodes.DLOAD: - case Opcodes.ALOAD: - push(interpreter.copyOperation(insn, - getLocal(((VarInsnNode) insn).var))); - break; - case Opcodes.IALOAD: - case Opcodes.LALOAD: - case Opcodes.FALOAD: - case Opcodes.DALOAD: - case Opcodes.AALOAD: - case Opcodes.BALOAD: - case Opcodes.CALOAD: - case Opcodes.SALOAD: - value2 = pop(); - value1 = pop(); - push(interpreter.binaryOperation(insn, value1, value2)); - break; - case Opcodes.ISTORE: - case Opcodes.LSTORE: - case Opcodes.FSTORE: - case Opcodes.DSTORE: - case Opcodes.ASTORE: - value1 = interpreter.copyOperation(insn, pop()); - var = ((VarInsnNode) insn).var; - setLocal(var, value1); - if (value1.getSize() == 2) { - setLocal(var + 1, interpreter.newValue(null)); + case Opcodes.NOP: + break; + case Opcodes.ACONST_NULL: + case Opcodes.ICONST_M1: + case Opcodes.ICONST_0: + case Opcodes.ICONST_1: + case Opcodes.ICONST_2: + case Opcodes.ICONST_3: + case Opcodes.ICONST_4: + case Opcodes.ICONST_5: + case Opcodes.LCONST_0: + case Opcodes.LCONST_1: + case Opcodes.FCONST_0: + case Opcodes.FCONST_1: + case Opcodes.FCONST_2: + case Opcodes.DCONST_0: + case Opcodes.DCONST_1: + case Opcodes.BIPUSH: + case Opcodes.SIPUSH: + case Opcodes.LDC: + push(interpreter.newOperation(insn)); + break; + case Opcodes.ILOAD: + case Opcodes.LLOAD: + case Opcodes.FLOAD: + case Opcodes.DLOAD: + case Opcodes.ALOAD: + push(interpreter.copyOperation(insn, + getLocal(((VarInsnNode) insn).var))); + break; + case Opcodes.IALOAD: + case Opcodes.LALOAD: + case Opcodes.FALOAD: + case Opcodes.DALOAD: + case Opcodes.AALOAD: + case Opcodes.BALOAD: + case Opcodes.CALOAD: + case Opcodes.SALOAD: + value2 = pop(); + value1 = pop(); + push(interpreter.binaryOperation(insn, value1, value2)); + break; + case Opcodes.ISTORE: + case Opcodes.LSTORE: + case Opcodes.FSTORE: + case Opcodes.DSTORE: + case Opcodes.ASTORE: + value1 = interpreter.copyOperation(insn, pop()); + var = ((VarInsnNode) insn).var; + setLocal(var, value1); + if (value1.getSize() == 2) { + setLocal(var + 1, interpreter.newValue(null)); + } + if (var > 0) { + Value local = getLocal(var - 1); + if (local != null && local.getSize() == 2) { + setLocal(var - 1, interpreter.newValue(null)); } - if (var > 0) { - Value local = getLocal(var - 1); - if (local != null && local.getSize() == 2) { - setLocal(var - 1, interpreter.newValue(null)); - } + } + break; + case Opcodes.IASTORE: + case Opcodes.LASTORE: + case Opcodes.FASTORE: + case Opcodes.DASTORE: + case Opcodes.AASTORE: + case Opcodes.BASTORE: + case Opcodes.CASTORE: + case Opcodes.SASTORE: + value3 = pop(); + value2 = pop(); + value1 = pop(); + interpreter.ternaryOperation(insn, value1, value2, value3); + break; + case Opcodes.POP: + if (pop().getSize() == 2) { + throw new AnalyzerException(insn, "Illegal use of POP"); + } + break; + case Opcodes.POP2: + if (pop().getSize() == 1) { + if (pop().getSize() != 1) { + throw new AnalyzerException(insn, "Illegal use of POP2"); } - break; - case Opcodes.IASTORE: - case Opcodes.LASTORE: - case Opcodes.FASTORE: - case Opcodes.DASTORE: - case Opcodes.AASTORE: - case Opcodes.BASTORE: - case Opcodes.CASTORE: - case Opcodes.SASTORE: - value3 = pop(); + } + break; + case Opcodes.DUP: + value1 = pop(); + if (value1.getSize() != 1) { + throw new AnalyzerException(insn, "Illegal use of DUP"); + } + push(value1); + push(interpreter.copyOperation(insn, value1)); + break; + case Opcodes.DUP_X1: + value1 = pop(); + value2 = pop(); + if (value1.getSize() != 1 || value2.getSize() != 1) { + throw new AnalyzerException(insn, "Illegal use of DUP_X1"); + } + push(interpreter.copyOperation(insn, value1)); + push(value2); + push(value1); + break; + case Opcodes.DUP_X2: + value1 = pop(); + if (value1.getSize() == 1) { value2 = pop(); - value1 = pop(); - interpreter.ternaryOperation(insn, value1, value2, value3); - break; - case Opcodes.POP: - if (pop().getSize() == 2) { - throw new AnalyzerException(insn, "Illegal use of POP"); - } - break; - case Opcodes.POP2: - if (pop().getSize() == 1) { - if (pop().getSize() != 1) { - throw new AnalyzerException(insn, "Illegal use of POP2"); + if (value2.getSize() == 1) { + value3 = pop(); + if (value3.getSize() == 1) { + push(interpreter.copyOperation(insn, value1)); + push(value3); + push(value2); + push(value1); + break; } + } else { + push(interpreter.copyOperation(insn, value1)); + push(value2); + push(value1); + break; } - break; - case Opcodes.DUP: - value1 = pop(); - if (value1.getSize() != 1) { - throw new AnalyzerException(insn, "Illegal use of DUP"); + } + throw new AnalyzerException(insn, "Illegal use of DUP_X2"); + case Opcodes.DUP2: + value1 = pop(); + if (value1.getSize() == 1) { + value2 = pop(); + if (value2.getSize() == 1) { + push(value2); + push(value1); + push(interpreter.copyOperation(insn, value2)); + push(interpreter.copyOperation(insn, value1)); + break; } + } else { push(value1); push(interpreter.copyOperation(insn, value1)); break; - case Opcodes.DUP_X1: - value1 = pop(); + } + throw new AnalyzerException(insn, "Illegal use of DUP2"); + case Opcodes.DUP2_X1: + value1 = pop(); + if (value1.getSize() == 1) { value2 = pop(); - if (value1.getSize() != 1 || value2.getSize() != 1) { - throw new AnalyzerException(insn, "Illegal use of DUP_X1"); - } - push(interpreter.copyOperation(insn, value1)); - push(value2); - push(value1); - break; - case Opcodes.DUP_X2: - value1 = pop(); - if (value1.getSize() == 1) { - value2 = pop(); - if (value2.getSize() == 1) { - value3 = pop(); - if (value3.getSize() == 1) { - push(interpreter.copyOperation(insn, value1)); - push(value3); - push(value2); - push(value1); - break; - } - } else { + if (value2.getSize() == 1) { + value3 = pop(); + if (value3.getSize() == 1) { + push(interpreter.copyOperation(insn, value2)); push(interpreter.copyOperation(insn, value1)); + push(value3); push(value2); push(value1); break; } } - throw new AnalyzerException(insn, "Illegal use of DUP_X2"); - case Opcodes.DUP2: - value1 = pop(); - if (value1.getSize() == 1) { - value2 = pop(); - if (value2.getSize() == 1) { - push(value2); - push(value1); - push(interpreter.copyOperation(insn, value2)); - push(interpreter.copyOperation(insn, value1)); - break; - } - } else { - push(value1); + } else { + value2 = pop(); + if (value2.getSize() == 1) { push(interpreter.copyOperation(insn, value1)); + push(value2); + push(value1); break; } - throw new AnalyzerException(insn, "Illegal use of DUP2"); - case Opcodes.DUP2_X1: - value1 = pop(); - if (value1.getSize() == 1) { - value2 = pop(); - if (value2.getSize() == 1) { - value3 = pop(); - if (value3.getSize() == 1) { + } + throw new AnalyzerException(insn, "Illegal use of DUP2_X1"); + case Opcodes.DUP2_X2: + value1 = pop(); + if (value1.getSize() == 1) { + value2 = pop(); + if (value2.getSize() == 1) { + value3 = pop(); + if (value3.getSize() == 1) { + value4 = pop(); + if (value4.getSize() == 1) { push(interpreter.copyOperation(insn, value2)); push(interpreter.copyOperation(insn, value1)); + push(value4); push(value3); push(value2); push(value1); break; } - } - } else { - value2 = pop(); - if (value2.getSize() == 1) { + } else { + push(interpreter.copyOperation(insn, value2)); push(interpreter.copyOperation(insn, value1)); + push(value3); push(value2); push(value1); break; } } - throw new AnalyzerException(insn, "Illegal use of DUP2_X1"); - case Opcodes.DUP2_X2: - value1 = pop(); - if (value1.getSize() == 1) { - value2 = pop(); - if (value2.getSize() == 1) { - value3 = pop(); - if (value3.getSize() == 1) { - value4 = pop(); - if (value4.getSize() == 1) { - push(interpreter.copyOperation(insn, value2)); - push(interpreter.copyOperation(insn, value1)); - push(value4); - push(value3); - push(value2); - push(value1); - break; - } - } else { - push(interpreter.copyOperation(insn, value2)); - push(interpreter.copyOperation(insn, value1)); - push(value3); - push(value2); - push(value1); - break; - } - } - } else { - value2 = pop(); - if (value2.getSize() == 1) { - value3 = pop(); - if (value3.getSize() == 1) { - push(interpreter.copyOperation(insn, value1)); - push(value3); - push(value2); - push(value1); - break; - } - } else { + } else { + value2 = pop(); + if (value2.getSize() == 1) { + value3 = pop(); + if (value3.getSize() == 1) { push(interpreter.copyOperation(insn, value1)); + push(value3); push(value2); push(value1); break; } - } - throw new AnalyzerException(insn, "Illegal use of DUP2_X2"); - case Opcodes.SWAP: - value2 = pop(); - value1 = pop(); - if (value1.getSize() != 1 || value2.getSize() != 1) { - throw new AnalyzerException(insn, "Illegal use of SWAP"); - } - push(interpreter.copyOperation(insn, value2)); - push(interpreter.copyOperation(insn, value1)); - break; - case Opcodes.IADD: - case Opcodes.LADD: - case Opcodes.FADD: - case Opcodes.DADD: - case Opcodes.ISUB: - case Opcodes.LSUB: - case Opcodes.FSUB: - case Opcodes.DSUB: - case Opcodes.IMUL: - case Opcodes.LMUL: - case Opcodes.FMUL: - case Opcodes.DMUL: - case Opcodes.IDIV: - case Opcodes.LDIV: - case Opcodes.FDIV: - case Opcodes.DDIV: - case Opcodes.IREM: - case Opcodes.LREM: - case Opcodes.FREM: - case Opcodes.DREM: - value2 = pop(); - value1 = pop(); - push(interpreter.binaryOperation(insn, value1, value2)); - break; - case Opcodes.INEG: - case Opcodes.LNEG: - case Opcodes.FNEG: - case Opcodes.DNEG: - push(interpreter.unaryOperation(insn, pop())); - break; - case Opcodes.ISHL: - case Opcodes.LSHL: - case Opcodes.ISHR: - case Opcodes.LSHR: - case Opcodes.IUSHR: - case Opcodes.LUSHR: - case Opcodes.IAND: - case Opcodes.LAND: - case Opcodes.IOR: - case Opcodes.LOR: - case Opcodes.IXOR: - case Opcodes.LXOR: - value2 = pop(); - value1 = pop(); - push(interpreter.binaryOperation(insn, value1, value2)); - break; - case Opcodes.IINC: - var = ((IincInsnNode) insn).var; - setLocal(var, interpreter.unaryOperation(insn, getLocal(var))); - break; - case Opcodes.I2L: - case Opcodes.I2F: - case Opcodes.I2D: - case Opcodes.L2I: - case Opcodes.L2F: - case Opcodes.L2D: - case Opcodes.F2I: - case Opcodes.F2L: - case Opcodes.F2D: - case Opcodes.D2I: - case Opcodes.D2L: - case Opcodes.D2F: - case Opcodes.I2B: - case Opcodes.I2C: - case Opcodes.I2S: - push(interpreter.unaryOperation(insn, pop())); - break; - case Opcodes.LCMP: - case Opcodes.FCMPL: - case Opcodes.FCMPG: - case Opcodes.DCMPL: - case Opcodes.DCMPG: - value2 = pop(); - value1 = pop(); - push(interpreter.binaryOperation(insn, value1, value2)); - break; - case Opcodes.IFEQ: - case Opcodes.IFNE: - case Opcodes.IFLT: - case Opcodes.IFGE: - case Opcodes.IFGT: - case Opcodes.IFLE: - interpreter.unaryOperation(insn, pop()); - break; - case Opcodes.IF_ICMPEQ: - case Opcodes.IF_ICMPNE: - case Opcodes.IF_ICMPLT: - case Opcodes.IF_ICMPGE: - case Opcodes.IF_ICMPGT: - case Opcodes.IF_ICMPLE: - case Opcodes.IF_ACMPEQ: - case Opcodes.IF_ACMPNE: - value2 = pop(); - value1 = pop(); - interpreter.binaryOperation(insn, value1, value2); - break; - case Opcodes.GOTO: - break; - case Opcodes.JSR: - push(interpreter.newOperation(insn)); - break; - case Opcodes.RET: - break; - case Opcodes.TABLESWITCH: - case Opcodes.LOOKUPSWITCH: - interpreter.unaryOperation(insn, pop()); - break; - case Opcodes.IRETURN: - case Opcodes.LRETURN: - case Opcodes.FRETURN: - case Opcodes.DRETURN: - case Opcodes.ARETURN: - value1 = pop(); - interpreter.unaryOperation(insn, value1); - interpreter.returnOperation(insn, value1, returnValue); - break; - case Opcodes.RETURN: - if (returnValue != null) { - throw new AnalyzerException(insn, "Incompatible return type"); - } - break; - case Opcodes.GETSTATIC: - push(interpreter.newOperation(insn)); - break; - case Opcodes.PUTSTATIC: - interpreter.unaryOperation(insn, pop()); - break; - case Opcodes.GETFIELD: - push(interpreter.unaryOperation(insn, pop())); - break; - case Opcodes.PUTFIELD: - value2 = pop(); - value1 = pop(); - interpreter.binaryOperation(insn, value1, value2); - break; - case Opcodes.INVOKEVIRTUAL: - case Opcodes.INVOKESPECIAL: - case Opcodes.INVOKESTATIC: - case Opcodes.INVOKEINTERFACE: { - values = new ArrayList<V>(); - String desc = ((MethodInsnNode) insn).desc; - for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) { - values.add(0, pop()); - } - if (insn.getOpcode() != Opcodes.INVOKESTATIC) { - values.add(0, pop()); - } - if (Type.getReturnType(desc) == Type.VOID_TYPE) { - interpreter.naryOperation(insn, values); } else { - push(interpreter.naryOperation(insn, values)); + push(interpreter.copyOperation(insn, value1)); + push(value2); + push(value1); + break; } - break; } - case Opcodes.INVOKEDYNAMIC: { - values = new ArrayList<V>(); - String desc = ((InvokeDynamicInsnNode) insn).desc; - for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) { - values.add(0, pop()); - } - if (Type.getReturnType(desc) == Type.VOID_TYPE) { - interpreter.naryOperation(insn, values); - } else { - push(interpreter.naryOperation(insn, values)); - } - break; + throw new AnalyzerException(insn, "Illegal use of DUP2_X2"); + case Opcodes.SWAP: + value2 = pop(); + value1 = pop(); + if (value1.getSize() != 1 || value2.getSize() != 1) { + throw new AnalyzerException(insn, "Illegal use of SWAP"); } - case Opcodes.NEW: - push(interpreter.newOperation(insn)); - break; - case Opcodes.NEWARRAY: - case Opcodes.ANEWARRAY: - case Opcodes.ARRAYLENGTH: - push(interpreter.unaryOperation(insn, pop())); - break; - case Opcodes.ATHROW: - interpreter.unaryOperation(insn, pop()); - break; - case Opcodes.CHECKCAST: - case Opcodes.INSTANCEOF: - push(interpreter.unaryOperation(insn, pop())); - break; - case Opcodes.MONITORENTER: - case Opcodes.MONITOREXIT: - interpreter.unaryOperation(insn, pop()); - break; - case Opcodes.MULTIANEWARRAY: - values = new ArrayList<V>(); - for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) { - values.add(0, pop()); - } + push(interpreter.copyOperation(insn, value2)); + push(interpreter.copyOperation(insn, value1)); + break; + case Opcodes.IADD: + case Opcodes.LADD: + case Opcodes.FADD: + case Opcodes.DADD: + case Opcodes.ISUB: + case Opcodes.LSUB: + case Opcodes.FSUB: + case Opcodes.DSUB: + case Opcodes.IMUL: + case Opcodes.LMUL: + case Opcodes.FMUL: + case Opcodes.DMUL: + case Opcodes.IDIV: + case Opcodes.LDIV: + case Opcodes.FDIV: + case Opcodes.DDIV: + case Opcodes.IREM: + case Opcodes.LREM: + case Opcodes.FREM: + case Opcodes.DREM: + value2 = pop(); + value1 = pop(); + push(interpreter.binaryOperation(insn, value1, value2)); + break; + case Opcodes.INEG: + case Opcodes.LNEG: + case Opcodes.FNEG: + case Opcodes.DNEG: + push(interpreter.unaryOperation(insn, pop())); + break; + case Opcodes.ISHL: + case Opcodes.LSHL: + case Opcodes.ISHR: + case Opcodes.LSHR: + case Opcodes.IUSHR: + case Opcodes.LUSHR: + case Opcodes.IAND: + case Opcodes.LAND: + case Opcodes.IOR: + case Opcodes.LOR: + case Opcodes.IXOR: + case Opcodes.LXOR: + value2 = pop(); + value1 = pop(); + push(interpreter.binaryOperation(insn, value1, value2)); + break; + case Opcodes.IINC: + var = ((IincInsnNode) insn).var; + setLocal(var, interpreter.unaryOperation(insn, getLocal(var))); + break; + case Opcodes.I2L: + case Opcodes.I2F: + case Opcodes.I2D: + case Opcodes.L2I: + case Opcodes.L2F: + case Opcodes.L2D: + case Opcodes.F2I: + case Opcodes.F2L: + case Opcodes.F2D: + case Opcodes.D2I: + case Opcodes.D2L: + case Opcodes.D2F: + case Opcodes.I2B: + case Opcodes.I2C: + case Opcodes.I2S: + push(interpreter.unaryOperation(insn, pop())); + break; + case Opcodes.LCMP: + case Opcodes.FCMPL: + case Opcodes.FCMPG: + case Opcodes.DCMPL: + case Opcodes.DCMPG: + value2 = pop(); + value1 = pop(); + push(interpreter.binaryOperation(insn, value1, value2)); + break; + case Opcodes.IFEQ: + case Opcodes.IFNE: + case Opcodes.IFLT: + case Opcodes.IFGE: + case Opcodes.IFGT: + case Opcodes.IFLE: + interpreter.unaryOperation(insn, pop()); + break; + case Opcodes.IF_ICMPEQ: + case Opcodes.IF_ICMPNE: + case Opcodes.IF_ICMPLT: + case Opcodes.IF_ICMPGE: + case Opcodes.IF_ICMPGT: + case Opcodes.IF_ICMPLE: + case Opcodes.IF_ACMPEQ: + case Opcodes.IF_ACMPNE: + value2 = pop(); + value1 = pop(); + interpreter.binaryOperation(insn, value1, value2); + break; + case Opcodes.GOTO: + break; + case Opcodes.JSR: + push(interpreter.newOperation(insn)); + break; + case Opcodes.RET: + break; + case Opcodes.TABLESWITCH: + case Opcodes.LOOKUPSWITCH: + interpreter.unaryOperation(insn, pop()); + break; + case Opcodes.IRETURN: + case Opcodes.LRETURN: + case Opcodes.FRETURN: + case Opcodes.DRETURN: + case Opcodes.ARETURN: + value1 = pop(); + interpreter.unaryOperation(insn, value1); + interpreter.returnOperation(insn, value1, returnValue); + break; + case Opcodes.RETURN: + if (returnValue != null) { + throw new AnalyzerException(insn, "Incompatible return type"); + } + break; + case Opcodes.GETSTATIC: + push(interpreter.newOperation(insn)); + break; + case Opcodes.PUTSTATIC: + interpreter.unaryOperation(insn, pop()); + break; + case Opcodes.GETFIELD: + push(interpreter.unaryOperation(insn, pop())); + break; + case Opcodes.PUTFIELD: + value2 = pop(); + value1 = pop(); + interpreter.binaryOperation(insn, value1, value2); + break; + case Opcodes.INVOKEVIRTUAL: + case Opcodes.INVOKESPECIAL: + case Opcodes.INVOKESTATIC: + case Opcodes.INVOKEINTERFACE: { + values = new ArrayList<V>(); + String desc = ((MethodInsnNode) insn).desc; + for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) { + values.add(0, pop()); + } + if (insn.getOpcode() != Opcodes.INVOKESTATIC) { + values.add(0, pop()); + } + if (Type.getReturnType(desc) == Type.VOID_TYPE) { + interpreter.naryOperation(insn, values); + } else { push(interpreter.naryOperation(insn, values)); - break; - case Opcodes.IFNULL: - case Opcodes.IFNONNULL: - interpreter.unaryOperation(insn, pop()); - break; - default: - throw new RuntimeException("Illegal opcode "+insn.getOpcode()); + } + break; + } + case Opcodes.INVOKEDYNAMIC: { + values = new ArrayList<V>(); + String desc = ((InvokeDynamicInsnNode) insn).desc; + for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) { + values.add(0, pop()); + } + if (Type.getReturnType(desc) == Type.VOID_TYPE) { + interpreter.naryOperation(insn, values); + } else { + push(interpreter.naryOperation(insn, values)); + } + break; + } + case Opcodes.NEW: + push(interpreter.newOperation(insn)); + break; + case Opcodes.NEWARRAY: + case Opcodes.ANEWARRAY: + case Opcodes.ARRAYLENGTH: + push(interpreter.unaryOperation(insn, pop())); + break; + case Opcodes.ATHROW: + interpreter.unaryOperation(insn, pop()); + break; + case Opcodes.CHECKCAST: + case Opcodes.INSTANCEOF: + push(interpreter.unaryOperation(insn, pop())); + break; + case Opcodes.MONITORENTER: + case Opcodes.MONITOREXIT: + interpreter.unaryOperation(insn, pop()); + break; + case Opcodes.MULTIANEWARRAY: + values = new ArrayList<V>(); + for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) { + values.add(0, pop()); + } + push(interpreter.naryOperation(insn, values)); + break; + case Opcodes.IFNULL: + case Opcodes.IFNONNULL: + interpreter.unaryOperation(insn, pop()); + break; + default: + throw new RuntimeException("Illegal opcode " + insn.getOpcode()); } } /** * Merges this frame with the given frame. * - * @param frame a frame. - * @param interpreter the interpreter used to merge values. + * @param frame + * a frame. + * @param interpreter + * the interpreter used to merge values. * @return <tt>true</tt> if this frame has been changed as a result of the * merge operation, or <tt>false</tt> otherwise. - * @throws AnalyzerException if the frames have incompatible sizes. + * @throws AnalyzerException + * if the frames have incompatible sizes. */ - public boolean merge(final Frame<? extends V> frame, final Interpreter<V> interpreter) - throws AnalyzerException - { + public boolean merge(final Frame<? extends V> frame, + final Interpreter<V> interpreter) throws AnalyzerException { if (top != frame.top) { throw new AnalyzerException(null, "Incompatible stack heights"); } boolean changes = false; for (int i = 0; i < locals + top; ++i) { V v = interpreter.merge(values[i], frame.values[i]); - if (v != values[i]) { + if (!v.equals(values[i])) { values[i] = v; changes = true; } @@ -672,9 +690,11 @@ public class Frame<V extends Value> { /** * Merges this frame with the given frame (case of a RET instruction). * - * @param frame a frame - * @param access the local variables that have been accessed by the - * subroutine to which the RET instruction corresponds. + * @param frame + * a frame + * @param access + * the local variables that have been accessed by the subroutine + * to which the RET instruction corresponds. * @return <tt>true</tt> if this frame has been changed as a result of the * merge operation, or <tt>false</tt> otherwise. */ diff --git a/src/asm/scala/tools/asm/tree/analysis/Interpreter.java b/src/asm/scala/tools/asm/tree/analysis/Interpreter.java index 930c8f4af8..56f4bedc00 100644 --- a/src/asm/scala/tools/asm/tree/analysis/Interpreter.java +++ b/src/asm/scala/tools/asm/tree/analysis/Interpreter.java @@ -42,7 +42,8 @@ import scala.tools.asm.tree.AbstractInsnNode; * various semantic interpreters, without needing to duplicate the code to * simulate the transfer of values. * - * @param <V> type of the Value used for the analysis. + * @param <V> + * type of the Value used for the analysis. * * @author Eric Bruneton */ @@ -57,12 +58,13 @@ public abstract class Interpreter<V extends Value> { /** * Creates a new value that represents the given type. * - * Called for method parameters (including <code>this</code>), - * exception handler variable and with <code>null</code> type - * for variables reserved by long and double types. + * Called for method parameters (including <code>this</code>), exception + * handler variable and with <code>null</code> type for variables reserved + * by long and double types. * - * @param type a primitive or reference type, or <tt>null</tt> to - * represent an uninitialized value. + * @param type + * a primitive or reference type, or <tt>null</tt> to represent + * an uninitialized value. * @return a value that represents the given type. The size of the returned * value must be equal to the size of the given type. */ @@ -76,9 +78,11 @@ public abstract class Interpreter<V extends Value> { * ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0, * DCONST_1, BIPUSH, SIPUSH, LDC, JSR, GETSTATIC, NEW * - * @param insn the bytecode instruction to be interpreted. + * @param insn + * the bytecode instruction to be interpreted. * @return the result of the interpretation of the given instruction. - * @throws AnalyzerException if an error occured during the interpretation. + * @throws AnalyzerException + * if an error occured during the interpretation. */ public abstract V newOperation(AbstractInsnNode insn) throws AnalyzerException; @@ -90,11 +94,14 @@ public abstract class Interpreter<V extends Value> { * ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, * ASTORE, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP * - * @param insn the bytecode instruction to be interpreted. - * @param value the value that must be moved by the instruction. + * @param insn + * the bytecode instruction to be interpreted. + * @param value + * the value that must be moved by the instruction. * @return the result of the interpretation of the given instruction. The * returned value must be <tt>equal</tt> to the given value. - * @throws AnalyzerException if an error occured during the interpretation. + * @throws AnalyzerException + * if an error occured during the interpretation. */ public abstract V copyOperation(AbstractInsnNode insn, V value) throws AnalyzerException; @@ -109,10 +116,13 @@ public abstract class Interpreter<V extends Value> { * PUTSTATIC, GETFIELD, NEWARRAY, ANEWARRAY, ARRAYLENGTH, ATHROW, CHECKCAST, * INSTANCEOF, MONITORENTER, MONITOREXIT, IFNULL, IFNONNULL * - * @param insn the bytecode instruction to be interpreted. - * @param value the argument of the instruction to be interpreted. + * @param insn + * the bytecode instruction to be interpreted. + * @param value + * the argument of the instruction to be interpreted. * @return the result of the interpretation of the given instruction. - * @throws AnalyzerException if an error occured during the interpretation. + * @throws AnalyzerException + * if an error occured during the interpretation. */ public abstract V unaryOperation(AbstractInsnNode insn, V value) throws AnalyzerException; @@ -128,11 +138,15 @@ public abstract class Interpreter<V extends Value> { * DCMPG, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, * IF_ACMPEQ, IF_ACMPNE, PUTFIELD * - * @param insn the bytecode instruction to be interpreted. - * @param value1 the first argument of the instruction to be interpreted. - * @param value2 the second argument of the instruction to be interpreted. + * @param insn + * the bytecode instruction to be interpreted. + * @param value1 + * the first argument of the instruction to be interpreted. + * @param value2 + * the second argument of the instruction to be interpreted. * @return the result of the interpretation of the given instruction. - * @throws AnalyzerException if an error occured during the interpretation. + * @throws AnalyzerException + * if an error occured during the interpretation. */ public abstract V binaryOperation(AbstractInsnNode insn, V value1, V value2) throws AnalyzerException; @@ -143,18 +157,20 @@ public abstract class Interpreter<V extends Value> { * * IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE * - * @param insn the bytecode instruction to be interpreted. - * @param value1 the first argument of the instruction to be interpreted. - * @param value2 the second argument of the instruction to be interpreted. - * @param value3 the third argument of the instruction to be interpreted. + * @param insn + * the bytecode instruction to be interpreted. + * @param value1 + * the first argument of the instruction to be interpreted. + * @param value2 + * the second argument of the instruction to be interpreted. + * @param value3 + * the third argument of the instruction to be interpreted. * @return the result of the interpretation of the given instruction. - * @throws AnalyzerException if an error occured during the interpretation. + * @throws AnalyzerException + * if an error occured during the interpretation. */ - public abstract V ternaryOperation( - AbstractInsnNode insn, - V value1, - V value2, - V value3) throws AnalyzerException; + public abstract V ternaryOperation(AbstractInsnNode insn, V value1, + V value2, V value3) throws AnalyzerException; /** * Interprets a bytecode instruction with a variable number of arguments. @@ -163,14 +179,16 @@ public abstract class Interpreter<V extends Value> { * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE, * MULTIANEWARRAY and INVOKEDYNAMIC * - * @param insn the bytecode instruction to be interpreted. - * @param values the arguments of the instruction to be interpreted. + * @param insn + * the bytecode instruction to be interpreted. + * @param values + * the arguments of the instruction to be interpreted. * @return the result of the interpretation of the given instruction. - * @throws AnalyzerException if an error occured during the interpretation. + * @throws AnalyzerException + * if an error occured during the interpretation. */ - public abstract V naryOperation( - AbstractInsnNode insn, - List< ? extends V> values) throws AnalyzerException; + public abstract V naryOperation(AbstractInsnNode insn, + List<? extends V> values) throws AnalyzerException; /** * Interprets a bytecode return instruction. This method is called for the @@ -178,15 +196,17 @@ public abstract class Interpreter<V extends Value> { * * IRETURN, LRETURN, FRETURN, DRETURN, ARETURN * - * @param insn the bytecode instruction to be interpreted. - * @param value the argument of the instruction to be interpreted. - * @param expected the expected return type of the analyzed method. - * @throws AnalyzerException if an error occured during the interpretation. + * @param insn + * the bytecode instruction to be interpreted. + * @param value + * the argument of the instruction to be interpreted. + * @param expected + * the expected return type of the analyzed method. + * @throws AnalyzerException + * if an error occured during the interpretation. */ - public abstract void returnOperation( - AbstractInsnNode insn, - V value, - V expected) throws AnalyzerException; + public abstract void returnOperation(AbstractInsnNode insn, V value, + V expected) throws AnalyzerException; /** * Merges two values. The merge operation must return a value that @@ -195,8 +215,10 @@ public abstract class Interpreter<V extends Value> { * values are integer intervals, the merged value must be an interval that * contains the previous ones. Likewise for other types of values). * - * @param v a value. - * @param w another value. + * @param v + * a value. + * @param w + * another value. * @return the merged value. If the merged value is equal to <tt>v</tt>, * this method <i>must</i> return <tt>v</tt>. */ diff --git a/src/asm/scala/tools/asm/tree/analysis/SimpleVerifier.java b/src/asm/scala/tools/asm/tree/analysis/SimpleVerifier.java index c4f515d328..eaecd057ea 100644 --- a/src/asm/scala/tools/asm/tree/analysis/SimpleVerifier.java +++ b/src/asm/scala/tools/asm/tree/analysis/SimpleVerifier.java @@ -79,15 +79,15 @@ public class SimpleVerifier extends BasicVerifier { * Constructs a new {@link SimpleVerifier} to verify a specific class. This * class will not be loaded into the JVM since it may be incorrect. * - * @param currentClass the class that is verified. - * @param currentSuperClass the super class of the class that is verified. - * @param isInterface if the class that is verified is an interface. + * @param currentClass + * the class that is verified. + * @param currentSuperClass + * the super class of the class that is verified. + * @param isInterface + * if the class that is verified is an interface. */ - public SimpleVerifier( - final Type currentClass, - final Type currentSuperClass, - final boolean isInterface) - { + public SimpleVerifier(final Type currentClass, + final Type currentSuperClass, final boolean isInterface) { this(currentClass, currentSuperClass, null, isInterface); } @@ -95,32 +95,25 @@ public class SimpleVerifier extends BasicVerifier { * Constructs a new {@link SimpleVerifier} to verify a specific class. This * class will not be loaded into the JVM since it may be incorrect. * - * @param currentClass the class that is verified. - * @param currentSuperClass the super class of the class that is verified. - * @param currentClassInterfaces the interfaces implemented by the class - * that is verified. - * @param isInterface if the class that is verified is an interface. + * @param currentClass + * the class that is verified. + * @param currentSuperClass + * the super class of the class that is verified. + * @param currentClassInterfaces + * the interfaces implemented by the class that is verified. + * @param isInterface + * if the class that is verified is an interface. */ - public SimpleVerifier( - final Type currentClass, - final Type currentSuperClass, - final List<Type> currentClassInterfaces, - final boolean isInterface) - { - this(ASM4, - currentClass, - currentSuperClass, - currentClassInterfaces, + public SimpleVerifier(final Type currentClass, + final Type currentSuperClass, + final List<Type> currentClassInterfaces, final boolean isInterface) { + this(ASM4, currentClass, currentSuperClass, currentClassInterfaces, isInterface); } - protected SimpleVerifier( - final int api, - final Type currentClass, - final Type currentSuperClass, - final List<Type> currentClassInterfaces, - final boolean isInterface) - { + protected SimpleVerifier(final int api, final Type currentClass, + final Type currentSuperClass, + final List<Type> currentClassInterfaces, final boolean isInterface) { super(api); this.currentClass = currentClass; this.currentSuperClass = currentSuperClass; @@ -133,7 +126,8 @@ public class SimpleVerifier extends BasicVerifier { * classes. This is useful if you are verifying multiple interdependent * classes. * - * @param loader a <code>ClassLoader</code> to use + * @param loader + * a <code>ClassLoader</code> to use */ public void setClassLoader(final ClassLoader loader) { this.loader = loader; @@ -148,11 +142,11 @@ public class SimpleVerifier extends BasicVerifier { boolean isArray = type.getSort() == Type.ARRAY; if (isArray) { switch (type.getElementType().getSort()) { - case Type.BOOLEAN: - case Type.CHAR: - case Type.BYTE: - case Type.SHORT: - return new BasicValue(type); + case Type.BOOLEAN: + case Type.CHAR: + case Type.BYTE: + case Type.SHORT: + return new BasicValue(type); } } @@ -181,8 +175,7 @@ public class SimpleVerifier extends BasicVerifier { @Override protected BasicValue getElementValue(final BasicValue objectArrayValue) - throws AnalyzerException - { + throws AnalyzerException { Type arrayType = objectArrayValue.getType(); if (arrayType != null) { if (arrayType.getSort() == Type.ARRAY) { @@ -196,28 +189,28 @@ public class SimpleVerifier extends BasicVerifier { } @Override - protected boolean isSubTypeOf(final BasicValue value, final BasicValue expected) { + protected boolean isSubTypeOf(final BasicValue value, + final BasicValue expected) { Type expectedType = expected.getType(); Type type = value.getType(); switch (expectedType.getSort()) { - case Type.INT: - case Type.FLOAT: - case Type.LONG: - case Type.DOUBLE: - return type.equals(expectedType); - case Type.ARRAY: - case Type.OBJECT: - if ("Lnull;".equals(type.getDescriptor())) { - return true; - } else if (type.getSort() == Type.OBJECT - || type.getSort() == Type.ARRAY) - { - return isAssignableFrom(expectedType, type); - } else { - return false; - } - default: - throw new Error("Internal error"); + case Type.INT: + case Type.FLOAT: + case Type.LONG: + case Type.DOUBLE: + return type.equals(expectedType); + case Type.ARRAY: + case Type.OBJECT: + if ("Lnull;".equals(type.getDescriptor())) { + return true; + } else if (type.getSort() == Type.OBJECT + || type.getSort() == Type.ARRAY) { + return isAssignableFrom(expectedType, type); + } else { + return false; + } + default: + throw new Error("Internal error"); } } @@ -227,11 +220,9 @@ public class SimpleVerifier extends BasicVerifier { Type t = v.getType(); Type u = w.getType(); if (t != null - && (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)) - { + && (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)) { if (u != null - && (u.getSort() == Type.OBJECT || u.getSort() == Type.ARRAY)) - { + && (u.getSort() == Type.OBJECT || u.getSort() == Type.ARRAY)) { if ("Lnull;".equals(t.getDescriptor())) { return w; } @@ -288,7 +279,8 @@ public class SimpleVerifier extends BasicVerifier { return false; } else { if (isInterface) { - return u.getSort() == Type.OBJECT || u.getSort() == Type.ARRAY; + return u.getSort() == Type.OBJECT + || u.getSort() == Type.ARRAY; } return isAssignableFrom(t, getSuperClass(u)); } @@ -318,8 +310,7 @@ public class SimpleVerifier extends BasicVerifier { try { if (t.getSort() == Type.ARRAY) { return Class.forName(t.getDescriptor().replace('/', '.'), - false, - loader); + false, loader); } return Class.forName(t.getClassName(), false, loader); } catch (ClassNotFoundException e) { diff --git a/src/asm/scala/tools/asm/tree/analysis/SourceInterpreter.java b/src/asm/scala/tools/asm/tree/analysis/SourceInterpreter.java index 067200b51e..a68086c073 100644 --- a/src/asm/scala/tools/asm/tree/analysis/SourceInterpreter.java +++ b/src/asm/scala/tools/asm/tree/analysis/SourceInterpreter.java @@ -47,8 +47,7 @@ import scala.tools.asm.tree.MethodInsnNode; * @author Eric Bruneton */ public class SourceInterpreter extends Interpreter<SourceValue> implements - Opcodes -{ + Opcodes { public SourceInterpreter() { super(ASM4); @@ -70,125 +69,118 @@ public class SourceInterpreter extends Interpreter<SourceValue> implements public SourceValue newOperation(final AbstractInsnNode insn) { int size; switch (insn.getOpcode()) { - case LCONST_0: - case LCONST_1: - case DCONST_0: - case DCONST_1: - size = 2; - break; - case LDC: - Object cst = ((LdcInsnNode) insn).cst; - size = cst instanceof Long || cst instanceof Double ? 2 : 1; - break; - case GETSTATIC: - size = Type.getType(((FieldInsnNode) insn).desc).getSize(); - break; - default: - size = 1; + case LCONST_0: + case LCONST_1: + case DCONST_0: + case DCONST_1: + size = 2; + break; + case LDC: + Object cst = ((LdcInsnNode) insn).cst; + size = cst instanceof Long || cst instanceof Double ? 2 : 1; + break; + case GETSTATIC: + size = Type.getType(((FieldInsnNode) insn).desc).getSize(); + break; + default: + size = 1; } return new SourceValue(size, insn); } @Override - public SourceValue copyOperation(final AbstractInsnNode insn, final SourceValue value) { + public SourceValue copyOperation(final AbstractInsnNode insn, + final SourceValue value) { return new SourceValue(value.getSize(), insn); } @Override - public SourceValue unaryOperation(final AbstractInsnNode insn, final SourceValue value) - { + public SourceValue unaryOperation(final AbstractInsnNode insn, + final SourceValue value) { int size; switch (insn.getOpcode()) { - case LNEG: - case DNEG: - case I2L: - case I2D: - case L2D: - case F2L: - case F2D: - case D2L: - size = 2; - break; - case GETFIELD: - size = Type.getType(((FieldInsnNode) insn).desc).getSize(); - break; - default: - size = 1; + case LNEG: + case DNEG: + case I2L: + case I2D: + case L2D: + case F2L: + case F2D: + case D2L: + size = 2; + break; + case GETFIELD: + size = Type.getType(((FieldInsnNode) insn).desc).getSize(); + break; + default: + size = 1; } return new SourceValue(size, insn); } @Override - public SourceValue binaryOperation( - final AbstractInsnNode insn, - final SourceValue value1, - final SourceValue value2) - { + public SourceValue binaryOperation(final AbstractInsnNode insn, + final SourceValue value1, final SourceValue value2) { int size; switch (insn.getOpcode()) { - case LALOAD: - case DALOAD: - case LADD: - case DADD: - case LSUB: - case DSUB: - case LMUL: - case DMUL: - case LDIV: - case DDIV: - case LREM: - case DREM: - case LSHL: - case LSHR: - case LUSHR: - case LAND: - case LOR: - case LXOR: - size = 2; - break; - default: - size = 1; + case LALOAD: + case DALOAD: + case LADD: + case DADD: + case LSUB: + case DSUB: + case LMUL: + case DMUL: + case LDIV: + case DDIV: + case LREM: + case DREM: + case LSHL: + case LSHR: + case LUSHR: + case LAND: + case LOR: + case LXOR: + size = 2; + break; + default: + size = 1; } return new SourceValue(size, insn); } @Override - public SourceValue ternaryOperation( - final AbstractInsnNode insn, - final SourceValue value1, - final SourceValue value2, - final SourceValue value3) - { + public SourceValue ternaryOperation(final AbstractInsnNode insn, + final SourceValue value1, final SourceValue value2, + final SourceValue value3) { return new SourceValue(1, insn); } @Override - public SourceValue naryOperation(final AbstractInsnNode insn, final List<? extends SourceValue> values) { + public SourceValue naryOperation(final AbstractInsnNode insn, + final List<? extends SourceValue> values) { int size; int opcode = insn.getOpcode(); if (opcode == MULTIANEWARRAY) { size = 1; } else { - String desc = (opcode == INVOKEDYNAMIC)? - ((InvokeDynamicInsnNode) insn).desc: - ((MethodInsnNode) insn).desc; + String desc = (opcode == INVOKEDYNAMIC) ? ((InvokeDynamicInsnNode) insn).desc + : ((MethodInsnNode) insn).desc; size = Type.getReturnType(desc).getSize(); } return new SourceValue(size, insn); } @Override - public void returnOperation( - final AbstractInsnNode insn, - final SourceValue value, - final SourceValue expected) - { + public void returnOperation(final AbstractInsnNode insn, + final SourceValue value, final SourceValue expected) { } @Override public SourceValue merge(final SourceValue d, final SourceValue w) { if (d.insns instanceof SmallSet && w.insns instanceof SmallSet) { - Set<AbstractInsnNode> s = ((SmallSet<AbstractInsnNode>) d.insns).union((SmallSet<AbstractInsnNode>) w.insns); + Set<AbstractInsnNode> s = ((SmallSet<AbstractInsnNode>) d.insns) + .union((SmallSet<AbstractInsnNode>) w.insns); if (s == d.insns && d.size == w.size) { return d; } else { diff --git a/src/asm/scala/tools/asm/tree/analysis/SourceValue.java b/src/asm/scala/tools/asm/tree/analysis/SourceValue.java index 57ff212fb2..40d6b68180 100644 --- a/src/asm/scala/tools/asm/tree/analysis/SourceValue.java +++ b/src/asm/scala/tools/asm/tree/analysis/SourceValue.java @@ -48,8 +48,8 @@ public class SourceValue implements Value { /** * The instructions that can produce this value. For example, for the Java - * code below, the instructions that can produce the value of <tt>i</tt> - * at line 5 are the txo ISTORE instructions at line 1 and 3: + * code below, the instructions that can produce the value of <tt>i</tt> at + * line 5 are the txo ISTORE instructions at line 1 and 3: * * <pre> * 1: i = 0; @@ -64,7 +64,7 @@ public class SourceValue implements Value { public final Set<AbstractInsnNode> insns; public SourceValue(final int size) { - this(size, SmallSet.<AbstractInsnNode>emptySet()); + this(size, SmallSet.<AbstractInsnNode> emptySet()); } public SourceValue(final int size, final AbstractInsnNode insn) { @@ -84,7 +84,7 @@ public class SourceValue implements Value { @Override public boolean equals(final Object value) { if (!(value instanceof SourceValue)) { - return false; + return false; } SourceValue v = (SourceValue) value; return size == v.size && insns.equals(v.insns); diff --git a/src/asm/scala/tools/asm/tree/analysis/Subroutine.java b/src/asm/scala/tools/asm/tree/analysis/Subroutine.java index 038880ddcd..d734bbd499 100644 --- a/src/asm/scala/tools/asm/tree/analysis/Subroutine.java +++ b/src/asm/scala/tools/asm/tree/analysis/Subroutine.java @@ -51,11 +51,8 @@ class Subroutine { private Subroutine() { } - Subroutine( - final LabelNode start, - final int maxLocals, - final JumpInsnNode caller) - { + Subroutine(final LabelNode start, final int maxLocals, + final JumpInsnNode caller) { this.start = start; this.access = new boolean[maxLocals]; this.callers = new ArrayList<JumpInsnNode>(); @@ -90,4 +87,4 @@ class Subroutine { } return changes; } -}
\ No newline at end of file +} diff --git a/src/asm/scala/tools/asm/util/ASMifiable.java b/src/asm/scala/tools/asm/util/ASMifiable.java index 6a31dd508f..95cc6e3a74 100644 --- a/src/asm/scala/tools/asm/util/ASMifiable.java +++ b/src/asm/scala/tools/asm/util/ASMifiable.java @@ -34,7 +34,7 @@ import java.util.Map; import scala.tools.asm.Label; /** - * An {@link org.objectweb.asm.Attribute Attribute} that can print the ASM code + * An {@link scala.tools.asm.Attribute Attribute} that can print the ASM code * to create an equivalent attribute. * * @author Eugene Kuleshov @@ -44,10 +44,13 @@ public interface ASMifiable { /** * Prints the ASM code to create an attribute equal to this attribute. * - * @param buf a buffer used for printing Java code. - * @param varName name of the variable in a printed code used to store - * attribute instance. - * @param labelNames map of label instances to their names. + * @param buf + * a buffer used for printing Java code. + * @param varName + * name of the variable in a printed code used to store attribute + * instance. + * @param labelNames + * map of label instances to their names. */ void asmify(StringBuffer buf, String varName, Map<Label, String> labelNames); } diff --git a/src/asm/scala/tools/asm/util/ASMifier.java b/src/asm/scala/tools/asm/util/ASMifier.java index 5967c877d1..7e6b223853 100644 --- a/src/asm/scala/tools/asm/util/ASMifier.java +++ b/src/asm/scala/tools/asm/util/ASMifier.java @@ -91,11 +91,14 @@ public class ASMifier extends Printer { /** * Constructs a new {@link ASMifier}. * - * @param api the ASM API version implemented by this class. Must be one of - * {@link Opcodes#ASM4}. - * @param name the name of the visitor variable in the produced code. - * @param id identifier of the annotation visitor variable in the produced - * code. + * @param api + * the ASM API version implemented by this class. Must be one of + * {@link Opcodes#ASM4}. + * @param name + * the name of the visitor variable in the produced code. + * @param id + * identifier of the annotation visitor variable in the produced + * code. */ protected ASMifier(final int api, final String name, final int id) { super(api); @@ -105,13 +108,15 @@ public class ASMifier extends Printer { /** * Prints the ASM source code to generate the given class to the standard - * output. <p> Usage: ASMifier [-debug] <binary - * class name or class file name> + * output. + * <p> + * Usage: ASMifier [-debug] <binary class name or class file name> * - * @param args the command line arguments. + * @param args + * the command line arguments. * - * @throws Exception if the class cannot be found, or if an IO exception - * occurs. + * @throws Exception + * if the class cannot be found, or if an IO exception occurs. */ public static void main(final String[] args) throws Exception { int i = 0; @@ -129,22 +134,21 @@ public class ASMifier extends Printer { } } if (!ok) { - System.err.println("Prints the ASM code to generate the given class."); + System.err + .println("Prints the ASM code to generate the given class."); System.err.println("Usage: ASMifier [-debug] " + "<fully qualified class name or class file name>"); return; } ClassReader cr; if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1 - || args[i].indexOf('/') > -1) - { + || args[i].indexOf('/') > -1) { cr = new ClassReader(new FileInputStream(args[i])); } else { cr = new ClassReader(args[i]); } - cr.accept(new TraceClassVisitor(null, - new ASMifier(), - new PrintWriter(System.out)), flags); + cr.accept(new TraceClassVisitor(null, new ASMifier(), new PrintWriter( + System.out)), flags); } // ------------------------------------------------------------------------ @@ -152,14 +156,9 @@ public class ASMifier extends Printer { // ------------------------------------------------------------------------ @Override - public void visit( - final int version, - final int access, - final String name, - final String signature, - final String superName, - final String[] interfaces) - { + public void visit(final int version, final int access, final String name, + final String signature, final String superName, + final String[] interfaces) { String simpleName; int n = name.lastIndexOf('/'); if (n == -1) { @@ -170,8 +169,8 @@ public class ASMifier extends Printer { simpleName = name.substring(n + 1); } text.add("import java.util.*;\n"); - text.add("import org.objectweb.asm.*;\n"); - text.add("import org.objectweb.asm.attrs.*;\n"); + text.add("import scala.tools.asm.*;\n"); + text.add("import scala.tools.asm.attrs.*;\n"); text.add("public class " + simpleName + "Dump implements Opcodes {\n\n"); text.add("public static byte[] dump () throws Exception {\n\n"); text.add("ClassWriter cw = new ClassWriter(0);\n"); @@ -182,30 +181,30 @@ public class ASMifier extends Printer { buf.setLength(0); buf.append("cw.visit("); switch (version) { - case Opcodes.V1_1: - buf.append("V1_1"); - break; - case Opcodes.V1_2: - buf.append("V1_2"); - break; - case Opcodes.V1_3: - buf.append("V1_3"); - break; - case Opcodes.V1_4: - buf.append("V1_4"); - break; - case Opcodes.V1_5: - buf.append("V1_5"); - break; - case Opcodes.V1_6: - buf.append("V1_6"); - break; - case Opcodes.V1_7: - buf.append("V1_7"); - break; - default: - buf.append(version); - break; + case Opcodes.V1_1: + buf.append("V1_1"); + break; + case Opcodes.V1_2: + buf.append("V1_2"); + break; + case Opcodes.V1_3: + buf.append("V1_3"); + break; + case Opcodes.V1_4: + buf.append("V1_4"); + break; + case Opcodes.V1_5: + buf.append("V1_5"); + break; + case Opcodes.V1_6: + buf.append("V1_6"); + break; + case Opcodes.V1_7: + buf.append("V1_7"); + break; + default: + buf.append(version); + break; } buf.append(", "); appendAccess(access | ACCESS_CLASS); @@ -242,11 +241,8 @@ public class ASMifier extends Printer { } @Override - public void visitOuterClass( - final String owner, - final String name, - final String desc) - { + public void visitOuterClass(final String owner, final String name, + final String desc) { buf.setLength(0); buf.append("cw.visitOuterClass("); appendConstant(owner); @@ -259,10 +255,8 @@ public class ASMifier extends Printer { } @Override - public ASMifier visitClassAnnotation( - final String desc, - final boolean visible) - { + public ASMifier visitClassAnnotation(final String desc, + final boolean visible) { return visitAnnotation(desc, visible); } @@ -272,12 +266,8 @@ public class ASMifier extends Printer { } @Override - public void visitInnerClass( - final String name, - final String outerName, - final String innerName, - final int access) - { + public void visitInnerClass(final String name, final String outerName, + final String innerName, final int access) { buf.setLength(0); buf.append("cw.visitInnerClass("); appendConstant(name); @@ -292,13 +282,8 @@ public class ASMifier extends Printer { } @Override - public ASMifier visitField( - final int access, - final String name, - final String desc, - final String signature, - final Object value) - { + public ASMifier visitField(final int access, final String name, + final String desc, final String signature, final Object value) { buf.setLength(0); buf.append("{\n"); buf.append("fv = cw.visitField("); @@ -320,13 +305,8 @@ public class ASMifier extends Printer { } @Override - public ASMifier visitMethod( - final int access, - final String name, - final String desc, - final String signature, - final String[] exceptions) - { + public ASMifier visitMethod(final int access, final String name, + final String desc, final String signature, final String[] exceptions) { buf.setLength(0); buf.append("{\n"); buf.append("mv = cw.visitMethod("); @@ -380,11 +360,8 @@ public class ASMifier extends Printer { } @Override - public void visitEnum( - final String name, - final String desc, - final String value) - { + public void visitEnum(final String name, final String desc, + final String value) { buf.setLength(0); buf.append("av").append(id).append(".visitEnum("); appendConstant(buf, name); @@ -397,10 +374,7 @@ public class ASMifier extends Printer { } @Override - public ASMifier visitAnnotation( - final String name, - final String desc) - { + public ASMifier visitAnnotation(final String name, final String desc) { buf.setLength(0); buf.append("{\n"); buf.append("AnnotationVisitor av").append(id + 1).append(" = av"); @@ -443,10 +417,8 @@ public class ASMifier extends Printer { // ------------------------------------------------------------------------ @Override - public ASMifier visitFieldAnnotation( - final String desc, - final boolean visible) - { + public ASMifier visitFieldAnnotation(final String desc, + final boolean visible) { return visitAnnotation(desc, visible); } @@ -469,9 +441,7 @@ public class ASMifier extends Printer { @Override public ASMifier visitAnnotationDefault() { buf.setLength(0); - buf.append("{\n") - .append("av0 = ") - .append(name) + buf.append("{\n").append("av0 = ").append(name) .append(".visitAnnotationDefault();\n"); text.add(buf.toString()); ASMifier a = createASMifier("av", 0); @@ -481,23 +451,17 @@ public class ASMifier extends Printer { } @Override - public ASMifier visitMethodAnnotation( - final String desc, - final boolean visible) - { + public ASMifier visitMethodAnnotation(final String desc, + final boolean visible) { return visitAnnotation(desc, visible); } @Override - public ASMifier visitParameterAnnotation( - final int parameter, - final String desc, - final boolean visible) - { + public ASMifier visitParameterAnnotation(final int parameter, + final String desc, final boolean visible) { buf.setLength(0); - buf.append("{\n") - .append("av0 = ").append(name).append(".visitParameterAnnotation(") - .append(parameter) + buf.append("{\n").append("av0 = ").append(name) + .append(".visitParameterAnnotation(").append(parameter) .append(", "); appendConstant(desc); buf.append(", ").append(visible).append(");\n"); @@ -519,52 +483,47 @@ public class ASMifier extends Printer { } @Override - public void visitFrame( - final int type, - final int nLocal, - final Object[] local, - final int nStack, - final Object[] stack) - { + public void visitFrame(final int type, final int nLocal, + final Object[] local, final int nStack, final Object[] stack) { buf.setLength(0); switch (type) { - case Opcodes.F_NEW: - case Opcodes.F_FULL: - declareFrameTypes(nLocal, local); - declareFrameTypes(nStack, stack); - if (type == Opcodes.F_NEW) { - buf.append(name).append(".visitFrame(Opcodes.F_NEW, "); - } else { - buf.append(name).append(".visitFrame(Opcodes.F_FULL, "); - } - buf.append(nLocal).append(", new Object[] {"); - appendFrameTypes(nLocal, local); - buf.append("}, ").append(nStack).append(", new Object[] {"); - appendFrameTypes(nStack, stack); - buf.append('}'); - break; - case Opcodes.F_APPEND: - declareFrameTypes(nLocal, local); - buf.append(name).append(".visitFrame(Opcodes.F_APPEND,") - .append(nLocal) - .append(", new Object[] {"); - appendFrameTypes(nLocal, local); - buf.append("}, 0, null"); - break; - case Opcodes.F_CHOP: - buf.append(name).append(".visitFrame(Opcodes.F_CHOP,") - .append(nLocal) - .append(", null, 0, null"); - break; - case Opcodes.F_SAME: - buf.append(name).append(".visitFrame(Opcodes.F_SAME, 0, null, 0, null"); - break; - case Opcodes.F_SAME1: - declareFrameTypes(1, stack); - buf.append(name).append(".visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"); - appendFrameTypes(1, stack); - buf.append('}'); - break; + case Opcodes.F_NEW: + case Opcodes.F_FULL: + declareFrameTypes(nLocal, local); + declareFrameTypes(nStack, stack); + if (type == Opcodes.F_NEW) { + buf.append(name).append(".visitFrame(Opcodes.F_NEW, "); + } else { + buf.append(name).append(".visitFrame(Opcodes.F_FULL, "); + } + buf.append(nLocal).append(", new Object[] {"); + appendFrameTypes(nLocal, local); + buf.append("}, ").append(nStack).append(", new Object[] {"); + appendFrameTypes(nStack, stack); + buf.append('}'); + break; + case Opcodes.F_APPEND: + declareFrameTypes(nLocal, local); + buf.append(name).append(".visitFrame(Opcodes.F_APPEND,") + .append(nLocal).append(", new Object[] {"); + appendFrameTypes(nLocal, local); + buf.append("}, 0, null"); + break; + case Opcodes.F_CHOP: + buf.append(name).append(".visitFrame(Opcodes.F_CHOP,") + .append(nLocal).append(", null, 0, null"); + break; + case Opcodes.F_SAME: + buf.append(name).append( + ".visitFrame(Opcodes.F_SAME, 0, null, 0, null"); + break; + case Opcodes.F_SAME1: + declareFrameTypes(1, stack); + buf.append(name).append( + ".visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"); + appendFrameTypes(1, stack); + buf.append('}'); + break; } buf.append(");\n"); text.add(buf.toString()); @@ -573,7 +532,8 @@ public class ASMifier extends Printer { @Override public void visitInsn(final int opcode) { buf.setLength(0); - buf.append(name).append(".visitInsn(").append(OPCODES[opcode]).append(");\n"); + buf.append(name).append(".visitInsn(").append(OPCODES[opcode]) + .append(");\n"); text.add(buf.toString()); } @@ -584,43 +544,35 @@ public class ASMifier extends Printer { .append(".visitIntInsn(") .append(OPCODES[opcode]) .append(", ") - .append(opcode == Opcodes.NEWARRAY - ? TYPES[operand] - : Integer.toString(operand)) - .append(");\n"); + .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer + .toString(operand)).append(");\n"); text.add(buf.toString()); } @Override public void visitVarInsn(final int opcode, final int var) { buf.setLength(0); - buf.append(name) - .append(".visitVarInsn(") - .append(OPCODES[opcode]) - .append(", ") - .append(var) - .append(");\n"); + buf.append(name).append(".visitVarInsn(").append(OPCODES[opcode]) + .append(", ").append(var).append(");\n"); text.add(buf.toString()); } @Override public void visitTypeInsn(final int opcode, final String type) { buf.setLength(0); - buf.append(name).append(".visitTypeInsn(").append(OPCODES[opcode]).append(", "); + buf.append(name).append(".visitTypeInsn(").append(OPCODES[opcode]) + .append(", "); appendConstant(type); buf.append(");\n"); text.add(buf.toString()); } @Override - public void visitFieldInsn( - final int opcode, - final String owner, - final String name, - final String desc) - { + public void visitFieldInsn(final int opcode, final String owner, + final String name, final String desc) { buf.setLength(0); - buf.append(this.name).append(".visitFieldInsn(").append(OPCODES[opcode]).append(", "); + buf.append(this.name).append(".visitFieldInsn(") + .append(OPCODES[opcode]).append(", "); appendConstant(owner); buf.append(", "); appendConstant(name); @@ -631,14 +583,11 @@ public class ASMifier extends Printer { } @Override - public void visitMethodInsn( - final int opcode, - final String owner, - final String name, - final String desc) - { + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { buf.setLength(0); - buf.append(this.name).append(".visitMethodInsn(").append(OPCODES[opcode]).append(", "); + buf.append(this.name).append(".visitMethodInsn(") + .append(OPCODES[opcode]).append(", "); appendConstant(owner); buf.append(", "); appendConstant(name); @@ -649,12 +598,8 @@ public class ASMifier extends Printer { } @Override - public void visitInvokeDynamicInsn( - String name, - String desc, - Handle bsm, - Object... bsmArgs) - { + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, + Object... bsmArgs) { buf.setLength(0); buf.append(this.name).append(".visitInvokeDynamicInsn("); appendConstant(name); @@ -677,7 +622,8 @@ public class ASMifier extends Printer { public void visitJumpInsn(final int opcode, final Label label) { buf.setLength(0); declareLabel(label); - buf.append(name).append(".visitJumpInsn(").append(OPCODES[opcode]).append(", "); + buf.append(name).append(".visitJumpInsn(").append(OPCODES[opcode]) + .append(", "); appendLabel(label); buf.append(");\n"); text.add(buf.toString()); @@ -705,34 +651,22 @@ public class ASMifier extends Printer { @Override public void visitIincInsn(final int var, final int increment) { buf.setLength(0); - buf.append(name) - .append(".visitIincInsn(") - .append(var) - .append(", ") - .append(increment) - .append(");\n"); + buf.append(name).append(".visitIincInsn(").append(var).append(", ") + .append(increment).append(");\n"); text.add(buf.toString()); } @Override - public void visitTableSwitchInsn( - final int min, - final int max, - final Label dflt, - final Label... labels) - { + public void visitTableSwitchInsn(final int min, final int max, + final Label dflt, final Label... labels) { buf.setLength(0); for (int i = 0; i < labels.length; ++i) { declareLabel(labels[i]); } declareLabel(dflt); - buf.append(name) - .append(".visitTableSwitchInsn(") - .append(min) - .append(", ") - .append(max) - .append(", "); + buf.append(name).append(".visitTableSwitchInsn(").append(min) + .append(", ").append(max).append(", "); appendLabel(dflt); buf.append(", new Label[] {"); for (int i = 0; i < labels.length; ++i) { @@ -744,11 +678,8 @@ public class ASMifier extends Printer { } @Override - public void visitLookupSwitchInsn( - final Label dflt, - final int[] keys, - final Label[] labels) - { + public void visitLookupSwitchInsn(final Label dflt, final int[] keys, + final Label[] labels) { buf.setLength(0); for (int i = 0; i < labels.length; ++i) { declareLabel(labels[i]); @@ -780,12 +711,8 @@ public class ASMifier extends Printer { } @Override - public void visitTryCatchBlock( - final Label start, - final Label end, - final Label handler, - final String type) - { + public void visitTryCatchBlock(final Label start, final Label end, + final Label handler, final String type) { buf.setLength(0); declareLabel(start); declareLabel(end); @@ -803,14 +730,9 @@ public class ASMifier extends Printer { } @Override - public void visitLocalVariable( - final String name, - final String desc, - final String signature, - final Label start, - final Label end, - final int index) - { + public void visitLocalVariable(final String name, final String desc, + final String signature, final Label start, final Label end, + final int index) { buf.setLength(0); buf.append(this.name).append(".visitLocalVariable("); appendConstant(name); @@ -838,12 +760,8 @@ public class ASMifier extends Printer { @Override public void visitMaxs(final int maxStack, final int maxLocals) { buf.setLength(0); - buf.append(name) - .append(".visitMaxs(") - .append(maxStack) - .append(", ") - .append(maxLocals) - .append(");\n"); + buf.append(name).append(".visitMaxs(").append(maxStack).append(", ") + .append(maxLocals).append(");\n"); text.add(buf.toString()); } @@ -858,14 +776,9 @@ public class ASMifier extends Printer { // Common methods // ------------------------------------------------------------------------ - public ASMifier visitAnnotation( - final String desc, - final boolean visible) - { + public ASMifier visitAnnotation(final String desc, final boolean visible) { buf.setLength(0); - buf.append("{\n") - .append("av0 = ") - .append(name) + buf.append("{\n").append("av0 = ").append(name) .append(".visitAnnotation("); appendConstant(desc); buf.append(", ").append(visible).append(");\n"); @@ -895,15 +808,16 @@ public class ASMifier extends Printer { // Utility methods // ------------------------------------------------------------------------ - protected ASMifier createASMifier(final String name, final int id) { + protected ASMifier createASMifier(final String name, final int id) { return new ASMifier(Opcodes.ASM4, name, id); } /** - * Appends a string representation of the given access modifiers to {@link - * #buf buf}. + * Appends a string representation of the given access modifiers to + * {@link #buf buf}. * - * @param access some access modifiers. + * @param access + * some access modifiers. */ void appendAccess(final int access) { boolean first = true; @@ -945,8 +859,7 @@ public class ASMifier extends Printer { first = false; } if ((access & Opcodes.ACC_VOLATILE) != 0 - && (access & ACCESS_FIELD) != 0) - { + && (access & ACCESS_FIELD) != 0) { if (!first) { buf.append(" + "); } @@ -954,8 +867,7 @@ public class ASMifier extends Printer { first = false; } if ((access & Opcodes.ACC_BRIDGE) != 0 && (access & ACCESS_CLASS) == 0 - && (access & ACCESS_FIELD) == 0) - { + && (access & ACCESS_FIELD) == 0) { if (!first) { buf.append(" + "); } @@ -963,8 +875,7 @@ public class ASMifier extends Printer { first = false; } if ((access & Opcodes.ACC_VARARGS) != 0 && (access & ACCESS_CLASS) == 0 - && (access & ACCESS_FIELD) == 0) - { + && (access & ACCESS_FIELD) == 0) { if (!first) { buf.append(" + "); } @@ -972,8 +883,7 @@ public class ASMifier extends Printer { first = false; } if ((access & Opcodes.ACC_TRANSIENT) != 0 - && (access & ACCESS_FIELD) != 0) - { + && (access & ACCESS_FIELD) != 0) { if (!first) { buf.append(" + "); } @@ -981,8 +891,7 @@ public class ASMifier extends Printer { first = false; } if ((access & Opcodes.ACC_NATIVE) != 0 && (access & ACCESS_CLASS) == 0 - && (access & ACCESS_FIELD) == 0) - { + && (access & ACCESS_FIELD) == 0) { if (!first) { buf.append(" + "); } @@ -991,8 +900,7 @@ public class ASMifier extends Printer { } if ((access & Opcodes.ACC_ENUM) != 0 && ((access & ACCESS_CLASS) != 0 - || (access & ACCESS_FIELD) != 0 || (access & ACCESS_INNER) != 0)) - { + || (access & ACCESS_FIELD) != 0 || (access & ACCESS_INNER) != 0)) { if (!first) { buf.append(" + "); } @@ -1000,8 +908,7 @@ public class ASMifier extends Printer { first = false; } if ((access & Opcodes.ACC_ANNOTATION) != 0 - && ((access & ACCESS_CLASS) != 0 || (access & ACCESS_INNER) != 0)) - { + && ((access & ACCESS_CLASS) != 0 || (access & ACCESS_INNER) != 0)) { if (!first) { buf.append(" + "); } @@ -1052,8 +959,9 @@ public class ASMifier extends Printer { * Appends a string representation of the given constant to the given * buffer. * - * @param cst an {@link Integer}, {@link Float}, {@link Long}, - * {@link Double} or {@link String} object. May be <tt>null</tt>. + * @param cst + * an {@link Integer}, {@link Float}, {@link Long}, + * {@link Double} or {@link String} object. May be <tt>null</tt>. */ protected void appendConstant(final Object cst) { appendConstant(buf, cst); @@ -1063,9 +971,11 @@ public class ASMifier extends Printer { * Appends a string representation of the given constant to the given * buffer. * - * @param buf a string buffer. - * @param cst an {@link Integer}, {@link Float}, {@link Long}, - * {@link Double} or {@link String} object. May be <tt>null</tt>. + * @param buf + * a string buffer. + * @param cst + * an {@link Integer}, {@link Float}, {@link Long}, + * {@link Double} or {@link String} object. May be <tt>null</tt>. */ static void appendConstant(final StringBuffer buf, final Object cst) { if (cst == null) { @@ -1079,14 +989,16 @@ public class ASMifier extends Printer { } else if (cst instanceof Handle) { buf.append("new Handle("); Handle h = (Handle) cst; - buf.append("Opcodes.").append(HANDLE_TAG[h.getTag()]).append(", \""); + buf.append("Opcodes.").append(HANDLE_TAG[h.getTag()]) + .append(", \""); buf.append(h.getOwner()).append("\", \""); buf.append(h.getName()).append("\", \""); buf.append(h.getDesc()).append("\")"); } else if (cst instanceof Byte) { buf.append("new Byte((byte)").append(cst).append(')'); } else if (cst instanceof Boolean) { - buf.append(((Boolean) cst).booleanValue() ? "Boolean.TRUE" : "Boolean.FALSE"); + buf.append(((Boolean) cst).booleanValue() ? "Boolean.TRUE" + : "Boolean.FALSE"); } else if (cst instanceof Short) { buf.append("new Short((short)").append(cst).append(')'); } else if (cst instanceof Character) { @@ -1125,8 +1037,7 @@ public class ASMifier extends Printer { char[] v = (char[]) cst; buf.append("new char[] {"); for (int i = 0; i < v.length; i++) { - buf.append(i == 0 ? "" : ",") - .append("(char)") + buf.append(i == 0 ? "" : ",").append("(char)") .append((int) v[i]); } buf.append('}'); @@ -1178,27 +1089,27 @@ public class ASMifier extends Printer { appendConstant(o[i]); } else if (o[i] instanceof Integer) { switch (((Integer) o[i]).intValue()) { - case 0: - buf.append("Opcodes.TOP"); - break; - case 1: - buf.append("Opcodes.INTEGER"); - break; - case 2: - buf.append("Opcodes.FLOAT"); - break; - case 3: - buf.append("Opcodes.DOUBLE"); - break; - case 4: - buf.append("Opcodes.LONG"); - break; - case 5: - buf.append("Opcodes.NULL"); - break; - case 6: - buf.append("Opcodes.UNINITIALIZED_THIS"); - break; + case 0: + buf.append("Opcodes.TOP"); + break; + case 1: + buf.append("Opcodes.INTEGER"); + break; + case 2: + buf.append("Opcodes.FLOAT"); + break; + case 3: + buf.append("Opcodes.DOUBLE"); + break; + case 4: + buf.append("Opcodes.LONG"); + break; + case 5: + buf.append("Opcodes.NULL"); + break; + case 6: + buf.append("Opcodes.UNINITIALIZED_THIS"); + break; } } else { appendLabel((Label) o[i]); @@ -1211,7 +1122,8 @@ public class ASMifier extends Printer { * declaration is of the form "Label lXXX = new Label();". Does nothing if * the given label has already been declared. * - * @param l a label. + * @param l + * a label. */ protected void declareLabel(final Label l) { if (labelNames == null) { @@ -1227,10 +1139,11 @@ public class ASMifier extends Printer { /** * Appends the name of the given label to {@link #buf buf}. The given label - * <i>must</i> already have a name. One way to ensure this is to always - * call {@link #declareLabel declared} before calling this method. + * <i>must</i> already have a name. One way to ensure this is to always call + * {@link #declareLabel declared} before calling this method. * - * @param l a label. + * @param l + * a label. */ protected void appendLabel(final Label l) { buf.append(labelNames.get(l)); diff --git a/src/asm/scala/tools/asm/util/CheckAnnotationAdapter.java b/src/asm/scala/tools/asm/util/CheckAnnotationAdapter.java index 8030c14f2e..f00a8f04a2 100644 --- a/src/asm/scala/tools/asm/util/CheckAnnotationAdapter.java +++ b/src/asm/scala/tools/asm/util/CheckAnnotationAdapter.java @@ -65,8 +65,7 @@ public class CheckAnnotationAdapter extends AnnotationVisitor { || value instanceof byte[] || value instanceof boolean[] || value instanceof char[] || value instanceof short[] || value instanceof int[] || value instanceof long[] - || value instanceof float[] || value instanceof double[])) - { + || value instanceof float[] || value instanceof double[])) { throw new IllegalArgumentException("Invalid annotation value"); } if (value instanceof Type) { @@ -81,11 +80,8 @@ public class CheckAnnotationAdapter extends AnnotationVisitor { } @Override - public void visitEnum( - final String name, - final String desc, - final String value) - { + public void visitEnum(final String name, final String desc, + final String value) { checkEnd(); checkName(name); CheckMethodAdapter.checkDesc(desc, false); @@ -98,15 +94,12 @@ public class CheckAnnotationAdapter extends AnnotationVisitor { } @Override - public AnnotationVisitor visitAnnotation( - final String name, - final String desc) - { + public AnnotationVisitor visitAnnotation(final String name, + final String desc) { checkEnd(); checkName(name); CheckMethodAdapter.checkDesc(desc, false); - return new CheckAnnotationAdapter(av == null - ? null + return new CheckAnnotationAdapter(av == null ? null : av.visitAnnotation(name, desc)); } @@ -114,8 +107,7 @@ public class CheckAnnotationAdapter extends AnnotationVisitor { public AnnotationVisitor visitArray(final String name) { checkEnd(); checkName(name); - return new CheckAnnotationAdapter(av == null - ? null + return new CheckAnnotationAdapter(av == null ? null : av.visitArray(name), false); } @@ -130,13 +122,15 @@ public class CheckAnnotationAdapter extends AnnotationVisitor { private void checkEnd() { if (end) { - throw new IllegalStateException("Cannot call a visit method after visitEnd has been called"); + throw new IllegalStateException( + "Cannot call a visit method after visitEnd has been called"); } } private void checkName(final String name) { if (named && name == null) { - throw new IllegalArgumentException("Annotation value name must not be null"); + throw new IllegalArgumentException( + "Annotation value name must not be null"); } } } diff --git a/src/asm/scala/tools/asm/util/CheckClassAdapter.java b/src/asm/scala/tools/asm/util/CheckClassAdapter.java index a455322531..0bfa143a95 100644 --- a/src/asm/scala/tools/asm/util/CheckClassAdapter.java +++ b/src/asm/scala/tools/asm/util/CheckClassAdapter.java @@ -59,10 +59,10 @@ import scala.tools.asm.tree.analysis.SimpleVerifier; * <i>only</i> on its arguments, but does <i>not</i> check the <i>sequence</i> * of method calls. For example, the invalid sequence * <tt>visitField(ACC_PUBLIC, "i", "I", null)</tt> <tt>visitField(ACC_PUBLIC, - * "i", "D", null)</tt> - * will <i>not</i> be detected by this class adapter. + * "i", "D", null)</tt> will <i>not</i> be detected by this class adapter. * - * <p><code>CheckClassAdapter</code> can be also used to verify bytecode + * <p> + * <code>CheckClassAdapter</code> can be also used to verify bytecode * transformations in order to make sure transformed bytecode is sane. For * example: * @@ -80,19 +80,20 @@ import scala.tools.asm.tree.analysis.SimpleVerifier; * </pre> * * Above code runs transformed bytecode trough the - * <code>CheckClassAdapter</code>. It won't be exactly the same verification - * as JVM does, but it run data flow analysis for the code of each method and + * <code>CheckClassAdapter</code>. It won't be exactly the same verification as + * JVM does, but it run data flow analysis for the code of each method and * checks that expectations are met for each method instruction. * - * <p>If method bytecode has errors, assertion text will show the erroneous + * <p> + * If method bytecode has errors, assertion text will show the erroneous * instruction number and dump of the failed method with information about * locals and stack slot for each instruction. For example (format is - * insnNumber locals : stack): * * <pre> - * org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 71: Expected I, but found . - * at org.objectweb.asm.tree.analysis.Analyzer.analyze(Analyzer.java:289) - * at org.objectweb.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:135) + * scala.tools.asm.tree.analysis.AnalyzerException: Error at instruction 71: Expected I, but found . + * at scala.tools.asm.tree.analysis.Analyzer.analyze(Analyzer.java:289) + * at scala.tools.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:135) * ... * remove()V * 00000 LinkedBlockingQueue$Itr . . . . . . . . : @@ -114,8 +115,9 @@ import scala.tools.asm.tree.analysis.SimpleVerifier; * initialized. You can also see that at the beginning of the method (code * inserted by the transformation) variable 2 is initialized. * - * <p>Note that when used like that, <code>CheckClassAdapter.verify()</code> - * can trigger additional class loading, because it is using + * <p> + * Note that when used like that, <code>CheckClassAdapter.verify()</code> can + * trigger additional class loading, because it is using * <code>SimpleVerifier</code>. * * @author Eric Bruneton @@ -159,13 +161,15 @@ public class CheckClassAdapter extends ClassVisitor { private boolean checkDataFlow; /** - * Checks a given class. <p> Usage: CheckClassAdapter <binary - * class name or class file name> + * Checks a given class. + * <p> + * Usage: CheckClassAdapter <binary class name or class file name> * - * @param args the command line arguments. + * @param args + * the command line arguments. * - * @throws Exception if the class cannot be found, or if an IO exception - * occurs. + * @throws Exception + * if the class cannot be found, or if an IO exception occurs. */ public static void main(final String[] args) throws Exception { if (args.length != 1) { @@ -187,27 +191,26 @@ public class CheckClassAdapter extends ClassVisitor { /** * Checks a given class. * - * @param cr a <code>ClassReader</code> that contains bytecode for the - * analysis. - * @param loader a <code>ClassLoader</code> which will be used to load - * referenced classes. This is useful if you are verifiying multiple - * interdependent classes. - * @param dump true if bytecode should be printed out not only when errors - * are found. - * @param pw write where results going to be printed + * @param cr + * a <code>ClassReader</code> that contains bytecode for the + * analysis. + * @param loader + * a <code>ClassLoader</code> which will be used to load + * referenced classes. This is useful if you are verifiying + * multiple interdependent classes. + * @param dump + * true if bytecode should be printed out not only when errors + * are found. + * @param pw + * write where results going to be printed */ - public static void verify( - final ClassReader cr, - final ClassLoader loader, - final boolean dump, - final PrintWriter pw) - { + public static void verify(final ClassReader cr, final ClassLoader loader, + final boolean dump, final PrintWriter pw) { ClassNode cn = new ClassNode(); cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG); - Type syperType = cn.superName == null - ? null - : Type.getObjectType(cn.superName); + Type syperType = cn.superName == null ? null : Type + .getObjectType(cn.superName); List<MethodNode> methods = cn.methods; List<Type> interfaces = new ArrayList<Type>(); @@ -217,9 +220,8 @@ public class CheckClassAdapter extends ClassVisitor { for (int i = 0; i < methods.size(); ++i) { MethodNode method = methods.get(i); - SimpleVerifier verifier = new SimpleVerifier(Type.getObjectType(cn.name), - syperType, - interfaces, + SimpleVerifier verifier = new SimpleVerifier( + Type.getObjectType(cn.name), syperType, interfaces, (cn.access & Opcodes.ACC_INTERFACE) != 0); Analyzer<BasicValue> a = new Analyzer<BasicValue>(verifier); if (loader != null) { @@ -241,25 +243,22 @@ public class CheckClassAdapter extends ClassVisitor { /** * Checks a given class * - * @param cr a <code>ClassReader</code> that contains bytecode for the - * analysis. - * @param dump true if bytecode should be printed out not only when errors - * are found. - * @param pw write where results going to be printed + * @param cr + * a <code>ClassReader</code> that contains bytecode for the + * analysis. + * @param dump + * true if bytecode should be printed out not only when errors + * are found. + * @param pw + * write where results going to be printed */ - public static void verify( - final ClassReader cr, - final boolean dump, - final PrintWriter pw) - { + public static void verify(final ClassReader cr, final boolean dump, + final PrintWriter pw) { verify(cr, null, dump, pw); } - static void printAnalyzerResult( - MethodNode method, - Analyzer<BasicValue> a, - final PrintWriter pw) - { + static void printAnalyzerResult(MethodNode method, Analyzer<BasicValue> a, + final PrintWriter pw) { Frame<BasicValue>[] frames = a.getFrames(); Textifier t = new Textifier(); TraceMethodVisitor mv = new TraceMethodVisitor(t); @@ -310,7 +309,8 @@ public class CheckClassAdapter extends ClassVisitor { * this constructor</i>. Instead, they must use the * {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version. * - * @param cv the class visitor to which this adapter must delegate calls. + * @param cv + * the class visitor to which this adapter must delegate calls. */ public CheckClassAdapter(final ClassVisitor cv) { this(cv, true); @@ -321,33 +321,34 @@ public class CheckClassAdapter extends ClassVisitor { * this constructor</i>. Instead, they must use the * {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version. * - * @param cv the class visitor to which this adapter must delegate calls. - * @param checkDataFlow <tt>true</tt> to perform basic data flow checks, or - * <tt>false</tt> to not perform any data flow check (see - * {@link CheckMethodAdapter}). This option requires valid maxLocals - * and maxStack values. + * @param cv + * the class visitor to which this adapter must delegate calls. + * @param checkDataFlow + * <tt>true</tt> to perform basic data flow checks, or + * <tt>false</tt> to not perform any data flow check (see + * {@link CheckMethodAdapter}). This option requires valid + * maxLocals and maxStack values. */ - public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) - { + public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) { this(Opcodes.ASM4, cv, checkDataFlow); } /** * Constructs a new {@link CheckClassAdapter}. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. - * @param cv the class visitor to which this adapter must delegate calls. - * @param checkDataFlow <tt>true</tt> to perform basic data flow checks, or - * <tt>false</tt> to not perform any data flow check (see - * {@link CheckMethodAdapter}). This option requires valid maxLocals - * and maxStack values. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param cv + * the class visitor to which this adapter must delegate calls. + * @param checkDataFlow + * <tt>true</tt> to perform basic data flow checks, or + * <tt>false</tt> to not perform any data flow check (see + * {@link CheckMethodAdapter}). This option requires valid + * maxLocals and maxStack values. */ - protected CheckClassAdapter( - final int api, - final ClassVisitor cv, - final boolean checkDataFlow) - { + protected CheckClassAdapter(final int api, final ClassVisitor cv, + final boolean checkDataFlow) { super(api, cv); this.labels = new HashMap<Label, Integer>(); this.checkDataFlow = checkDataFlow; @@ -358,14 +359,9 @@ public class CheckClassAdapter extends ClassVisitor { // ------------------------------------------------------------------------ @Override - public void visit( - final int version, - final int access, - final String name, - final String signature, - final String superName, - final String[] interfaces) - { + public void visit(final int version, final int access, final String name, + final String signature, final String superName, + final String[] interfaces) { if (start) { throw new IllegalStateException("visit must be called only once"); } @@ -375,24 +371,25 @@ public class CheckClassAdapter extends ClassVisitor { + Opcodes.ACC_SUPER + Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM - + Opcodes.ACC_DEPRECATED - + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE + + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE if (name == null || !name.endsWith("package-info")) { CheckMethodAdapter.checkInternalName(name, "class name"); } if ("java/lang/Object".equals(name)) { if (superName != null) { - throw new IllegalArgumentException("The super class name of the Object class must be 'null'"); + throw new IllegalArgumentException( + "The super class name of the Object class must be 'null'"); } } else { CheckMethodAdapter.checkInternalName(superName, "super class name"); } if (signature != null) { - CheckMethodAdapter.checkClassSignature(signature); + checkClassSignature(signature); } if ((access & Opcodes.ACC_INTERFACE) != 0) { if (!"java/lang/Object".equals(superName)) { - throw new IllegalArgumentException("The super class name of interfaces must be 'java/lang/Object'"); + throw new IllegalArgumentException( + "The super class name of interfaces must be 'java/lang/Object'"); } } if (interfaces != null) { @@ -409,21 +406,20 @@ public class CheckClassAdapter extends ClassVisitor { public void visitSource(final String file, final String debug) { checkState(); if (source) { - throw new IllegalStateException("visitSource can be called only once."); + throw new IllegalStateException( + "visitSource can be called only once."); } source = true; super.visitSource(file, debug); } @Override - public void visitOuterClass( - final String owner, - final String name, - final String desc) - { + public void visitOuterClass(final String owner, final String name, + final String desc) { checkState(); if (outer) { - throw new IllegalStateException("visitOuterClass can be called only once."); + throw new IllegalStateException( + "visitOuterClass can be called only once."); } outer = true; if (owner == null) { @@ -436,12 +432,8 @@ public class CheckClassAdapter extends ClassVisitor { } @Override - public void visitInnerClass( - final String name, - final String outerName, - final String innerName, - final int access) - { + public void visitInnerClass(final String name, final String outerName, + final String innerName, final int access) { checkState(); CheckMethodAdapter.checkInternalName(name, "class name"); if (outerName != null) { @@ -459,52 +451,44 @@ public class CheckClassAdapter extends ClassVisitor { } @Override - public FieldVisitor visitField( - final int access, - final String name, - final String desc, - final String signature, - final Object value) - { + public FieldVisitor visitField(final int access, final String name, + final String desc, final String signature, final Object value) { checkState(); checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL + Opcodes.ACC_VOLATILE + Opcodes.ACC_TRANSIENT + Opcodes.ACC_SYNTHETIC - + Opcodes.ACC_ENUM + Opcodes.ACC_DEPRECATED - + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE + + Opcodes.ACC_ENUM + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE CheckMethodAdapter.checkUnqualifiedName(version, name, "field name"); CheckMethodAdapter.checkDesc(desc, false); if (signature != null) { - CheckMethodAdapter.checkFieldSignature(signature); + checkFieldSignature(signature); } if (value != null) { CheckMethodAdapter.checkConstant(value); } - FieldVisitor av = super.visitField(access, name, desc, signature, value); + FieldVisitor av = super + .visitField(access, name, desc, signature, value); return new CheckFieldAdapter(av); } @Override - public MethodVisitor visitMethod( - final int access, - final String name, - final String desc, - final String signature, - final String[] exceptions) - { + public MethodVisitor visitMethod(final int access, final String name, + final String desc, final String signature, final String[] exceptions) { checkState(); checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL + Opcodes.ACC_SYNCHRONIZED + Opcodes.ACC_BRIDGE + Opcodes.ACC_VARARGS + Opcodes.ACC_NATIVE + Opcodes.ACC_ABSTRACT + Opcodes.ACC_STRICT - + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_DEPRECATED - + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE - CheckMethodAdapter.checkMethodIdentifier(version, name, "method name"); + + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE + if (!"<init>".equals(name) && !"<clinit>".equals(name)) { + CheckMethodAdapter.checkMethodIdentifier(version, name, + "method name"); + } CheckMethodAdapter.checkMethodDesc(desc); if (signature != null) { - CheckMethodAdapter.checkMethodSignature(signature); + checkMethodSignature(signature); } if (exceptions != null) { for (int i = 0; i < exceptions.length; ++i) { @@ -514,27 +498,19 @@ public class CheckClassAdapter extends ClassVisitor { } CheckMethodAdapter cma; if (checkDataFlow) { - cma = new CheckMethodAdapter(access, - name, - desc, - super.visitMethod(access, name, desc, signature, exceptions), - labels); + cma = new CheckMethodAdapter(access, name, desc, super.visitMethod( + access, name, desc, signature, exceptions), labels); } else { - cma = new CheckMethodAdapter(super.visitMethod(access, - name, - desc, - signature, - exceptions), labels); + cma = new CheckMethodAdapter(super.visitMethod(access, name, desc, + signature, exceptions), labels); } cma.version = version; return cma; } @Override - public AnnotationVisitor visitAnnotation( - final String desc, - final boolean visible) - { + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { checkState(); CheckMethodAdapter.checkDesc(desc, false); return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible)); @@ -544,7 +520,8 @@ public class CheckClassAdapter extends ClassVisitor { public void visitAttribute(final Attribute attr) { checkState(); if (attr == null) { - throw new IllegalArgumentException("Invalid attribute (must not be null)"); + throw new IllegalArgumentException( + "Invalid attribute (must not be null)"); } super.visitAttribute(attr); } @@ -566,10 +543,12 @@ public class CheckClassAdapter extends ClassVisitor { */ private void checkState() { if (!start) { - throw new IllegalStateException("Cannot visit member before visit has been called."); + throw new IllegalStateException( + "Cannot visit member before visit has been called."); } if (end) { - throw new IllegalStateException("Cannot visit member after visitEnd has been called."); + throw new IllegalStateException( + "Cannot visit member after visitEnd has been called."); } } @@ -578,8 +557,10 @@ public class CheckClassAdapter extends ClassVisitor { * method also checks that mutually incompatible flags are not set * simultaneously. * - * @param access the access flags to be checked - * @param possibleAccess the valid access flags. + * @param access + * the access flags to be checked + * @param possibleAccess + * the valid access flags. */ static void checkAccess(final int access, final int possibleAccess) { if ((access & ~possibleAccess) != 0) { @@ -590,14 +571,336 @@ public class CheckClassAdapter extends ClassVisitor { int pri = (access & Opcodes.ACC_PRIVATE) == 0 ? 0 : 1; int pro = (access & Opcodes.ACC_PROTECTED) == 0 ? 0 : 1; if (pub + pri + pro > 1) { - throw new IllegalArgumentException("public private and protected are mutually exclusive: " - + access); + throw new IllegalArgumentException( + "public private and protected are mutually exclusive: " + + access); } int fin = (access & Opcodes.ACC_FINAL) == 0 ? 0 : 1; int abs = (access & Opcodes.ACC_ABSTRACT) == 0 ? 0 : 1; if (fin + abs > 1) { - throw new IllegalArgumentException("final and abstract are mutually exclusive: " - + access); + throw new IllegalArgumentException( + "final and abstract are mutually exclusive: " + access); + } + } + + /** + * Checks a class signature. + * + * @param signature + * a string containing the signature that must be checked. + */ + public static void checkClassSignature(final String signature) { + // ClassSignature: + // FormalTypeParameters? ClassTypeSignature ClassTypeSignature* + + int pos = 0; + if (getChar(signature, 0) == '<') { + pos = checkFormalTypeParameters(signature, pos); + } + pos = checkClassTypeSignature(signature, pos); + while (getChar(signature, pos) == 'L') { + pos = checkClassTypeSignature(signature, pos); + } + if (pos != signature.length()) { + throw new IllegalArgumentException(signature + ": error at index " + + pos); + } + } + + /** + * Checks a method signature. + * + * @param signature + * a string containing the signature that must be checked. + */ + public static void checkMethodSignature(final String signature) { + // MethodTypeSignature: + // FormalTypeParameters? ( TypeSignature* ) ( TypeSignature | V ) ( + // ^ClassTypeSignature | ^TypeVariableSignature )* + + int pos = 0; + if (getChar(signature, 0) == '<') { + pos = checkFormalTypeParameters(signature, pos); + } + pos = checkChar('(', signature, pos); + while ("ZCBSIFJDL[T".indexOf(getChar(signature, pos)) != -1) { + pos = checkTypeSignature(signature, pos); + } + pos = checkChar(')', signature, pos); + if (getChar(signature, pos) == 'V') { + ++pos; + } else { + pos = checkTypeSignature(signature, pos); + } + while (getChar(signature, pos) == '^') { + ++pos; + if (getChar(signature, pos) == 'L') { + pos = checkClassTypeSignature(signature, pos); + } else { + pos = checkTypeVariableSignature(signature, pos); + } + } + if (pos != signature.length()) { + throw new IllegalArgumentException(signature + ": error at index " + + pos); + } + } + + /** + * Checks a field signature. + * + * @param signature + * a string containing the signature that must be checked. + */ + public static void checkFieldSignature(final String signature) { + int pos = checkFieldTypeSignature(signature, 0); + if (pos != signature.length()) { + throw new IllegalArgumentException(signature + ": error at index " + + pos); + } + } + + /** + * Checks the formal type parameters of a class or method signature. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkFormalTypeParameters(final String signature, int pos) { + // FormalTypeParameters: + // < FormalTypeParameter+ > + + pos = checkChar('<', signature, pos); + pos = checkFormalTypeParameter(signature, pos); + while (getChar(signature, pos) != '>') { + pos = checkFormalTypeParameter(signature, pos); + } + return pos + 1; + } + + /** + * Checks a formal type parameter of a class or method signature. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkFormalTypeParameter(final String signature, int pos) { + // FormalTypeParameter: + // Identifier : FieldTypeSignature? (: FieldTypeSignature)* + + pos = checkIdentifier(signature, pos); + pos = checkChar(':', signature, pos); + if ("L[T".indexOf(getChar(signature, pos)) != -1) { + pos = checkFieldTypeSignature(signature, pos); + } + while (getChar(signature, pos) == ':') { + pos = checkFieldTypeSignature(signature, pos + 1); + } + return pos; + } + + /** + * Checks a field type signature. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkFieldTypeSignature(final String signature, int pos) { + // FieldTypeSignature: + // ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature + // + // ArrayTypeSignature: + // [ TypeSignature + + switch (getChar(signature, pos)) { + case 'L': + return checkClassTypeSignature(signature, pos); + case '[': + return checkTypeSignature(signature, pos + 1); + default: + return checkTypeVariableSignature(signature, pos); } } + + /** + * Checks a class type signature. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkClassTypeSignature(final String signature, int pos) { + // ClassTypeSignature: + // L Identifier ( / Identifier )* TypeArguments? ( . Identifier + // TypeArguments? )* ; + + pos = checkChar('L', signature, pos); + pos = checkIdentifier(signature, pos); + while (getChar(signature, pos) == '/') { + pos = checkIdentifier(signature, pos + 1); + } + if (getChar(signature, pos) == '<') { + pos = checkTypeArguments(signature, pos); + } + while (getChar(signature, pos) == '.') { + pos = checkIdentifier(signature, pos + 1); + if (getChar(signature, pos) == '<') { + pos = checkTypeArguments(signature, pos); + } + } + return checkChar(';', signature, pos); + } + + /** + * Checks the type arguments in a class type signature. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkTypeArguments(final String signature, int pos) { + // TypeArguments: + // < TypeArgument+ > + + pos = checkChar('<', signature, pos); + pos = checkTypeArgument(signature, pos); + while (getChar(signature, pos) != '>') { + pos = checkTypeArgument(signature, pos); + } + return pos + 1; + } + + /** + * Checks a type argument in a class type signature. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkTypeArgument(final String signature, int pos) { + // TypeArgument: + // * | ( ( + | - )? FieldTypeSignature ) + + char c = getChar(signature, pos); + if (c == '*') { + return pos + 1; + } else if (c == '+' || c == '-') { + pos++; + } + return checkFieldTypeSignature(signature, pos); + } + + /** + * Checks a type variable signature. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkTypeVariableSignature(final String signature, + int pos) { + // TypeVariableSignature: + // T Identifier ; + + pos = checkChar('T', signature, pos); + pos = checkIdentifier(signature, pos); + return checkChar(';', signature, pos); + } + + /** + * Checks a type signature. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkTypeSignature(final String signature, int pos) { + // TypeSignature: + // Z | C | B | S | I | F | J | D | FieldTypeSignature + + switch (getChar(signature, pos)) { + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + case 'F': + case 'J': + case 'D': + return pos + 1; + default: + return checkFieldTypeSignature(signature, pos); + } + } + + /** + * Checks an identifier. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkIdentifier(final String signature, int pos) { + if (!Character.isJavaIdentifierStart(getChar(signature, pos))) { + throw new IllegalArgumentException(signature + + ": identifier expected at index " + pos); + } + ++pos; + while (Character.isJavaIdentifierPart(getChar(signature, pos))) { + ++pos; + } + return pos; + } + + /** + * Checks a single character. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkChar(final char c, final String signature, int pos) { + if (getChar(signature, pos) == c) { + return pos + 1; + } + throw new IllegalArgumentException(signature + ": '" + c + + "' expected at index " + pos); + } + + /** + * Returns the signature car at the given index. + * + * @param signature + * a signature. + * @param pos + * an index in signature. + * @return the character at the given index, or 0 if there is no such + * character. + */ + private static char getChar(final String signature, int pos) { + return pos < signature.length() ? signature.charAt(pos) : (char) 0; + } } diff --git a/src/asm/scala/tools/asm/util/CheckFieldAdapter.java b/src/asm/scala/tools/asm/util/CheckFieldAdapter.java index bdcbe14b16..4657605936 100644 --- a/src/asm/scala/tools/asm/util/CheckFieldAdapter.java +++ b/src/asm/scala/tools/asm/util/CheckFieldAdapter.java @@ -46,7 +46,8 @@ public class CheckFieldAdapter extends FieldVisitor { * this constructor</i>. Instead, they must use the * {@link #CheckFieldAdapter(int, FieldVisitor)} version. * - * @param fv the field visitor to which this adapter must delegate calls. + * @param fv + * the field visitor to which this adapter must delegate calls. */ public CheckFieldAdapter(final FieldVisitor fv) { this(Opcodes.ASM4, fv); @@ -55,19 +56,19 @@ public class CheckFieldAdapter extends FieldVisitor { /** * Constructs a new {@link CheckFieldAdapter}. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. - * @param fv the field visitor to which this adapter must delegate calls. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param fv + * the field visitor to which this adapter must delegate calls. */ protected CheckFieldAdapter(final int api, final FieldVisitor fv) { super(api, fv); } @Override - public AnnotationVisitor visitAnnotation( - final String desc, - final boolean visible) - { + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { checkEnd(); CheckMethodAdapter.checkDesc(desc, false); return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible)); @@ -77,7 +78,8 @@ public class CheckFieldAdapter extends FieldVisitor { public void visitAttribute(final Attribute attr) { checkEnd(); if (attr == null) { - throw new IllegalArgumentException("Invalid attribute (must not be null)"); + throw new IllegalArgumentException( + "Invalid attribute (must not be null)"); } super.visitAttribute(attr); } @@ -91,7 +93,8 @@ public class CheckFieldAdapter extends FieldVisitor { private void checkEnd() { if (end) { - throw new IllegalStateException("Cannot call a visit method after visitEnd has been called"); + throw new IllegalStateException( + "Cannot call a visit method after visitEnd has been called"); } } } diff --git a/src/asm/scala/tools/asm/util/CheckMethodAdapter.java b/src/asm/scala/tools/asm/util/CheckMethodAdapter.java index 7549765421..9da01c9d6e 100644 --- a/src/asm/scala/tools/asm/util/CheckMethodAdapter.java +++ b/src/asm/scala/tools/asm/util/CheckMethodAdapter.java @@ -58,7 +58,7 @@ import scala.tools.asm.tree.analysis.BasicVerifier; * arguments - such as the fact that the given opcode is correct for a given * visit method. This adapter can also perform some basic data flow checks (more * precisely those that can be performed without the full class hierarchy - see - * {@link org.objectweb.asm.tree.analysis.BasicVerifier}). For instance in a + * {@link scala.tools.asm.tree.analysis.BasicVerifier}). For instance in a * method whose signature is <tt>void m ()</tt>, the invalid instruction * IRETURN, or the invalid sequence IADD L2I will be detected if the data flow * checks are enabled. These checks are enabled by using the @@ -75,6 +75,11 @@ public class CheckMethodAdapter extends MethodVisitor { public int version; /** + * The access flags of the method. + */ + private int access; + + /** * <tt>true</tt> if the visitCode method has been called. */ private boolean startCode; @@ -107,6 +112,21 @@ public class CheckMethodAdapter extends MethodVisitor { private Set<Label> usedLabels; /** + * Number of visited frames in expanded form. + */ + private int expandedFrames; + + /** + * Number of visited frames in compressed form. + */ + private int compressedFrames; + + /** + * Number of instructions before the last visited frame. + */ + private int lastFrame = -1; + + /** * The exception handler ranges. Each pair of list element contains the * start and end labels of an exception handler block. */ @@ -352,7 +372,8 @@ public class CheckMethodAdapter extends MethodVisitor { * <i>Subclasses must not use this constructor</i>. Instead, they must use * the {@link #CheckMethodAdapter(int, MethodVisitor, Map)} version. * - * @param mv the method visitor to which this adapter must delegate calls. + * @param mv + * the method visitor to which this adapter must delegate calls. */ public CheckMethodAdapter(final MethodVisitor mv) { this(mv, new HashMap<Label, Integer>()); @@ -365,13 +386,13 @@ public class CheckMethodAdapter extends MethodVisitor { * <i>Subclasses must not use this constructor</i>. Instead, they must use * the {@link #CheckMethodAdapter(int, MethodVisitor, Map)} version. * - * @param mv the method visitor to which this adapter must delegate calls. - * @param labels a map of already visited labels (in other methods). + * @param mv + * the method visitor to which this adapter must delegate calls. + * @param labels + * a map of already visited labels (in other methods). */ - public CheckMethodAdapter( - final MethodVisitor mv, - final Map<Label, Integer> labels) - { + public CheckMethodAdapter(final MethodVisitor mv, + final Map<Label, Integer> labels) { this(Opcodes.ASM4, mv, labels); } @@ -380,14 +401,13 @@ public class CheckMethodAdapter extends MethodVisitor { * will not perform any data flow check (see * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}). * - * @param mv the method visitor to which this adapter must delegate calls. - * @param labels a map of already visited labels (in other methods). + * @param mv + * the method visitor to which this adapter must delegate calls. + * @param labels + * a map of already visited labels (in other methods). */ - protected CheckMethodAdapter( - final int api, - final MethodVisitor mv, - final Map<Label, Integer> labels) - { + protected CheckMethodAdapter(final int api, final MethodVisitor mv, + final Map<Label, Integer> labels) { super(api, mv); this.labels = labels; this.usedLabels = new HashSet<Label>(); @@ -400,30 +420,32 @@ public class CheckMethodAdapter extends MethodVisitor { * signature is <tt>void m ()</tt>, the invalid instruction IRETURN, or the * invalid sequence IADD L2I will be detected. * - * @param access the method's access flags. - * @param name the method's name. - * @param desc the method's descriptor (see {@link Type Type}). - * @param cmv the method visitor to which this adapter must delegate calls. - * @param labels a map of already visited labels (in other methods). + * @param access + * the method's access flags. + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link Type Type}). + * @param cmv + * the method visitor to which this adapter must delegate calls. + * @param labels + * a map of already visited labels (in other methods). */ - public CheckMethodAdapter( - final int access, - final String name, - final String desc, - final MethodVisitor cmv, - final Map<Label, Integer> labels) - { + public CheckMethodAdapter(final int access, final String name, + final String desc, final MethodVisitor cmv, + final Map<Label, Integer> labels) { this(new MethodNode(access, name, desc, null, null) { @Override public void visitEnd() { - Analyzer<BasicValue> a = new Analyzer<BasicValue>(new BasicVerifier()); + Analyzer<BasicValue> a = new Analyzer<BasicValue>( + new BasicVerifier()); try { a.analyze("dummy", this); } catch (Exception e) { if (e instanceof IndexOutOfBoundsException - && maxLocals == 0 && maxStack == 0) - { - throw new RuntimeException("Data flow checking option requires valid, non zero maxLocals and maxStack values."); + && maxLocals == 0 && maxStack == 0) { + throw new RuntimeException( + "Data flow checking option requires valid, non zero maxLocals and maxStack values."); } e.printStackTrace(); StringWriter sw = new StringWriter(); @@ -435,15 +457,13 @@ public class CheckMethodAdapter extends MethodVisitor { } accept(cmv); } - }, - labels); + }, labels); + this.access = access; } @Override - public AnnotationVisitor visitAnnotation( - final String desc, - final boolean visible) - { + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { checkEndMethod(); checkDesc(desc, false); return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible)); @@ -456,68 +476,68 @@ public class CheckMethodAdapter extends MethodVisitor { } @Override - public AnnotationVisitor visitParameterAnnotation( - final int parameter, - final String desc, - final boolean visible) - { + public AnnotationVisitor visitParameterAnnotation(final int parameter, + final String desc, final boolean visible) { checkEndMethod(); checkDesc(desc, false); - return new CheckAnnotationAdapter(super.visitParameterAnnotation(parameter, - desc, - visible)); + return new CheckAnnotationAdapter(super.visitParameterAnnotation( + parameter, desc, visible)); } @Override public void visitAttribute(final Attribute attr) { checkEndMethod(); if (attr == null) { - throw new IllegalArgumentException("Invalid attribute (must not be null)"); + throw new IllegalArgumentException( + "Invalid attribute (must not be null)"); } super.visitAttribute(attr); } @Override public void visitCode() { + if ((access & Opcodes.ACC_ABSTRACT) != 0) { + throw new RuntimeException("Abstract methods cannot have code"); + } startCode = true; super.visitCode(); } @Override - public void visitFrame( - final int type, - final int nLocal, - final Object[] local, - final int nStack, - final Object[] stack) - { + public void visitFrame(final int type, final int nLocal, + final Object[] local, final int nStack, final Object[] stack) { + if (insnCount == lastFrame) { + throw new IllegalStateException( + "At most one frame can be visited at a given code location."); + } + lastFrame = insnCount; int mLocal; int mStack; switch (type) { - case Opcodes.F_NEW: - case Opcodes.F_FULL: - mLocal = Integer.MAX_VALUE; - mStack = Integer.MAX_VALUE; - break; + case Opcodes.F_NEW: + case Opcodes.F_FULL: + mLocal = Integer.MAX_VALUE; + mStack = Integer.MAX_VALUE; + break; - case Opcodes.F_SAME: - mLocal = 0; - mStack = 0; - break; + case Opcodes.F_SAME: + mLocal = 0; + mStack = 0; + break; - case Opcodes.F_SAME1: - mLocal = 0; - mStack = 1; - break; + case Opcodes.F_SAME1: + mLocal = 0; + mStack = 1; + break; - case Opcodes.F_APPEND: - case Opcodes.F_CHOP: - mLocal = 3; - mStack = 0; - break; + case Opcodes.F_APPEND: + case Opcodes.F_CHOP: + mLocal = 3; + mStack = 0; + break; - default: - throw new IllegalArgumentException("Invalid frame type " + type); + default: + throw new IllegalArgumentException("Invalid frame type " + type); } if (nLocal > mLocal) { @@ -531,19 +551,29 @@ public class CheckMethodAdapter extends MethodVisitor { if (type != Opcodes.F_CHOP) { if (nLocal > 0 && (local == null || local.length < nLocal)) { - throw new IllegalArgumentException("Array local[] is shorter than nLocal"); + throw new IllegalArgumentException( + "Array local[] is shorter than nLocal"); } for (int i = 0; i < nLocal; ++i) { checkFrameValue(local[i]); } } if (nStack > 0 && (stack == null || stack.length < nStack)) { - throw new IllegalArgumentException("Array stack[] is shorter than nStack"); + throw new IllegalArgumentException( + "Array stack[] is shorter than nStack"); } for (int i = 0; i < nStack; ++i) { checkFrameValue(stack[i]); } - + if (type == Opcodes.F_NEW) { + ++expandedFrames; + } else { + ++compressedFrames; + } + if (expandedFrames > 0 && compressedFrames > 0) { + throw new RuntimeException( + "Expanded and compressed frames must not be mixed."); + } super.visitFrame(type, nLocal, local, nStack, stack); } @@ -562,18 +592,19 @@ public class CheckMethodAdapter extends MethodVisitor { checkEndCode(); checkOpcode(opcode, 1); switch (opcode) { - case Opcodes.BIPUSH: - checkSignedByte(operand, "Invalid operand"); - break; - case Opcodes.SIPUSH: - checkSignedShort(operand, "Invalid operand"); - break; - // case Constants.NEWARRAY: - default: - if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) { - throw new IllegalArgumentException("Invalid operand (must be an array type code T_...): " - + operand); - } + case Opcodes.BIPUSH: + checkSignedByte(operand, "Invalid operand"); + break; + case Opcodes.SIPUSH: + checkSignedShort(operand, "Invalid operand"); + break; + // case Constants.NEWARRAY: + default: + if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) { + throw new IllegalArgumentException( + "Invalid operand (must be an array type code T_...): " + + operand); + } } super.visitIntInsn(opcode, operand); ++insnCount; @@ -596,20 +627,16 @@ public class CheckMethodAdapter extends MethodVisitor { checkOpcode(opcode, 3); checkInternalName(type, "type"); if (opcode == Opcodes.NEW && type.charAt(0) == '[') { - throw new IllegalArgumentException("NEW cannot be used to create arrays: " - + type); + throw new IllegalArgumentException( + "NEW cannot be used to create arrays: " + type); } super.visitTypeInsn(opcode, type); ++insnCount; } @Override - public void visitFieldInsn( - final int opcode, - final String owner, - final String name, - final String desc) - { + public void visitFieldInsn(final int opcode, final String owner, + final String name, final String desc) { checkStartCode(); checkEndCode(); checkOpcode(opcode, 4); @@ -621,16 +648,14 @@ public class CheckMethodAdapter extends MethodVisitor { } @Override - public void visitMethodInsn( - final int opcode, - final String owner, - final String name, - final String desc) - { + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { checkStartCode(); checkEndCode(); checkOpcode(opcode, 5); - checkMethodIdentifier(version, name, "name"); + if (opcode != Opcodes.INVOKESPECIAL || !"<init>".equals(name)) { + checkMethodIdentifier(version, name, "name"); + } checkInternalName(owner, "owner"); checkMethodDesc(desc); super.visitMethodInsn(opcode, owner, name, desc); @@ -638,19 +663,14 @@ public class CheckMethodAdapter extends MethodVisitor { } @Override - public void visitInvokeDynamicInsn( - String name, - String desc, - Handle bsm, - Object... bsmArgs) - { + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, + Object... bsmArgs) { checkStartCode(); checkEndCode(); checkMethodIdentifier(version, name, "name"); checkMethodDesc(desc); if (bsm.getTag() != Opcodes.H_INVOKESTATIC - && bsm.getTag() != Opcodes.H_NEWINVOKESPECIAL) - { + && bsm.getTag() != Opcodes.H_NEWINVOKESPECIAL) { throw new IllegalArgumentException("invalid handle tag " + bsm.getTag()); } @@ -705,12 +725,8 @@ public class CheckMethodAdapter extends MethodVisitor { } @Override - public void visitTableSwitchInsn( - final int min, - final int max, - final Label dflt, - final Label... labels) - { + public void visitTableSwitchInsn(final int min, final int max, + final Label dflt, final Label... labels) { checkStartCode(); checkEndCode(); if (max < min) { @@ -720,7 +736,8 @@ public class CheckMethodAdapter extends MethodVisitor { checkLabel(dflt, false, "default label"); checkNonDebugLabel(dflt); if (labels == null || labels.length != max - min + 1) { - throw new IllegalArgumentException("There must be max - min + 1 labels"); + throw new IllegalArgumentException( + "There must be max - min + 1 labels"); } for (int i = 0; i < labels.length; ++i) { checkLabel(labels[i], false, "label at index " + i); @@ -734,17 +751,15 @@ public class CheckMethodAdapter extends MethodVisitor { } @Override - public void visitLookupSwitchInsn( - final Label dflt, - final int[] keys, - final Label[] labels) - { + public void visitLookupSwitchInsn(final Label dflt, final int[] keys, + final Label[] labels) { checkEndCode(); checkStartCode(); checkLabel(dflt, false, "default label"); checkNonDebugLabel(dflt); if (keys == null || labels == null || keys.length != labels.length) { - throw new IllegalArgumentException("There must be the same number of keys and labels"); + throw new IllegalArgumentException( + "There must be the same number of keys and labels"); } for (int i = 0; i < labels.length; ++i) { checkLabel(labels[i], false, "label at index " + i); @@ -764,28 +779,26 @@ public class CheckMethodAdapter extends MethodVisitor { checkEndCode(); checkDesc(desc, false); if (desc.charAt(0) != '[') { - throw new IllegalArgumentException("Invalid descriptor (must be an array type descriptor): " - + desc); + throw new IllegalArgumentException( + "Invalid descriptor (must be an array type descriptor): " + + desc); } if (dims < 1) { - throw new IllegalArgumentException("Invalid dimensions (must be greater than 0): " - + dims); + throw new IllegalArgumentException( + "Invalid dimensions (must be greater than 0): " + dims); } if (dims > desc.lastIndexOf('[') + 1) { - throw new IllegalArgumentException("Invalid dimensions (must not be greater than dims(desc)): " - + dims); + throw new IllegalArgumentException( + "Invalid dimensions (must not be greater than dims(desc)): " + + dims); } super.visitMultiANewArrayInsn(desc, dims); ++insnCount; } @Override - public void visitTryCatchBlock( - final Label start, - final Label end, - final Label handler, - final String type) - { + public void visitTryCatchBlock(final Label start, final Label end, + final Label handler, final String type) { checkStartCode(); checkEndCode(); checkLabel(start, false, "start label"); @@ -795,9 +808,9 @@ public class CheckMethodAdapter extends MethodVisitor { checkNonDebugLabel(end); checkNonDebugLabel(handler); if (labels.get(start) != null || labels.get(end) != null - || labels.get(handler) != null) - { - throw new IllegalStateException("Try catch blocks must be visited before their labels"); + || labels.get(handler) != null) { + throw new IllegalStateException( + "Try catch blocks must be visited before their labels"); } if (type != null) { checkInternalName(type, "type"); @@ -808,14 +821,9 @@ public class CheckMethodAdapter extends MethodVisitor { } @Override - public void visitLocalVariable( - final String name, - final String desc, - final String signature, - final Label start, - final Label end, - final int index) - { + public void visitLocalVariable(final String name, final String desc, + final String signature, final Label start, final Label end, + final int index) { checkStartCode(); checkEndCode(); checkUnqualifiedName(version, name, "name"); @@ -826,7 +834,8 @@ public class CheckMethodAdapter extends MethodVisitor { int s = labels.get(start).intValue(); int e = labels.get(end).intValue(); if (e < s) { - throw new IllegalArgumentException("Invalid start and end labels (end must be greater than start)"); + throw new IllegalArgumentException( + "Invalid start and end labels (end must be greater than start)"); } super.visitLocalVariable(name, desc, signature, start, end, index); } @@ -850,14 +859,16 @@ public class CheckMethodAdapter extends MethodVisitor { throw new IllegalStateException("Undefined label used"); } } - for (int i = 0; i < handlers.size(); ) { + for (int i = 0; i < handlers.size();) { Integer start = labels.get(handlers.get(i++)); Integer end = labels.get(handlers.get(i++)); if (start == null || end == null) { - throw new IllegalStateException("Undefined try catch block labels"); + throw new IllegalStateException( + "Undefined try catch block labels"); } if (end.intValue() <= start.intValue()) { - throw new IllegalStateException("Emty try catch block handler range"); + throw new IllegalStateException( + "Emty try catch block handler range"); } } checkUnsignedShort(maxStack, "Invalid max stack"); @@ -879,7 +890,8 @@ public class CheckMethodAdapter extends MethodVisitor { */ void checkStartCode() { if (!startCode) { - throw new IllegalStateException("Cannot visit instructions before visitCode has been called."); + throw new IllegalStateException( + "Cannot visit instructions before visitCode has been called."); } } @@ -888,7 +900,8 @@ public class CheckMethodAdapter extends MethodVisitor { */ void checkEndCode() { if (endCode) { - throw new IllegalStateException("Cannot visit instructions after visitMaxs has been called."); + throw new IllegalStateException( + "Cannot visit instructions after visitMaxs has been called."); } } @@ -897,21 +910,22 @@ public class CheckMethodAdapter extends MethodVisitor { */ void checkEndMethod() { if (endMethod) { - throw new IllegalStateException("Cannot visit elements after visitEnd has been called."); + throw new IllegalStateException( + "Cannot visit elements after visitEnd has been called."); } } /** * Checks a stack frame value. * - * @param value the value to be checked. + * @param value + * the value to be checked. */ void checkFrameValue(final Object value) { if (value == Opcodes.TOP || value == Opcodes.INTEGER || value == Opcodes.FLOAT || value == Opcodes.LONG || value == Opcodes.DOUBLE || value == Opcodes.NULL - || value == Opcodes.UNINITIALIZED_THIS) - { + || value == Opcodes.UNINITIALIZED_THIS) { return; } if (value instanceof String) { @@ -929,8 +943,10 @@ public class CheckMethodAdapter extends MethodVisitor { /** * Checks that the type of the given opcode is equal to the given type. * - * @param opcode the opcode to be checked. - * @param type the expected opcode type. + * @param opcode + * the opcode to be checked. + * @param type + * the expected opcode type. */ static void checkOpcode(final int opcode, final int type) { if (opcode < 0 || opcode > 199 || TYPE[opcode] != type) { @@ -941,8 +957,10 @@ public class CheckMethodAdapter extends MethodVisitor { /** * Checks that the given value is a signed byte. * - * @param value the value to be checked. - * @param msg an message to be used in case of error. + * @param value + * the value to be checked. + * @param msg + * an message to be used in case of error. */ static void checkSignedByte(final int value, final String msg) { if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) { @@ -954,8 +972,10 @@ public class CheckMethodAdapter extends MethodVisitor { /** * Checks that the given value is a signed short. * - * @param value the value to be checked. - * @param msg an message to be used in case of error. + * @param value + * the value to be checked. + * @param msg + * an message to be used in case of error. */ static void checkSignedShort(final int value, final String msg) { if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) { @@ -967,8 +987,10 @@ public class CheckMethodAdapter extends MethodVisitor { /** * Checks that the given value is an unsigned short. * - * @param value the value to be checked. - * @param msg an message to be used in case of error. + * @param value + * the value to be checked. + * @param msg + * an message to be used in case of error. */ static void checkUnsignedShort(final int value, final String msg) { if (value < 0 || value > 65535) { @@ -981,13 +1003,13 @@ public class CheckMethodAdapter extends MethodVisitor { * Checks that the given value is an {@link Integer}, a{@link Float}, a * {@link Long}, a {@link Double} or a {@link String}. * - * @param cst the value to be checked. + * @param cst + * the value to be checked. */ static void checkConstant(final Object cst) { if (!(cst instanceof Integer) && !(cst instanceof Float) && !(cst instanceof Long) && !(cst instanceof Double) - && !(cst instanceof String)) - { + && !(cst instanceof String)) { throw new IllegalArgumentException("Invalid constant: " + cst); } } @@ -999,19 +1021,21 @@ public class CheckMethodAdapter extends MethodVisitor { throw new IllegalArgumentException("Illegal LDC constant value"); } if (s != Type.METHOD && (version & 0xFFFF) < Opcodes.V1_5) { - throw new IllegalArgumentException("ldc of a constant class requires at least version 1.5"); + throw new IllegalArgumentException( + "ldc of a constant class requires at least version 1.5"); } if (s == Type.METHOD && (version & 0xFFFF) < Opcodes.V1_7) { - throw new IllegalArgumentException("ldc of a method type requires at least version 1.7"); + throw new IllegalArgumentException( + "ldc of a method type requires at least version 1.7"); } } else if (cst instanceof Handle) { if ((version & 0xFFFF) < Opcodes.V1_7) { - throw new IllegalArgumentException("ldc of a handle requires at least version 1.7"); + throw new IllegalArgumentException( + "ldc of a handle requires at least version 1.7"); } int tag = ((Handle) cst).getTag(); if (tag < Opcodes.H_GETFIELD || tag > Opcodes.H_INVOKEINTERFACE) { - throw new IllegalArgumentException("invalid handle tag " - + tag); + throw new IllegalArgumentException("invalid handle tag " + tag); } } else { checkConstant(cst); @@ -1021,15 +1045,15 @@ public class CheckMethodAdapter extends MethodVisitor { /** * Checks that the given string is a valid unqualified name. * - * @param version the class version. - * @param name the string to be checked. - * @param msg a message to be used in case of error. + * @param version + * the class version. + * @param name + * the string to be checked. + * @param msg + * a message to be used in case of error. */ - static void checkUnqualifiedName( - int version, - final String name, - final String msg) - { + static void checkUnqualifiedName(int version, final String name, + final String msg) { if ((version & 0xFFFF) < Opcodes.V1_5) { checkIdentifier(name, msg); } else { @@ -1045,8 +1069,10 @@ public class CheckMethodAdapter extends MethodVisitor { /** * Checks that the given string is a valid Java identifier. * - * @param name the string to be checked. - * @param msg a message to be used in case of error. + * @param name + * the string to be checked. + * @param msg + * a message to be used in case of error. */ static void checkIdentifier(final String name, final String msg) { checkIdentifier(name, 0, -1, msg); @@ -1055,21 +1081,20 @@ public class CheckMethodAdapter extends MethodVisitor { /** * Checks that the given substring is a valid Java identifier. * - * @param name the string to be checked. - * @param start index of the first character of the identifier (inclusive). - * @param end index of the last character of the identifier (exclusive). -1 - * is equivalent to <tt>name.length()</tt> if name is not - * <tt>null</tt>. - * @param msg a message to be used in case of error. + * @param name + * the string to be checked. + * @param start + * index of the first character of the identifier (inclusive). + * @param end + * index of the last character of the identifier (exclusive). -1 + * is equivalent to <tt>name.length()</tt> if name is not + * <tt>null</tt>. + * @param msg + * a message to be used in case of error. */ - static void checkIdentifier( - final String name, - final int start, - final int end, - final String msg) - { - if (name == null || (end == -1 ? name.length() <= start : end <= start)) - { + static void checkIdentifier(final String name, final int start, + final int end, final String msg) { + if (name == null || (end == -1 ? name.length() <= start : end <= start)) { throw new IllegalArgumentException("Invalid " + msg + " (must not be null or empty)"); } @@ -1087,25 +1112,21 @@ public class CheckMethodAdapter extends MethodVisitor { } /** - * Checks that the given string is a valid Java identifier or is equal to - * '<init>' or '<clinit>'. + * Checks that the given string is a valid Java identifier. * - * @param version the class version. - * @param name the string to be checked. - * @param msg a message to be used in case of error. + * @param version + * the class version. + * @param name + * the string to be checked. + * @param msg + * a message to be used in case of error. */ - static void checkMethodIdentifier( - int version, - final String name, - final String msg) - { + static void checkMethodIdentifier(int version, final String name, + final String msg) { if (name == null || name.length() == 0) { throw new IllegalArgumentException("Invalid " + msg + " (must not be null or empty)"); } - if ("<init>".equals(name) || "<clinit>".equals(name)) { - return; - } if ((version & 0xFFFF) >= Opcodes.V1_5) { for (int i = 0; i < name.length(); ++i) { if (".;[/<>".indexOf(name.charAt(i)) != -1) { @@ -1116,17 +1137,19 @@ public class CheckMethodAdapter extends MethodVisitor { return; } if (!Character.isJavaIdentifierStart(name.charAt(0))) { - throw new IllegalArgumentException("Invalid " - + msg - + " (must be a '<init>', '<clinit>' or a valid Java identifier): " - + name); + throw new IllegalArgumentException( + "Invalid " + + msg + + " (must be a '<init>', '<clinit>' or a valid Java identifier): " + + name); } for (int i = 1; i < name.length(); ++i) { if (!Character.isJavaIdentifierPart(name.charAt(i))) { - throw new IllegalArgumentException("Invalid " - + msg - + " (must be '<init>' or '<clinit>' or a valid Java identifier): " - + name); + throw new IllegalArgumentException( + "Invalid " + + msg + + " (must be '<init>' or '<clinit>' or a valid Java identifier): " + + name); } } } @@ -1134,8 +1157,10 @@ public class CheckMethodAdapter extends MethodVisitor { /** * Checks that the given string is a valid internal class name. * - * @param name the string to be checked. - * @param msg a message to be used in case of error. + * @param name + * the string to be checked. + * @param msg + * a message to be used in case of error. */ static void checkInternalName(final String name, final String msg) { if (name == null || name.length() == 0) { @@ -1152,19 +1177,19 @@ public class CheckMethodAdapter extends MethodVisitor { /** * Checks that the given substring is a valid internal class name. * - * @param name the string to be checked. - * @param start index of the first character of the identifier (inclusive). - * @param end index of the last character of the identifier (exclusive). -1 - * is equivalent to <tt>name.length()</tt> if name is not - * <tt>null</tt>. - * @param msg a message to be used in case of error. + * @param name + * the string to be checked. + * @param start + * index of the first character of the identifier (inclusive). + * @param end + * index of the last character of the identifier (exclusive). -1 + * is equivalent to <tt>name.length()</tt> if name is not + * <tt>null</tt>. + * @param msg + * a message to be used in case of error. */ - static void checkInternalName( - final String name, - final int start, - final int end, - final String msg) - { + static void checkInternalName(final String name, final int start, + final int end, final String msg) { int max = end == -1 ? name.length() : end; try { int begin = start; @@ -1178,18 +1203,21 @@ public class CheckMethodAdapter extends MethodVisitor { begin = slash + 1; } while (slash != max); } catch (IllegalArgumentException _) { - throw new IllegalArgumentException("Invalid " - + msg - + " (must be a fully qualified class name in internal form): " - + name); + throw new IllegalArgumentException( + "Invalid " + + msg + + " (must be a fully qualified class name in internal form): " + + name); } } /** * Checks that the given string is a valid type descriptor. * - * @param desc the string to be checked. - * @param canBeVoid <tt>true</tt> if <tt>V</tt> can be considered valid. + * @param desc + * the string to be checked. + * @param canBeVoid + * <tt>true</tt> if <tt>V</tt> can be considered valid. */ static void checkDesc(final String desc, final boolean canBeVoid) { int end = checkDesc(desc, 0, canBeVoid); @@ -1201,75 +1229,77 @@ public class CheckMethodAdapter extends MethodVisitor { /** * Checks that a the given substring is a valid type descriptor. * - * @param desc the string to be checked. - * @param start index of the first character of the identifier (inclusive). - * @param canBeVoid <tt>true</tt> if <tt>V</tt> can be considered valid. + * @param desc + * the string to be checked. + * @param start + * index of the first character of the identifier (inclusive). + * @param canBeVoid + * <tt>true</tt> if <tt>V</tt> can be considered valid. * @return the index of the last character of the type decriptor, plus one. */ - static int checkDesc( - final String desc, - final int start, - final boolean canBeVoid) - { + static int checkDesc(final String desc, final int start, + final boolean canBeVoid) { if (desc == null || start >= desc.length()) { - throw new IllegalArgumentException("Invalid type descriptor (must not be null or empty)"); + throw new IllegalArgumentException( + "Invalid type descriptor (must not be null or empty)"); } int index; switch (desc.charAt(start)) { - case 'V': - if (canBeVoid) { - return start + 1; - } else { - throw new IllegalArgumentException("Invalid descriptor: " - + desc); - } - case 'Z': - case 'C': - case 'B': - case 'S': - case 'I': - case 'F': - case 'J': - case 'D': + case 'V': + if (canBeVoid) { return start + 1; - case '[': - index = start + 1; - while (index < desc.length() && desc.charAt(index) == '[') { - ++index; - } - if (index < desc.length()) { - return checkDesc(desc, index, false); - } else { - throw new IllegalArgumentException("Invalid descriptor: " - + desc); - } - case 'L': - index = desc.indexOf(';', start); - if (index == -1 || index - start < 2) { - throw new IllegalArgumentException("Invalid descriptor: " - + desc); - } - try { - checkInternalName(desc, start + 1, index, null); - } catch (IllegalArgumentException _) { - throw new IllegalArgumentException("Invalid descriptor: " - + desc); - } - return index + 1; - default: + } else { + throw new IllegalArgumentException("Invalid descriptor: " + + desc); + } + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + case 'F': + case 'J': + case 'D': + return start + 1; + case '[': + index = start + 1; + while (index < desc.length() && desc.charAt(index) == '[') { + ++index; + } + if (index < desc.length()) { + return checkDesc(desc, index, false); + } else { throw new IllegalArgumentException("Invalid descriptor: " + desc); + } + case 'L': + index = desc.indexOf(';', start); + if (index == -1 || index - start < 2) { + throw new IllegalArgumentException("Invalid descriptor: " + + desc); + } + try { + checkInternalName(desc, start + 1, index, null); + } catch (IllegalArgumentException _) { + throw new IllegalArgumentException("Invalid descriptor: " + + desc); + } + return index + 1; + default: + throw new IllegalArgumentException("Invalid descriptor: " + desc); } } /** * Checks that the given string is a valid method descriptor. * - * @param desc the string to be checked. + * @param desc + * the string to be checked. */ static void checkMethodDesc(final String desc) { if (desc == null || desc.length() == 0) { - throw new IllegalArgumentException("Invalid method descriptor (must not be null or empty)"); + throw new IllegalArgumentException( + "Invalid method descriptor (must not be null or empty)"); } if (desc.charAt(0) != '(' || desc.length() < 3) { throw new IllegalArgumentException("Invalid descriptor: " + desc); @@ -1291,322 +1321,18 @@ public class CheckMethodAdapter extends MethodVisitor { } /** - * Checks a class signature. - * - * @param signature a string containing the signature that must be checked. - */ - static void checkClassSignature(final String signature) { - // ClassSignature: - // FormalTypeParameters? ClassTypeSignature ClassTypeSignature* - - int pos = 0; - if (getChar(signature, 0) == '<') { - pos = checkFormalTypeParameters(signature, pos); - } - pos = checkClassTypeSignature(signature, pos); - while (getChar(signature, pos) == 'L') { - pos = checkClassTypeSignature(signature, pos); - } - if (pos != signature.length()) { - throw new IllegalArgumentException(signature + ": error at index " - + pos); - } - } - - /** - * Checks a method signature. - * - * @param signature a string containing the signature that must be checked. - */ - static void checkMethodSignature(final String signature) { - // MethodTypeSignature: - // FormalTypeParameters? ( TypeSignature* ) ( TypeSignature | V ) ( - // ^ClassTypeSignature | ^TypeVariableSignature )* - - int pos = 0; - if (getChar(signature, 0) == '<') { - pos = checkFormalTypeParameters(signature, pos); - } - pos = checkChar('(', signature, pos); - while ("ZCBSIFJDL[T".indexOf(getChar(signature, pos)) != -1) { - pos = checkTypeSignature(signature, pos); - } - pos = checkChar(')', signature, pos); - if (getChar(signature, pos) == 'V') { - ++pos; - } else { - pos = checkTypeSignature(signature, pos); - } - while (getChar(signature, pos) == '^') { - ++pos; - if (getChar(signature, pos) == 'L') { - pos = checkClassTypeSignature(signature, pos); - } else { - pos = checkTypeVariableSignature(signature, pos); - } - } - if (pos != signature.length()) { - throw new IllegalArgumentException(signature + ": error at index " - + pos); - } - } - - /** - * Checks a field signature. - * - * @param signature a string containing the signature that must be checked. - */ - static void checkFieldSignature(final String signature) { - int pos = checkFieldTypeSignature(signature, 0); - if (pos != signature.length()) { - throw new IllegalArgumentException(signature + ": error at index " - + pos); - } - } - - /** - * Checks the formal type parameters of a class or method signature. - * - * @param signature a string containing the signature that must be checked. - * @param pos index of first character to be checked. - * @return the index of the first character after the checked part. - */ - private static int checkFormalTypeParameters(final String signature, int pos) - { - // FormalTypeParameters: - // < FormalTypeParameter+ > - - pos = checkChar('<', signature, pos); - pos = checkFormalTypeParameter(signature, pos); - while (getChar(signature, pos) != '>') { - pos = checkFormalTypeParameter(signature, pos); - } - return pos + 1; - } - - /** - * Checks a formal type parameter of a class or method signature. - * - * @param signature a string containing the signature that must be checked. - * @param pos index of first character to be checked. - * @return the index of the first character after the checked part. - */ - private static int checkFormalTypeParameter(final String signature, int pos) - { - // FormalTypeParameter: - // Identifier : FieldTypeSignature? (: FieldTypeSignature)* - - pos = checkIdentifier(signature, pos); - pos = checkChar(':', signature, pos); - if ("L[T".indexOf(getChar(signature, pos)) != -1) { - pos = checkFieldTypeSignature(signature, pos); - } - while (getChar(signature, pos) == ':') { - pos = checkFieldTypeSignature(signature, pos + 1); - } - return pos; - } - - /** - * Checks a field type signature. - * - * @param signature a string containing the signature that must be checked. - * @param pos index of first character to be checked. - * @return the index of the first character after the checked part. - */ - private static int checkFieldTypeSignature(final String signature, int pos) - { - // FieldTypeSignature: - // ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature - // - // ArrayTypeSignature: - // [ TypeSignature - - switch (getChar(signature, pos)) { - case 'L': - return checkClassTypeSignature(signature, pos); - case '[': - return checkTypeSignature(signature, pos + 1); - default: - return checkTypeVariableSignature(signature, pos); - } - } - - /** - * Checks a class type signature. - * - * @param signature a string containing the signature that must be checked. - * @param pos index of first character to be checked. - * @return the index of the first character after the checked part. - */ - private static int checkClassTypeSignature(final String signature, int pos) - { - // ClassTypeSignature: - // L Identifier ( / Identifier )* TypeArguments? ( . Identifier - // TypeArguments? )* ; - - pos = checkChar('L', signature, pos); - pos = checkIdentifier(signature, pos); - while (getChar(signature, pos) == '/') { - pos = checkIdentifier(signature, pos + 1); - } - if (getChar(signature, pos) == '<') { - pos = checkTypeArguments(signature, pos); - } - while (getChar(signature, pos) == '.') { - pos = checkIdentifier(signature, pos + 1); - if (getChar(signature, pos) == '<') { - pos = checkTypeArguments(signature, pos); - } - } - return checkChar(';', signature, pos); - } - - /** - * Checks the type arguments in a class type signature. - * - * @param signature a string containing the signature that must be checked. - * @param pos index of first character to be checked. - * @return the index of the first character after the checked part. - */ - private static int checkTypeArguments(final String signature, int pos) { - // TypeArguments: - // < TypeArgument+ > - - pos = checkChar('<', signature, pos); - pos = checkTypeArgument(signature, pos); - while (getChar(signature, pos) != '>') { - pos = checkTypeArgument(signature, pos); - } - return pos + 1; - } - - /** - * Checks a type argument in a class type signature. - * - * @param signature a string containing the signature that must be checked. - * @param pos index of first character to be checked. - * @return the index of the first character after the checked part. - */ - private static int checkTypeArgument(final String signature, int pos) { - // TypeArgument: - // * | ( ( + | - )? FieldTypeSignature ) - - char c = getChar(signature, pos); - if (c == '*') { - return pos + 1; - } else if (c == '+' || c == '-') { - pos++; - } - return checkFieldTypeSignature(signature, pos); - } - - /** - * Checks a type variable signature. - * - * @param signature a string containing the signature that must be checked. - * @param pos index of first character to be checked. - * @return the index of the first character after the checked part. - */ - private static int checkTypeVariableSignature( - final String signature, - int pos) - { - // TypeVariableSignature: - // T Identifier ; - - pos = checkChar('T', signature, pos); - pos = checkIdentifier(signature, pos); - return checkChar(';', signature, pos); - } - - /** - * Checks a type signature. - * - * @param signature a string containing the signature that must be checked. - * @param pos index of first character to be checked. - * @return the index of the first character after the checked part. - */ - private static int checkTypeSignature(final String signature, int pos) { - // TypeSignature: - // Z | C | B | S | I | F | J | D | FieldTypeSignature - - switch (getChar(signature, pos)) { - case 'Z': - case 'C': - case 'B': - case 'S': - case 'I': - case 'F': - case 'J': - case 'D': - return pos + 1; - default: - return checkFieldTypeSignature(signature, pos); - } - } - - /** - * Checks an identifier. - * - * @param signature a string containing the signature that must be checked. - * @param pos index of first character to be checked. - * @return the index of the first character after the checked part. - */ - private static int checkIdentifier(final String signature, int pos) { - if (!Character.isJavaIdentifierStart(getChar(signature, pos))) { - throw new IllegalArgumentException(signature - + ": identifier expected at index " + pos); - } - ++pos; - while (Character.isJavaIdentifierPart(getChar(signature, pos))) { - ++pos; - } - return pos; - } - - /** - * Checks a single character. - * - * @param signature a string containing the signature that must be checked. - * @param pos index of first character to be checked. - * @return the index of the first character after the checked part. - */ - private static int checkChar(final char c, final String signature, int pos) - { - if (getChar(signature, pos) == c) { - return pos + 1; - } - throw new IllegalArgumentException(signature + ": '" + c - + "' expected at index " + pos); - } - - /** - * Returns the signature car at the given index. - * - * @param signature a signature. - * @param pos an index in signature. - * @return the character at the given index, or 0 if there is no such - * character. - */ - private static char getChar(final String signature, int pos) { - return pos < signature.length() ? signature.charAt(pos) : (char) 0; - } - - /** * Checks that the given label is not null. This method can also check that * the label has been visited. * - * @param label the label to be checked. - * @param checkVisited <tt>true</tt> to check that the label has been - * visited. - * @param msg a message to be used in case of error. + * @param label + * the label to be checked. + * @param checkVisited + * <tt>true</tt> to check that the label has been visited. + * @param msg + * a message to be used in case of error. */ - void checkLabel( - final Label label, - final boolean checkVisited, - final String msg) - { + void checkLabel(final Label label, final boolean checkVisited, + final String msg) { if (label == null) { throw new IllegalArgumentException("Invalid " + msg + " (must not be null)"); @@ -1620,7 +1346,8 @@ public class CheckMethodAdapter extends MethodVisitor { /** * Checks that the given label is not a label used only for debug purposes. * - * @param label the label to be checked. + * @param label + * the label to be checked. */ private static void checkNonDebugLabel(final Label label) { Field f = getLabelStatusField(); @@ -1631,7 +1358,8 @@ public class CheckMethodAdapter extends MethodVisitor { throw new Error("Internal error"); } if ((status & 0x01) != 0) { - throw new IllegalArgumentException("Labels used for debug info cannot be reused for control flow"); + throw new IllegalArgumentException( + "Labels used for debug info cannot be reused for control flow"); } } @@ -1653,7 +1381,8 @@ public class CheckMethodAdapter extends MethodVisitor { /** * Returns the field of the Label class whose name is given. * - * @param name a field name. + * @param name + * a field name. * @return the field of the Label class whose name is given, or null. */ private static Field getLabelField(final String name) { diff --git a/src/asm/scala/tools/asm/util/CheckSignatureAdapter.java b/src/asm/scala/tools/asm/util/CheckSignatureAdapter.java index 3a6c3e780f..e69302b8a6 100644 --- a/src/asm/scala/tools/asm/util/CheckSignatureAdapter.java +++ b/src/asm/scala/tools/asm/util/CheckSignatureAdapter.java @@ -41,19 +41,22 @@ public class CheckSignatureAdapter extends SignatureVisitor { /** * Type to be used to check class signatures. See - * {@link #CheckSignatureAdapter(int, SignatureVisitor) CheckSignatureAdapter}. + * {@link #CheckSignatureAdapter(int, SignatureVisitor) + * CheckSignatureAdapter}. */ public static final int CLASS_SIGNATURE = 0; /** * Type to be used to check method signatures. See - * {@link #CheckSignatureAdapter(int, SignatureVisitor) CheckSignatureAdapter}. + * {@link #CheckSignatureAdapter(int, SignatureVisitor) + * CheckSignatureAdapter}. */ public static final int METHOD_SIGNATURE = 1; /** * Type to be used to check type signatures.See - * {@link #CheckSignatureAdapter(int, SignatureVisitor) CheckSignatureAdapter}. + * {@link #CheckSignatureAdapter(int, SignatureVisitor) + * CheckSignatureAdapter}. */ public static final int TYPE_SIGNATURE = 2; @@ -101,11 +104,13 @@ public class CheckSignatureAdapter extends SignatureVisitor { * not use this constructor</i>. Instead, they must use the * {@link #CheckSignatureAdapter(int, int, SignatureVisitor)} version. * - * @param type the type of signature to be checked. See - * {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and - * {@link #TYPE_SIGNATURE}. - * @param sv the visitor to which this adapter must delegate calls. May be - * <tt>null</tt>. + * @param type + * the type of signature to be checked. See + * {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and + * {@link #TYPE_SIGNATURE}. + * @param sv + * the visitor to which this adapter must delegate calls. May be + * <tt>null</tt>. */ public CheckSignatureAdapter(final int type, final SignatureVisitor sv) { this(Opcodes.ASM4, type, sv); @@ -114,19 +119,19 @@ public class CheckSignatureAdapter extends SignatureVisitor { /** * Creates a new {@link CheckSignatureAdapter} object. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. - * @param type the type of signature to be checked. See - * {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and - * {@link #TYPE_SIGNATURE}. - * @param sv the visitor to which this adapter must delegate calls. May be - * <tt>null</tt>. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param type + * the type of signature to be checked. See + * {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and + * {@link #TYPE_SIGNATURE}. + * @param sv + * the visitor to which this adapter must delegate calls. May be + * <tt>null</tt>. */ - protected CheckSignatureAdapter( - final int api, - final int type, - final SignatureVisitor sv) - { + protected CheckSignatureAdapter(final int api, final int type, + final SignatureVisitor sv) { super(api); this.type = type; this.state = EMPTY; @@ -138,8 +143,7 @@ public class CheckSignatureAdapter extends SignatureVisitor { @Override public void visitFormalTypeParameter(final String name) { if (type == TYPE_SIGNATURE - || (state != EMPTY && state != FORMAL && state != BOUND)) - { + || (state != EMPTY && state != FORMAL && state != BOUND)) { throw new IllegalStateException(); } CheckMethodAdapter.checkIdentifier(name, "formal type parameter"); @@ -172,8 +176,7 @@ public class CheckSignatureAdapter extends SignatureVisitor { @Override public SignatureVisitor visitSuperclass() { - if (type != CLASS_SIGNATURE || (state & (EMPTY | FORMAL | BOUND)) == 0) - { + if (type != CLASS_SIGNATURE || (state & (EMPTY | FORMAL | BOUND)) == 0) { throw new IllegalArgumentException(); } state = SUPER; @@ -195,8 +198,7 @@ public class CheckSignatureAdapter extends SignatureVisitor { @Override public SignatureVisitor visitParameterType() { if (type != METHOD_SIGNATURE - || (state & (EMPTY | FORMAL | BOUND | PARAM)) == 0) - { + || (state & (EMPTY | FORMAL | BOUND | PARAM)) == 0) { throw new IllegalArgumentException(); } state = PARAM; @@ -207,8 +209,7 @@ public class CheckSignatureAdapter extends SignatureVisitor { @Override public SignatureVisitor visitReturnType() { if (type != METHOD_SIGNATURE - || (state & (EMPTY | FORMAL | BOUND | PARAM)) == 0) - { + || (state & (EMPTY | FORMAL | BOUND | PARAM)) == 0) { throw new IllegalArgumentException(); } state = RETURN; diff --git a/src/asm/scala/tools/asm/util/Printer.java b/src/asm/scala/tools/asm/util/Printer.java index c39fd548ce..86e0f9e122 100644 --- a/src/asm/scala/tools/asm/util/Printer.java +++ b/src/asm/scala/tools/asm/util/Printer.java @@ -52,14 +52,14 @@ public abstract class Printer { /** * The names of the for <code>operand</code> parameter values of the - * {@link org.objectweb.asm.MethodVisitor#visitIntInsn} method when + * {@link scala.tools.asm.MethodVisitor#visitIntInsn} method when * <code>opcode</code> is <code>NEWARRAY</code>. */ public static final String[] TYPES; /** * The names of the <code>tag</code> field values for - * {@link org.objectweb.asm.Handle}. + * {@link scala.tools.asm.Handle}. */ public static final String[] HANDLE_TAG; @@ -103,8 +103,8 @@ public abstract class Printer { } s = "H_GETFIELD,H_GETSTATIC,H_PUTFIELD,H_PUTSTATIC," - + "H_INVOKEVIRTUAL,H_INVOKESTATIC,H_INVOKESPECIAL," - + "H_NEWINVOKESPECIAL,H_INVOKEINTERFACE,"; + + "H_INVOKEVIRTUAL,H_INVOKESTATIC,H_INVOKESPECIAL," + + "H_NEWINVOKESPECIAL,H_INVOKEINTERFACE,"; HANDLE_TAG = new String[10]; j = 0; i = 1; @@ -149,81 +149,58 @@ public abstract class Printer { } /** - * Class header. - * See {@link org.objectweb.asm.ClassVisitor#visit}. + * Class header. See {@link scala.tools.asm.ClassVisitor#visit}. */ - public abstract void visit( - final int version, - final int access, - final String name, - final String signature, - final String superName, - final String[] interfaces); + public abstract void visit(final int version, final int access, + final String name, final String signature, final String superName, + final String[] interfaces); /** - * Class source. - * See {@link org.objectweb.asm.ClassVisitor#visitSource}. + * Class source. See {@link scala.tools.asm.ClassVisitor#visitSource}. */ public abstract void visitSource(final String file, final String debug); /** - * Class outer class. - * See {@link org.objectweb.asm.ClassVisitor#visitOuterClass}. + * Class outer class. See + * {@link scala.tools.asm.ClassVisitor#visitOuterClass}. */ - public abstract void visitOuterClass( - final String owner, - final String name, - final String desc); + public abstract void visitOuterClass(final String owner, final String name, + final String desc); /** - * Class annotation. - * See {@link org.objectweb.asm.ClassVisitor#visitAnnotation}. + * Class annotation. See + * {@link scala.tools.asm.ClassVisitor#visitAnnotation}. */ - public abstract Printer visitClassAnnotation( - final String desc, - final boolean visible); + public abstract Printer visitClassAnnotation(final String desc, + final boolean visible); /** - * Class attribute. - * See {@link org.objectweb.asm.ClassVisitor#visitAttribute}. + * Class attribute. See + * {@link scala.tools.asm.ClassVisitor#visitAttribute}. */ public abstract void visitClassAttribute(final Attribute attr); /** - * Class inner name. - * See {@link org.objectweb.asm.ClassVisitor#visitInnerClass}. + * Class inner name. See + * {@link scala.tools.asm.ClassVisitor#visitInnerClass}. */ - public abstract void visitInnerClass( - final String name, - final String outerName, - final String innerName, - final int access); + public abstract void visitInnerClass(final String name, + final String outerName, final String innerName, final int access); /** - * Class field. - * See {@link org.objectweb.asm.ClassVisitor#visitField}. + * Class field. See {@link scala.tools.asm.ClassVisitor#visitField}. */ - public abstract Printer visitField( - final int access, - final String name, - final String desc, - final String signature, - final Object value); + public abstract Printer visitField(final int access, final String name, + final String desc, final String signature, final Object value); /** - * Class method. - * See {@link org.objectweb.asm.ClassVisitor#visitMethod}. + * Class method. See {@link scala.tools.asm.ClassVisitor#visitMethod}. */ - public abstract Printer visitMethod( - final int access, - final String name, - final String desc, - final String signature, - final String[] exceptions); + public abstract Printer visitMethod(final int access, final String name, + final String desc, final String signature, final String[] exceptions); /** - * Class end. - * See {@link org.objectweb.asm.ClassVisitor#visitEnd}. + * Class end. See {@link scala.tools.asm.ClassVisitor#visitEnd}. */ public abstract void visitClassEnd(); @@ -232,37 +209,31 @@ public abstract class Printer { // ------------------------------------------------------------------------ /** - * Annotation value. - * See {@link org.objectweb.asm.AnnotationVisitor#visit}. + * Annotation value. See {@link scala.tools.asm.AnnotationVisitor#visit}. */ public abstract void visit(final String name, final Object value); /** - * Annotation enum value. - * See {@link org.objectweb.asm.AnnotationVisitor#visitEnum}. + * Annotation enum value. See + * {@link scala.tools.asm.AnnotationVisitor#visitEnum}. */ - public abstract void visitEnum( - final String name, - final String desc, - final String value); + public abstract void visitEnum(final String name, final String desc, + final String value); /** - * Nested annotation value. - * See {@link org.objectweb.asm.AnnotationVisitor#visitAnnotation}. + * Nested annotation value. See + * {@link scala.tools.asm.AnnotationVisitor#visitAnnotation}. */ - public abstract Printer visitAnnotation( - final String name, - final String desc); + public abstract Printer visitAnnotation(final String name, final String desc); /** - * Annotation array value. - * See {@link org.objectweb.asm.AnnotationVisitor#visitArray}. + * Annotation array value. See + * {@link scala.tools.asm.AnnotationVisitor#visitArray}. */ public abstract Printer visitArray(final String name); /** - * Annotation end. - * See {@link org.objectweb.asm.AnnotationVisitor#visitEnd}. + * Annotation end. See {@link scala.tools.asm.AnnotationVisitor#visitEnd}. */ public abstract void visitAnnotationEnd(); @@ -271,22 +242,20 @@ public abstract class Printer { // ------------------------------------------------------------------------ /** - * Field annotation. - * See {@link org.objectweb.asm.FieldVisitor#visitAnnotation}. + * Field annotation. See + * {@link scala.tools.asm.FieldVisitor#visitAnnotation}. */ - public abstract Printer visitFieldAnnotation( - final String desc, - final boolean visible); + public abstract Printer visitFieldAnnotation(final String desc, + final boolean visible); /** - * Field attribute. - * See {@link org.objectweb.asm.FieldVisitor#visitAttribute}. + * Field attribute. See + * {@link scala.tools.asm.FieldVisitor#visitAttribute}. */ public abstract void visitFieldAttribute(final Attribute attr); /** - * Field end. - * See {@link org.objectweb.asm.FieldVisitor#visitEnd}. + * Field end. See {@link scala.tools.asm.FieldVisitor#visitEnd}. */ public abstract void visitFieldEnd(); @@ -295,193 +264,161 @@ public abstract class Printer { // ------------------------------------------------------------------------ /** - * Method default annotation. - * See {@link org.objectweb.asm.MethodVisitor#visitAnnotationDefault}. + * Method default annotation. See + * {@link scala.tools.asm.MethodVisitor#visitAnnotationDefault}. */ public abstract Printer visitAnnotationDefault(); /** - * Method annotation. - * See {@link org.objectweb.asm.MethodVisitor#visitAnnotation}. + * Method annotation. See + * {@link scala.tools.asm.MethodVisitor#visitAnnotation}. */ - public abstract Printer visitMethodAnnotation( - final String desc, - final boolean visible); + public abstract Printer visitMethodAnnotation(final String desc, + final boolean visible); /** - * Method parameter annotation. - * See {@link org.objectweb.asm.MethodVisitor#visitParameterAnnotation}. + * Method parameter annotation. See + * {@link scala.tools.asm.MethodVisitor#visitParameterAnnotation}. */ - public abstract Printer visitParameterAnnotation( - final int parameter, - final String desc, - final boolean visible); + public abstract Printer visitParameterAnnotation(final int parameter, + final String desc, final boolean visible); /** - * Method attribute. - * See {@link org.objectweb.asm.MethodVisitor#visitAttribute}. + * Method attribute. See + * {@link scala.tools.asm.MethodVisitor#visitAttribute}. */ public abstract void visitMethodAttribute(final Attribute attr); /** - * Method start. - * See {@link org.objectweb.asm.MethodVisitor#visitCode}. + * Method start. See {@link scala.tools.asm.MethodVisitor#visitCode}. */ public abstract void visitCode(); /** - * Method stack frame. - * See {@link org.objectweb.asm.MethodVisitor#visitFrame}. + * Method stack frame. See + * {@link scala.tools.asm.MethodVisitor#visitFrame}. */ - public abstract void visitFrame( - final int type, - final int nLocal, - final Object[] local, - final int nStack, - final Object[] stack); + public abstract void visitFrame(final int type, final int nLocal, + final Object[] local, final int nStack, final Object[] stack); /** - * Method instruction. - * See {@link org.objectweb.asm.MethodVisitor#visitInsn}. + * Method instruction. See {@link scala.tools.asm.MethodVisitor#visitInsn} + * . */ public abstract void visitInsn(final int opcode); /** - * Method instruction. - * See {@link org.objectweb.asm.MethodVisitor#visitIntInsn}. + * Method instruction. See + * {@link scala.tools.asm.MethodVisitor#visitIntInsn}. */ public abstract void visitIntInsn(final int opcode, final int operand); /** - * Method instruction. - * See {@link org.objectweb.asm.MethodVisitor#visitVarInsn}. + * Method instruction. See + * {@link scala.tools.asm.MethodVisitor#visitVarInsn}. */ public abstract void visitVarInsn(final int opcode, final int var); /** - * Method instruction. - * See {@link org.objectweb.asm.MethodVisitor#visitTypeInsn}. + * Method instruction. See + * {@link scala.tools.asm.MethodVisitor#visitTypeInsn}. */ public abstract void visitTypeInsn(final int opcode, final String type); /** - * Method instruction. - * See {@link org.objectweb.asm.MethodVisitor#visitFieldInsn}. + * Method instruction. See + * {@link scala.tools.asm.MethodVisitor#visitFieldInsn}. */ - public abstract void visitFieldInsn( - final int opcode, - final String owner, - final String name, - final String desc); + public abstract void visitFieldInsn(final int opcode, final String owner, + final String name, final String desc); /** - * Method instruction. - * See {@link org.objectweb.asm.MethodVisitor#visitMethodInsn}. + * Method instruction. See + * {@link scala.tools.asm.MethodVisitor#visitMethodInsn}. */ - public abstract void visitMethodInsn( - final int opcode, - final String owner, - final String name, - final String desc); + public abstract void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc); /** - * Method instruction. - * See {@link org.objectweb.asm.MethodVisitor#visitInvokeDynamicInsn}. + * Method instruction. See + * {@link scala.tools.asm.MethodVisitor#visitInvokeDynamicInsn}. */ - public abstract void visitInvokeDynamicInsn( - String name, - String desc, - Handle bsm, - Object... bsmArgs); + public abstract void visitInvokeDynamicInsn(String name, String desc, + Handle bsm, Object... bsmArgs); /** - * Method instruction. - * See {@link org.objectweb.asm.MethodVisitor#visitJumpInsn}. + * Method instruction. See + * {@link scala.tools.asm.MethodVisitor#visitJumpInsn}. */ public abstract void visitJumpInsn(final int opcode, final Label label); /** - * Method label. - * See {@link org.objectweb.asm.MethodVisitor#visitLabel}. + * Method label. See {@link scala.tools.asm.MethodVisitor#visitLabel}. */ public abstract void visitLabel(final Label label); /** - * Method instruction. - * See {@link org.objectweb.asm.MethodVisitor#visitLdcInsn}. + * Method instruction. See + * {@link scala.tools.asm.MethodVisitor#visitLdcInsn}. */ public abstract void visitLdcInsn(final Object cst); /** - * Method instruction. - * See {@link org.objectweb.asm.MethodVisitor#visitIincInsn}. + * Method instruction. See + * {@link scala.tools.asm.MethodVisitor#visitIincInsn}. */ public abstract void visitIincInsn(final int var, final int increment); /** - * Method instruction. - * See {@link org.objectweb.asm.MethodVisitor#visitTableSwitchInsn}. + * Method instruction. See + * {@link scala.tools.asm.MethodVisitor#visitTableSwitchInsn}. */ - public abstract void visitTableSwitchInsn( - final int min, - final int max, - final Label dflt, - final Label... labels); + public abstract void visitTableSwitchInsn(final int min, final int max, + final Label dflt, final Label... labels); /** - * Method instruction. - * See {@link org.objectweb.asm.MethodVisitor#visitLookupSwitchInsn}. + * Method instruction. See + * {@link scala.tools.asm.MethodVisitor#visitLookupSwitchInsn}. */ - public abstract void visitLookupSwitchInsn( - final Label dflt, - final int[] keys, - final Label[] labels); + public abstract void visitLookupSwitchInsn(final Label dflt, + final int[] keys, final Label[] labels); /** - * Method instruction. - * See {@link org.objectweb.asm.MethodVisitor#visitMultiANewArrayInsn}. + * Method instruction. See + * {@link scala.tools.asm.MethodVisitor#visitMultiANewArrayInsn}. */ - public abstract void visitMultiANewArrayInsn( - final String desc, - final int dims); + public abstract void visitMultiANewArrayInsn(final String desc, + final int dims); /** - * Method exception handler. - * See {@link org.objectweb.asm.MethodVisitor#visitTryCatchBlock}. + * Method exception handler. See + * {@link scala.tools.asm.MethodVisitor#visitTryCatchBlock}. */ - public abstract void visitTryCatchBlock( - final Label start, - final Label end, - final Label handler, - final String type); + public abstract void visitTryCatchBlock(final Label start, final Label end, + final Label handler, final String type); /** - * Method debug info. - * See {@link org.objectweb.asm.MethodVisitor#visitLocalVariable}. + * Method debug info. See + * {@link scala.tools.asm.MethodVisitor#visitLocalVariable}. */ - public abstract void visitLocalVariable( - final String name, - final String desc, - final String signature, - final Label start, - final Label end, - final int index); + public abstract void visitLocalVariable(final String name, + final String desc, final String signature, final Label start, + final Label end, final int index); /** - * Method debug info. - * See {@link org.objectweb.asm.MethodVisitor#visitLineNumber}. + * Method debug info. See + * {@link scala.tools.asm.MethodVisitor#visitLineNumber}. */ public abstract void visitLineNumber(final int line, final Label start); /** - * Method max stack and max locals. - * See {@link org.objectweb.asm.MethodVisitor#visitMaxs}. + * Method max stack and max locals. See + * {@link scala.tools.asm.MethodVisitor#visitMaxs}. */ public abstract void visitMaxs(final int maxStack, final int maxLocals); /** - * Method end. - * See {@link org.objectweb.asm.MethodVisitor#visitEnd}. + * Method end. See {@link scala.tools.asm.MethodVisitor#visitEnd}. */ public abstract void visitMethodEnd(); @@ -497,7 +434,8 @@ public abstract class Printer { /** * Prints the text constructed by this visitor. * - * @param pw the print writer to be used. + * @param pw + * the print writer to be used. */ public void print(final PrintWriter pw) { printList(pw, text); @@ -506,8 +444,10 @@ public abstract class Printer { /** * Appends a quoted string to a given buffer. * - * @param buf the buffer where the string must be added. - * @param s the string to be added. + * @param buf + * the buffer where the string must be added. + * @param s + * the string to be added. */ public static void appendString(final StringBuffer buf, final String s) { buf.append('\"'); @@ -541,9 +481,11 @@ public abstract class Printer { /** * Prints the given string tree. * - * @param pw the writer to be used to print the tree. - * @param l a string tree, i.e., a string list that can contain other string - * lists, and so on recursively. + * @param pw + * the writer to be used to print the tree. + * @param l + * a string tree, i.e., a string list that can contain other + * string lists, and so on recursively. */ static void printList(final PrintWriter pw, final List<?> l) { for (int i = 0; i < l.size(); ++i) { diff --git a/src/asm/scala/tools/asm/util/SignatureChecker.java b/src/asm/scala/tools/asm/util/SignatureChecker.java deleted file mode 100644 index 71f0d80027..0000000000 --- a/src/asm/scala/tools/asm/util/SignatureChecker.java +++ /dev/null @@ -1,47 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - */ - -package scala.tools.asm.util; - -import scala.tools.asm.util.CheckMethodAdapter; -import scala.tools.asm.MethodVisitor; - -/** - * A subclass of ASM's CheckMethodAdapter for the sole purpose of accessing some protected methods there. - * - */ -public class SignatureChecker extends CheckMethodAdapter { - - public SignatureChecker(final MethodVisitor mv) { - super(mv); - } - - /** - * Checks a class signature. - * - * @param signature a string containing the signature that must be checked. - */ - public static void checkClassSignature(final String signature) { - CheckMethodAdapter.checkClassSignature(signature); - } - - /** - * Checks a method signature. - * - * @param signature a string containing the signature that must be checked. - */ - public static void checkMethodSignature(final String signature) { - CheckMethodAdapter.checkMethodSignature(signature); - } - - /** - * Checks a field signature. - * - * @param signature a string containing the signature that must be checked. - */ - public static void checkFieldSignature(final String signature) { - CheckMethodAdapter.checkFieldSignature(signature); - } - -} diff --git a/src/asm/scala/tools/asm/util/Textifiable.java b/src/asm/scala/tools/asm/util/Textifiable.java index b80d0139db..85e051e2f8 100644 --- a/src/asm/scala/tools/asm/util/Textifiable.java +++ b/src/asm/scala/tools/asm/util/Textifiable.java @@ -34,7 +34,7 @@ import java.util.Map; import scala.tools.asm.Label; /** - * An {@link org.objectweb.asm.Attribute Attribute} that can print a readable + * An {@link scala.tools.asm.Attribute Attribute} that can print a readable * representation of itself. * * Implementations should construct readable output from an attribute data @@ -47,8 +47,10 @@ public interface Textifiable { /** * Build a human readable representation of this attribute. * - * @param buf a buffer used for printing Java code. - * @param labelNames map of label instances to their names. + * @param buf + * a buffer used for printing Java code. + * @param labelNames + * map of label instances to their names. */ void textify(StringBuffer buf, Map<Label, String> labelNames); } diff --git a/src/asm/scala/tools/asm/util/Textifier.java b/src/asm/scala/tools/asm/util/Textifier.java index 8d40ebd026..a5c4f6779e 100644 --- a/src/asm/scala/tools/asm/util/Textifier.java +++ b/src/asm/scala/tools/asm/util/Textifier.java @@ -149,22 +149,24 @@ public class Textifier extends Printer { /** * Constructs a new {@link Textifier}. * - * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4}. + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. */ protected Textifier(final int api) { super(api); } /** - * Prints a disassembled view of the given class to the standard output. <p> - * Usage: Textifier [-debug] <binary class name or class - * file name > + * Prints a disassembled view of the given class to the standard output. + * <p> + * Usage: Textifier [-debug] <binary class name or class file name > * - * @param args the command line arguments. + * @param args + * the command line arguments. * - * @throws Exception if the class cannot be found, or if an IO exception - * occurs. + * @throws Exception + * if the class cannot be found, or if an IO exception occurs. */ public static void main(final String[] args) throws Exception { int i = 0; @@ -182,21 +184,20 @@ public class Textifier extends Printer { } } if (!ok) { - System.err.println("Prints a disassembled view of the given class."); + System.err + .println("Prints a disassembled view of the given class."); System.err.println("Usage: Textifier [-debug] " + "<fully qualified class name or class file name>"); return; } ClassReader cr; if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1 - || args[i].indexOf('/') > -1) - { + || args[i].indexOf('/') > -1) { cr = new ClassReader(new FileInputStream(args[i])); } else { cr = new ClassReader(args[i]); } - cr.accept(new TraceClassVisitor(new PrintWriter(System.out)), - flags); + cr.accept(new TraceClassVisitor(new PrintWriter(System.out)), flags); } // ------------------------------------------------------------------------ @@ -204,38 +205,27 @@ public class Textifier extends Printer { // ------------------------------------------------------------------------ @Override - public void visit( - final int version, - final int access, - final String name, - final String signature, - final String superName, - final String[] interfaces) - { + public void visit(final int version, final int access, final String name, + final String signature, final String superName, + final String[] interfaces) { int major = version & 0xFFFF; int minor = version >>> 16; buf.setLength(0); - buf.append("// class version ") - .append(major) - .append('.') - .append(minor) - .append(" (") - .append(version) - .append(")\n"); + buf.append("// class version ").append(major).append('.').append(minor) + .append(" (").append(version).append(")\n"); if ((access & Opcodes.ACC_DEPRECATED) != 0) { buf.append("// DEPRECATED\n"); } - buf.append("// access flags 0x").append(Integer.toHexString(access).toUpperCase()).append('\n'); + buf.append("// access flags 0x") + .append(Integer.toHexString(access).toUpperCase()).append('\n'); appendDescriptor(CLASS_SIGNATURE, signature); if (signature != null) { TraceSignatureVisitor sv = new TraceSignatureVisitor(access); SignatureReader r = new SignatureReader(signature); r.accept(sv); - buf.append("// declaration: ") - .append(name) - .append(sv.getDeclaration()) - .append('\n'); + buf.append("// declaration: ").append(name) + .append(sv.getDeclaration()).append('\n'); } appendAccess(access & ~Opcodes.ACC_SUPER); @@ -269,15 +259,11 @@ public class Textifier extends Printer { public void visitSource(final String file, final String debug) { buf.setLength(0); if (file != null) { - buf.append(tab) - .append("// compiled from: ") - .append(file) + buf.append(tab).append("// compiled from: ").append(file) .append('\n'); } if (debug != null) { - buf.append(tab) - .append("// debug info: ") - .append(debug) + buf.append(tab).append("// debug info: ").append(debug) .append('\n'); } if (buf.length() > 0) { @@ -286,11 +272,8 @@ public class Textifier extends Printer { } @Override - public void visitOuterClass( - final String owner, - final String name, - final String desc) - { + public void visitOuterClass(final String owner, final String name, + final String desc) { buf.setLength(0); buf.append(tab).append("OUTERCLASS "); appendDescriptor(INTERNAL_NAME, owner); @@ -304,10 +287,8 @@ public class Textifier extends Printer { } @Override - public Textifier visitClassAnnotation( - final String desc, - final boolean visible) - { + public Textifier visitClassAnnotation(final String desc, + final boolean visible) { text.add("\n"); return visitAnnotation(desc, visible); } @@ -319,15 +300,13 @@ public class Textifier extends Printer { } @Override - public void visitInnerClass( - final String name, - final String outerName, - final String innerName, - final int access) - { + public void visitInnerClass(final String name, final String outerName, + final String innerName, final int access) { buf.setLength(0); buf.append(tab).append("// access flags 0x"); - buf.append(Integer.toHexString(access & ~Opcodes.ACC_SUPER).toUpperCase()).append('\n'); + buf.append( + Integer.toHexString(access & ~Opcodes.ACC_SUPER).toUpperCase()) + .append('\n'); buf.append(tab); appendAccess(access); buf.append("INNERCLASS "); @@ -341,19 +320,15 @@ public class Textifier extends Printer { } @Override - public Textifier visitField( - final int access, - final String name, - final String desc, - final String signature, - final Object value) - { + public Textifier visitField(final int access, final String name, + final String desc, final String signature, final Object value) { buf.setLength(0); buf.append('\n'); if ((access & Opcodes.ACC_DEPRECATED) != 0) { buf.append(tab).append("// DEPRECATED\n"); } - buf.append(tab).append("// access flags 0x").append(Integer.toHexString(access).toUpperCase()).append('\n'); + buf.append(tab).append("// access flags 0x") + .append(Integer.toHexString(access).toUpperCase()).append('\n'); if (signature != null) { buf.append(tab); appendDescriptor(FIELD_SIGNATURE, signature); @@ -361,10 +336,8 @@ public class Textifier extends Printer { TraceSignatureVisitor sv = new TraceSignatureVisitor(0); SignatureReader r = new SignatureReader(signature); r.acceptType(sv); - buf.append(tab) - .append("// declaration: ") - .append(sv.getDeclaration()) - .append('\n'); + buf.append(tab).append("// declaration: ") + .append(sv.getDeclaration()).append('\n'); } buf.append(tab); @@ -390,19 +363,15 @@ public class Textifier extends Printer { } @Override - public Textifier visitMethod( - final int access, - final String name, - final String desc, - final String signature, - final String[] exceptions) - { + public Textifier visitMethod(final int access, final String name, + final String desc, final String signature, final String[] exceptions) { buf.setLength(0); buf.append('\n'); if ((access & Opcodes.ACC_DEPRECATED) != 0) { buf.append(tab).append("// DEPRECATED\n"); } - buf.append(tab).append("// access flags 0x").append(Integer.toHexString(access).toUpperCase()).append('\n'); + buf.append(tab).append("// access flags 0x") + .append(Integer.toHexString(access).toUpperCase()).append('\n'); if (signature != null) { buf.append(tab); @@ -415,12 +384,8 @@ public class Textifier extends Printer { String genericReturn = v.getReturnType(); String genericExceptions = v.getExceptions(); - buf.append(tab) - .append("// declaration: ") - .append(genericReturn) - .append(' ') - .append(name) - .append(genericDecl); + buf.append(tab).append("// declaration: ").append(genericReturn) + .append(' ').append(name).append(genericDecl); if (genericExceptions != null) { buf.append(" throws ").append(genericExceptions); } @@ -593,11 +558,8 @@ public class Textifier extends Printer { } @Override - public void visitEnum( - final String name, - final String desc, - final String value) - { + public void visitEnum(final String name, final String desc, + final String value) { buf.setLength(0); appendComa(valueNumber++); if (name != null) { @@ -609,10 +571,7 @@ public class Textifier extends Printer { } @Override - public Textifier visitAnnotation( - final String name, - final String desc) - { + public Textifier visitAnnotation(final String name, final String desc) { buf.setLength(0); appendComa(valueNumber++); if (name != null) { @@ -629,9 +588,7 @@ public class Textifier extends Printer { } @Override - public Textifier visitArray( - final String name) - { + public Textifier visitArray(final String name) { buf.setLength(0); appendComa(valueNumber++); if (name != null) { @@ -654,10 +611,8 @@ public class Textifier extends Printer { // ------------------------------------------------------------------------ @Override - public Textifier visitFieldAnnotation( - final String desc, - final boolean visible) - { + public Textifier visitFieldAnnotation(final String desc, + final boolean visible) { return visitAnnotation(desc, visible); } @@ -684,19 +639,14 @@ public class Textifier extends Printer { } @Override - public Textifier visitMethodAnnotation( - final String desc, - final boolean visible) - { + public Textifier visitMethodAnnotation(final String desc, + final boolean visible) { return visitAnnotation(desc, visible); } @Override - public Textifier visitParameterAnnotation( - final int parameter, - final String desc, - final boolean visible) - { + public Textifier visitParameterAnnotation(final int parameter, + final String desc, final boolean visible) { buf.setLength(0); buf.append(tab2).append('@'); appendDescriptor(FIELD_DESCRIPTOR, desc); @@ -730,40 +680,35 @@ public class Textifier extends Printer { } @Override - public void visitFrame( - final int type, - final int nLocal, - final Object[] local, - final int nStack, - final Object[] stack) - { + public void visitFrame(final int type, final int nLocal, + final Object[] local, final int nStack, final Object[] stack) { buf.setLength(0); buf.append(ltab); buf.append("FRAME "); switch (type) { - case Opcodes.F_NEW: - case Opcodes.F_FULL: - buf.append("FULL ["); - appendFrameTypes(nLocal, local); - buf.append("] ["); - appendFrameTypes(nStack, stack); - buf.append(']'); - break; - case Opcodes.F_APPEND: - buf.append("APPEND ["); - appendFrameTypes(nLocal, local); - buf.append(']'); - break; - case Opcodes.F_CHOP: - buf.append("CHOP ").append(nLocal); - break; - case Opcodes.F_SAME: - buf.append("SAME"); - break; - case Opcodes.F_SAME1: - buf.append("SAME1 "); - appendFrameTypes(1, stack); - break; + case Opcodes.F_NEW: + case Opcodes.F_FULL: + buf.append("FULL ["); + appendFrameTypes(nLocal, local); + buf.append("] ["); + appendFrameTypes(nStack, stack); + buf.append(']'); + break; + case Opcodes.F_APPEND: + buf.append("APPEND ["); + appendFrameTypes(nLocal, local); + buf.append(']'); + break; + case Opcodes.F_CHOP: + buf.append("CHOP ").append(nLocal); + break; + case Opcodes.F_SAME: + buf.append("SAME"); + break; + case Opcodes.F_SAME1: + buf.append("SAME1 "); + appendFrameTypes(1, stack); + break; } buf.append('\n'); text.add(buf.toString()); @@ -782,20 +727,15 @@ public class Textifier extends Printer { buf.append(tab2) .append(OPCODES[opcode]) .append(' ') - .append(opcode == Opcodes.NEWARRAY - ? TYPES[operand] - : Integer.toString(operand)) - .append('\n'); + .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer + .toString(operand)).append('\n'); text.add(buf.toString()); } @Override public void visitVarInsn(final int opcode, final int var) { buf.setLength(0); - buf.append(tab2) - .append(OPCODES[opcode]) - .append(' ') - .append(var) + buf.append(tab2).append(OPCODES[opcode]).append(' ').append(var) .append('\n'); text.add(buf.toString()); } @@ -810,12 +750,8 @@ public class Textifier extends Printer { } @Override - public void visitFieldInsn( - final int opcode, - final String owner, - final String name, - final String desc) - { + public void visitFieldInsn(final int opcode, final String owner, + final String name, final String desc) { buf.setLength(0); buf.append(tab2).append(OPCODES[opcode]).append(' '); appendDescriptor(INTERNAL_NAME, owner); @@ -826,12 +762,8 @@ public class Textifier extends Printer { } @Override - public void visitMethodInsn( - final int opcode, - final String owner, - final String name, - final String desc) - { + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { buf.setLength(0); buf.append(tab2).append(OPCODES[opcode]).append(' '); appendDescriptor(INTERNAL_NAME, owner); @@ -842,12 +774,8 @@ public class Textifier extends Printer { } @Override - public void visitInvokeDynamicInsn( - String name, - String desc, - Handle bsm, - Object... bsmArgs) - { + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, + Object... bsmArgs) { buf.setLength(0); buf.append(tab2).append("INVOKEDYNAMIC").append(' '); buf.append(name); @@ -855,11 +783,11 @@ public class Textifier extends Printer { buf.append(" ["); appendHandle(bsm); buf.append(tab3).append("// arguments:"); - if(bsmArgs.length == 0) { + if (bsmArgs.length == 0) { buf.append(" none"); } else { buf.append('\n').append(tab3); - for(int i = 0; i < bsmArgs.length; i++) { + for (int i = 0; i < bsmArgs.length; i++) { Object cst = bsmArgs[i]; if (cst instanceof String) { Printer.appendString(buf, (String) cst); @@ -915,22 +843,14 @@ public class Textifier extends Printer { @Override public void visitIincInsn(final int var, final int increment) { buf.setLength(0); - buf.append(tab2) - .append("IINC ") - .append(var) - .append(' ') - .append(increment) - .append('\n'); + buf.append(tab2).append("IINC ").append(var).append(' ') + .append(increment).append('\n'); text.add(buf.toString()); } @Override - public void visitTableSwitchInsn( - final int min, - final int max, - final Label dflt, - final Label... labels) - { + public void visitTableSwitchInsn(final int min, final int max, + final Label dflt, final Label... labels) { buf.setLength(0); buf.append(tab2).append("TABLESWITCH\n"); for (int i = 0; i < labels.length; ++i) { @@ -945,11 +865,8 @@ public class Textifier extends Printer { } @Override - public void visitLookupSwitchInsn( - final Label dflt, - final int[] keys, - final Label[] labels) - { + public void visitLookupSwitchInsn(final Label dflt, final int[] keys, + final Label[] labels) { buf.setLength(0); buf.append(tab2).append("LOOKUPSWITCH\n"); for (int i = 0; i < labels.length; ++i) { @@ -973,12 +890,8 @@ public class Textifier extends Printer { } @Override - public void visitTryCatchBlock( - final Label start, - final Label end, - final Label handler, - final String type) - { + public void visitTryCatchBlock(final Label start, final Label end, + final Label handler, final String type) { buf.setLength(0); buf.append(tab2).append("TRYCATCHBLOCK "); appendLabel(start); @@ -993,14 +906,9 @@ public class Textifier extends Printer { } @Override - public void visitLocalVariable( - final String name, - final String desc, - final String signature, - final Label start, - final Label end, - final int index) - { + public void visitLocalVariable(final String name, final String desc, + final String signature, final Label start, final Label end, + final int index) { buf.setLength(0); buf.append(tab2).append("LOCALVARIABLE ").append(name).append(' '); appendDescriptor(FIELD_DESCRIPTOR, desc); @@ -1017,10 +925,8 @@ public class Textifier extends Printer { TraceSignatureVisitor sv = new TraceSignatureVisitor(0); SignatureReader r = new SignatureReader(signature); r.acceptType(sv); - buf.append(tab2) - .append("// declaration: ") - .append(sv.getDeclaration()) - .append('\n'); + buf.append(tab2).append("// declaration: ") + .append(sv.getDeclaration()).append('\n'); } text.add(buf.toString()); } @@ -1056,14 +962,13 @@ public class Textifier extends Printer { /** * Prints a disassembled view of the given annotation. * - * @param desc the class descriptor of the annotation class. - * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * <tt>true</tt> if the annotation is visible at runtime. * @return a visitor to visit the annotation values. */ - public Textifier visitAnnotation( - final String desc, - final boolean visible) - { + public Textifier visitAnnotation(final String desc, final boolean visible) { buf.setLength(0); buf.append(tab).append('@'); appendDescriptor(FIELD_DESCRIPTOR, desc); @@ -1078,7 +983,8 @@ public class Textifier extends Printer { /** * Prints a disassembled view of the given attribute. * - * @param attr an attribute. + * @param attr + * an attribute. */ public void visitAttribute(final Attribute attr) { buf.setLength(0); @@ -1111,15 +1017,16 @@ public class Textifier extends Printer { * Appends an internal name, a type descriptor or a type signature to * {@link #buf buf}. * - * @param type indicates if desc is an internal name, a field descriptor, a - * method descriptor, a class signature, ... - * @param desc an internal name, type descriptor, or type signature. May be - * <tt>null</tt>. + * @param type + * indicates if desc is an internal name, a field descriptor, a + * method descriptor, a class signature, ... + * @param desc + * an internal name, type descriptor, or type signature. May be + * <tt>null</tt>. */ protected void appendDescriptor(final int type, final String desc) { if (type == CLASS_SIGNATURE || type == FIELD_SIGNATURE - || type == METHOD_SIGNATURE) - { + || type == METHOD_SIGNATURE) { if (desc != null) { buf.append("// signature ").append(desc).append('\n'); } @@ -1132,7 +1039,8 @@ public class Textifier extends Printer { * Appends the name of the given label to {@link #buf buf}. Creates a new * label name if the given label does not yet have one. * - * @param l a label. + * @param l + * a label. */ protected void appendLabel(final Label l) { if (labelNames == null) { @@ -1149,40 +1057,42 @@ public class Textifier extends Printer { /** * Appends the information about the given handle to {@link #buf buf}. * - * @param h a handle, non null. + * @param h + * a handle, non null. */ protected void appendHandle(final Handle h) { buf.append('\n').append(tab3); int tag = h.getTag(); - buf.append("// handle kind 0x").append(Integer.toHexString(tag)).append(" : "); + buf.append("// handle kind 0x").append(Integer.toHexString(tag)) + .append(" : "); switch (tag) { - case Opcodes.H_GETFIELD: - buf.append("GETFIELD"); - break; - case Opcodes.H_GETSTATIC: - buf.append("GETSTATIC"); - break; - case Opcodes.H_PUTFIELD: - buf.append("PUTFIELD"); - break; - case Opcodes.H_PUTSTATIC: - buf.append("PUTSTATIC"); - break; - case Opcodes.H_INVOKEINTERFACE: - buf.append("INVOKEINTERFACE"); - break; - case Opcodes.H_INVOKESPECIAL: - buf.append("INVOKESPECIAL"); - break; - case Opcodes.H_INVOKESTATIC: - buf.append("INVOKESTATIC"); - break; - case Opcodes.H_INVOKEVIRTUAL: - buf.append("INVOKEVIRTUAL"); - break; - case Opcodes.H_NEWINVOKESPECIAL: - buf.append("NEWINVOKESPECIAL"); - break; + case Opcodes.H_GETFIELD: + buf.append("GETFIELD"); + break; + case Opcodes.H_GETSTATIC: + buf.append("GETSTATIC"); + break; + case Opcodes.H_PUTFIELD: + buf.append("PUTFIELD"); + break; + case Opcodes.H_PUTSTATIC: + buf.append("PUTSTATIC"); + break; + case Opcodes.H_INVOKEINTERFACE: + buf.append("INVOKEINTERFACE"); + break; + case Opcodes.H_INVOKESPECIAL: + buf.append("INVOKESPECIAL"); + break; + case Opcodes.H_INVOKESTATIC: + buf.append("INVOKESTATIC"); + break; + case Opcodes.H_INVOKEVIRTUAL: + buf.append("INVOKEVIRTUAL"); + break; + case Opcodes.H_NEWINVOKESPECIAL: + buf.append("NEWINVOKESPECIAL"); + break; } buf.append('\n'); buf.append(tab3); @@ -1195,10 +1105,11 @@ public class Textifier extends Printer { } /** - * Appends a string representation of the given access modifiers to {@link - * #buf buf}. + * Appends a string representation of the given access modifiers to + * {@link #buf buf}. * - * @param access some access modifiers. + * @param access + * some access modifiers. */ private void appendAccess(final int access) { if ((access & Opcodes.ACC_PUBLIC) != 0) { @@ -1231,6 +1142,9 @@ public class Textifier extends Printer { if ((access & Opcodes.ACC_STRICT) != 0) { buf.append("strictfp "); } + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + buf.append("synthetic "); + } if ((access & Opcodes.ACC_ENUM) != 0) { buf.append("enum "); } @@ -1256,27 +1170,27 @@ public class Textifier extends Printer { } } else if (o[i] instanceof Integer) { switch (((Integer) o[i]).intValue()) { - case 0: - appendDescriptor(FIELD_DESCRIPTOR, "T"); - break; - case 1: - appendDescriptor(FIELD_DESCRIPTOR, "I"); - break; - case 2: - appendDescriptor(FIELD_DESCRIPTOR, "F"); - break; - case 3: - appendDescriptor(FIELD_DESCRIPTOR, "D"); - break; - case 4: - appendDescriptor(FIELD_DESCRIPTOR, "J"); - break; - case 5: - appendDescriptor(FIELD_DESCRIPTOR, "N"); - break; - case 6: - appendDescriptor(FIELD_DESCRIPTOR, "U"); - break; + case 0: + appendDescriptor(FIELD_DESCRIPTOR, "T"); + break; + case 1: + appendDescriptor(FIELD_DESCRIPTOR, "I"); + break; + case 2: + appendDescriptor(FIELD_DESCRIPTOR, "F"); + break; + case 3: + appendDescriptor(FIELD_DESCRIPTOR, "D"); + break; + case 4: + appendDescriptor(FIELD_DESCRIPTOR, "J"); + break; + case 5: + appendDescriptor(FIELD_DESCRIPTOR, "N"); + break; + case 6: + appendDescriptor(FIELD_DESCRIPTOR, "U"); + break; } } else { appendLabel((Label) o[i]); diff --git a/src/asm/scala/tools/asm/util/TraceAnnotationVisitor.java b/src/asm/scala/tools/asm/util/TraceAnnotationVisitor.java index f112609031..33e7cf0b26 100644 --- a/src/asm/scala/tools/asm/util/TraceAnnotationVisitor.java +++ b/src/asm/scala/tools/asm/util/TraceAnnotationVisitor.java @@ -58,33 +58,26 @@ public final class TraceAnnotationVisitor extends AnnotationVisitor { } @Override - public void visitEnum( - final String name, - final String desc, - final String value) - { + public void visitEnum(final String name, final String desc, + final String value) { p.visitEnum(name, desc, value); super.visitEnum(name, desc, value); } @Override - public AnnotationVisitor visitAnnotation( - final String name, - final String desc) - { + public AnnotationVisitor visitAnnotation(final String name, + final String desc) { Printer p = this.p.visitAnnotation(name, desc); - AnnotationVisitor av = this.av == null - ? null - : this.av.visitAnnotation(name, desc); + AnnotationVisitor av = this.av == null ? null : this.av + .visitAnnotation(name, desc); return new TraceAnnotationVisitor(av, p); } @Override public AnnotationVisitor visitArray(final String name) { Printer p = this.p.visitArray(name); - AnnotationVisitor av = this.av == null - ? null - : this.av.visitArray(name); + AnnotationVisitor av = this.av == null ? null : this.av + .visitArray(name); return new TraceAnnotationVisitor(av, p); } diff --git a/src/asm/scala/tools/asm/util/TraceClassVisitor.java b/src/asm/scala/tools/asm/util/TraceClassVisitor.java index bb830b71ce..ff7a017482 100644 --- a/src/asm/scala/tools/asm/util/TraceClassVisitor.java +++ b/src/asm/scala/tools/asm/util/TraceClassVisitor.java @@ -42,30 +42,41 @@ import scala.tools.asm.Opcodes; * A {@link ClassVisitor} that prints the classes it visits with a * {@link Printer}. This class visitor can be used in the middle of a class * visitor chain to trace the class that is visited at a given point in this - * chain. This may be useful for debugging purposes. <p> The trace printed when - * visiting the <tt>Hello</tt> class is the following: <p> <blockquote> - * - * <pre> // class version 49.0 (49) // access flags 0x21 public class Hello { - * + * chain. This may be useful for debugging purposes. + * <p> + * The trace printed when visiting the <tt>Hello</tt> class is the following: + * <p> + * <blockquote> + * + * <pre> + * // class version 49.0 (49) // access flags 0x21 public class Hello { + * * // compiled from: Hello.java - * + * * // access flags 0x1 public <init> ()V ALOAD 0 INVOKESPECIAL * java/lang/Object <init> ()V RETURN MAXSTACK = 1 MAXLOCALS = 1 - * + * * // access flags 0x9 public static main ([Ljava/lang/String;)V GETSTATIC * java/lang/System out Ljava/io/PrintStream; LDC "hello" * INVOKEVIRTUAL java/io/PrintStream println (Ljava/lang/String;)V RETURN - * MAXSTACK = 2 MAXLOCALS = 1 } </pre> - * - * </blockquote> where <tt>Hello</tt> is defined by: <p> <blockquote> - * - * <pre> public class Hello { - * - * public static void main(String[] args) { - * System.out.println("hello"); } } </pre> - * + * MAXSTACK = 2 MAXLOCALS = 1 } + * </pre> + * + * </blockquote> where <tt>Hello</tt> is defined by: + * <p> + * <blockquote> + * + * <pre> + * public class Hello { + * + * public static void main(String[] args) { + * System.out.println("hello"); + * } + * } + * </pre> + * * </blockquote> - * + * * @author Eric Bruneton * @author Eugene Kuleshov */ @@ -83,8 +94,9 @@ public final class TraceClassVisitor extends ClassVisitor { /** * Constructs a new {@link TraceClassVisitor}. - * - * @param pw the print writer to be used to print the class. + * + * @param pw + * the print writer to be used to print the class. */ public TraceClassVisitor(final PrintWriter pw) { this(null, pw); @@ -92,10 +104,12 @@ public final class TraceClassVisitor extends ClassVisitor { /** * Constructs a new {@link TraceClassVisitor}. - * - * @param cv the {@link ClassVisitor} to which this visitor delegates calls. - * May be <tt>null</tt>. - * @param pw the print writer to be used to print the class. + * + * @param cv + * the {@link ClassVisitor} to which this visitor delegates + * calls. May be <tt>null</tt>. + * @param pw + * the print writer to be used to print the class. */ public TraceClassVisitor(final ClassVisitor cv, final PrintWriter pw) { this(cv, new Textifier(), pw); @@ -103,33 +117,28 @@ public final class TraceClassVisitor extends ClassVisitor { /** * Constructs a new {@link TraceClassVisitor}. - * - * @param cv the {@link ClassVisitor} to which this visitor delegates calls. - * May be <tt>null</tt>. - * @param p the object that actually converts visit events into text. - * @param pw the print writer to be used to print the class. May be null if - * you simply want to use the result via - * {@link Printer#getText()}, instead of printing it. + * + * @param cv + * the {@link ClassVisitor} to which this visitor delegates + * calls. May be <tt>null</tt>. + * @param p + * the object that actually converts visit events into text. + * @param pw + * the print writer to be used to print the class. May be null if + * you simply want to use the result via + * {@link Printer#getText()}, instead of printing it. */ - public TraceClassVisitor( - final ClassVisitor cv, - final Printer p, - final PrintWriter pw) - { + public TraceClassVisitor(final ClassVisitor cv, final Printer p, + final PrintWriter pw) { super(Opcodes.ASM4, cv); this.pw = pw; this.p = p; } @Override - public void visit( - final int version, - final int access, - final String name, - final String signature, - final String superName, - final String[] interfaces) - { + public void visit(final int version, final int access, final String name, + final String signature, final String superName, + final String[] interfaces) { p.visit(version, access, name, signature, superName, interfaces); super.visit(version, access, name, signature, superName, interfaces); } @@ -141,20 +150,15 @@ public final class TraceClassVisitor extends ClassVisitor { } @Override - public void visitOuterClass( - final String owner, - final String name, - final String desc) - { + public void visitOuterClass(final String owner, final String name, + final String desc) { p.visitOuterClass(owner, name, desc); super.visitOuterClass(owner, name, desc); } @Override - public AnnotationVisitor visitAnnotation( - final String desc, - final boolean visible) - { + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { Printer p = this.p.visitClassAnnotation(desc, visible); AnnotationVisitor av = cv == null ? null : cv.visitAnnotation(desc, visible); @@ -168,55 +172,28 @@ public final class TraceClassVisitor extends ClassVisitor { } @Override - public void visitInnerClass( - final String name, - final String outerName, - final String innerName, - final int access) - { + public void visitInnerClass(final String name, final String outerName, + final String innerName, final int access) { p.visitInnerClass(name, outerName, innerName, access); super.visitInnerClass(name, outerName, innerName, access); } @Override - public FieldVisitor visitField( - final int access, - final String name, - final String desc, - final String signature, - final Object value) - { - Printer p = this.p.visitField(access, - name, - desc, - signature, - value); - FieldVisitor fv = cv == null ? null : cv.visitField(access, - name, - desc, - signature, - value); + public FieldVisitor visitField(final int access, final String name, + final String desc, final String signature, final Object value) { + Printer p = this.p.visitField(access, name, desc, signature, value); + FieldVisitor fv = cv == null ? null : cv.visitField(access, name, desc, + signature, value); return new TraceFieldVisitor(fv, p); } @Override - public MethodVisitor visitMethod( - final int access, - final String name, - final String desc, - final String signature, - final String[] exceptions) - { - Printer p = this.p.visitMethod(access, - name, - desc, - signature, - exceptions); - MethodVisitor mv = cv == null ? null : cv.visitMethod(access, - name, - desc, - signature, + public MethodVisitor visitMethod(final int access, final String name, + final String desc, final String signature, final String[] exceptions) { + Printer p = this.p.visitMethod(access, name, desc, signature, exceptions); + MethodVisitor mv = cv == null ? null : cv.visitMethod(access, name, + desc, signature, exceptions); return new TraceMethodVisitor(mv, p); } diff --git a/src/asm/scala/tools/asm/util/TraceFieldVisitor.java b/src/asm/scala/tools/asm/util/TraceFieldVisitor.java index f537e83be1..9547a70008 100644 --- a/src/asm/scala/tools/asm/util/TraceFieldVisitor.java +++ b/src/asm/scala/tools/asm/util/TraceFieldVisitor.java @@ -37,7 +37,7 @@ import scala.tools.asm.Opcodes; /** * A {@link FieldVisitor} that prints the fields it visits with a * {@link Printer}. - * + * * @author Eric Bruneton */ public final class TraceFieldVisitor extends FieldVisitor { @@ -52,12 +52,10 @@ public final class TraceFieldVisitor extends FieldVisitor { super(Opcodes.ASM4, fv); this.p = p; } - + @Override - public AnnotationVisitor visitAnnotation( - final String desc, - final boolean visible) - { + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { Printer p = this.p.visitFieldAnnotation(desc, visible); AnnotationVisitor av = fv == null ? null : fv.visitAnnotation(desc, visible); diff --git a/src/asm/scala/tools/asm/util/TraceMethodVisitor.java b/src/asm/scala/tools/asm/util/TraceMethodVisitor.java index 9aabf2079e..9034567c8f 100644 --- a/src/asm/scala/tools/asm/util/TraceMethodVisitor.java +++ b/src/asm/scala/tools/asm/util/TraceMethodVisitor.java @@ -56,10 +56,8 @@ public final class TraceMethodVisitor extends MethodVisitor { } @Override - public AnnotationVisitor visitAnnotation( - final String desc, - final boolean visible) - { + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { Printer p = this.p.visitMethodAnnotation(desc, visible); AnnotationVisitor av = mv == null ? null : mv.visitAnnotation(desc, visible); @@ -80,17 +78,11 @@ public final class TraceMethodVisitor extends MethodVisitor { } @Override - public AnnotationVisitor visitParameterAnnotation( - final int parameter, - final String desc, - final boolean visible) - { - Printer p = this.p.visitParameterAnnotation(parameter, - desc, - visible); - AnnotationVisitor av = mv == null - ? null - : mv.visitParameterAnnotation(parameter, desc, visible); + public AnnotationVisitor visitParameterAnnotation(final int parameter, + final String desc, final boolean visible) { + Printer p = this.p.visitParameterAnnotation(parameter, desc, visible); + AnnotationVisitor av = mv == null ? null : mv.visitParameterAnnotation( + parameter, desc, visible); return new TraceAnnotationVisitor(av, p); } @@ -101,13 +93,8 @@ public final class TraceMethodVisitor extends MethodVisitor { } @Override - public void visitFrame( - final int type, - final int nLocal, - final Object[] local, - final int nStack, - final Object[] stack) - { + public void visitFrame(final int type, final int nLocal, + final Object[] local, final int nStack, final Object[] stack) { p.visitFrame(type, nLocal, local, nStack, stack); super.visitFrame(type, nLocal, local, nStack, stack); } @@ -137,34 +124,22 @@ public final class TraceMethodVisitor extends MethodVisitor { } @Override - public void visitFieldInsn( - final int opcode, - final String owner, - final String name, - final String desc) - { + public void visitFieldInsn(final int opcode, final String owner, + final String name, final String desc) { p.visitFieldInsn(opcode, owner, name, desc); super.visitFieldInsn(opcode, owner, name, desc); } @Override - public void visitMethodInsn( - final int opcode, - final String owner, - final String name, - final String desc) - { + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { p.visitMethodInsn(opcode, owner, name, desc); super.visitMethodInsn(opcode, owner, name, desc); } @Override - public void visitInvokeDynamicInsn( - String name, - String desc, - Handle bsm, - Object... bsmArgs) - { + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, + Object... bsmArgs) { p.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); } @@ -194,22 +169,15 @@ public final class TraceMethodVisitor extends MethodVisitor { } @Override - public void visitTableSwitchInsn( - final int min, - final int max, - final Label dflt, - final Label... labels) - { + public void visitTableSwitchInsn(final int min, final int max, + final Label dflt, final Label... labels) { p.visitTableSwitchInsn(min, max, dflt, labels); super.visitTableSwitchInsn(min, max, dflt, labels); } @Override - public void visitLookupSwitchInsn( - final Label dflt, - final int[] keys, - final Label[] labels) - { + public void visitLookupSwitchInsn(final Label dflt, final int[] keys, + final Label[] labels) { p.visitLookupSwitchInsn(dflt, keys, labels); super.visitLookupSwitchInsn(dflt, keys, labels); } @@ -221,25 +189,16 @@ public final class TraceMethodVisitor extends MethodVisitor { } @Override - public void visitTryCatchBlock( - final Label start, - final Label end, - final Label handler, - final String type) - { + public void visitTryCatchBlock(final Label start, final Label end, + final Label handler, final String type) { p.visitTryCatchBlock(start, end, handler, type); super.visitTryCatchBlock(start, end, handler, type); } @Override - public void visitLocalVariable( - final String name, - final String desc, - final String signature, - final Label start, - final Label end, - final int index) - { + public void visitLocalVariable(final String name, final String desc, + final String signature, final Label start, final Label end, + final int index) { p.visitLocalVariable(name, desc, signature, start, end, index); super.visitLocalVariable(name, desc, signature, start, end, index); } diff --git a/src/asm/scala/tools/asm/util/TraceSignatureVisitor.java b/src/asm/scala/tools/asm/util/TraceSignatureVisitor.java index a37b759811..1e23c7ef1a 100644 --- a/src/asm/scala/tools/asm/util/TraceSignatureVisitor.java +++ b/src/asm/scala/tools/asm/util/TraceSignatureVisitor.java @@ -117,8 +117,7 @@ public final class TraceSignatureVisitor extends SignatureVisitor { @Override public SignatureVisitor visitInterface() { - separator = seenInterface ? ", " : isInterface - ? " extends " + separator = seenInterface ? ", " : isInterface ? " extends " : " implements "; seenInterface = true; startType(); @@ -165,34 +164,34 @@ public final class TraceSignatureVisitor extends SignatureVisitor { @Override public void visitBaseType(final char descriptor) { switch (descriptor) { - case 'V': - declaration.append("void"); - break; - case 'B': - declaration.append("byte"); - break; - case 'J': - declaration.append("long"); - break; - case 'Z': - declaration.append("boolean"); - break; - case 'I': - declaration.append("int"); - break; - case 'S': - declaration.append("short"); - break; - case 'C': - declaration.append("char"); - break; - case 'F': - declaration.append("float"); - break; - // case 'D': - default: - declaration.append("double"); - break; + case 'V': + declaration.append("void"); + break; + case 'B': + declaration.append("byte"); + break; + case 'J': + declaration.append("long"); + break; + case 'Z': + declaration.append("boolean"); + break; + case 'I': + declaration.append("int"); + break; + case 'S': + declaration.append("short"); + break; + case 'C': + declaration.append("char"); + break; + case 'F': + declaration.append("float"); + break; + // case 'D': + default: + declaration.append("double"); + break; } endType(); } diff --git a/src/compiler/scala/reflect/macros/runtime/Enclosures.scala b/src/compiler/scala/reflect/macros/runtime/Enclosures.scala index be5f2dbe83..d9f337b5ba 100644 --- a/src/compiler/scala/reflect/macros/runtime/Enclosures.scala +++ b/src/compiler/scala/reflect/macros/runtime/Enclosures.scala @@ -5,7 +5,6 @@ trait Enclosures { self: Context => import universe._ - import mirror._ private def site = callsiteTyper.context private def enclTrees = site.enclosingContextChain map (_.tree) diff --git a/src/compiler/scala/reflect/macros/runtime/ExprUtils.scala b/src/compiler/scala/reflect/macros/runtime/ExprUtils.scala index 672699f00e..a719beed97 100644 --- a/src/compiler/scala/reflect/macros/runtime/ExprUtils.scala +++ b/src/compiler/scala/reflect/macros/runtime/ExprUtils.scala @@ -5,7 +5,6 @@ trait ExprUtils { self: Context => import universe._ - import mirror._ def literalNull = Expr[Null](Literal(Constant(null)))(TypeTag.Null) diff --git a/src/compiler/scala/reflect/reify/Errors.scala b/src/compiler/scala/reflect/reify/Errors.scala index 7c66d5b9eb..3a68794c97 100644 --- a/src/compiler/scala/reflect/reify/Errors.scala +++ b/src/compiler/scala/reflect/reify/Errors.scala @@ -7,7 +7,6 @@ trait Errors { self: Reifier => import global._ - import definitions._ def defaultErrorPosition = { val stack = currents collect { case t: Tree if t.pos != NoPosition => t.pos } @@ -22,11 +21,6 @@ trait Errors { throw new ReificationException(defaultErrorPosition, msg) } - def CannotReifySymbol(sym: Symbol) = { - val msg = "implementation restriction: cannot reify symbol %s (%s)".format(sym, sym.accurateKindString) - throw new ReificationException(defaultErrorPosition, msg) - } - def CannotReifyWeakType(details: Any) = { val msg = "cannot create a TypeTag" + details + ": use WeakTypeTag instead" throw new ReificationException(defaultErrorPosition, msg) diff --git a/src/compiler/scala/reflect/reify/Phases.scala b/src/compiler/scala/reflect/reify/Phases.scala index 1710cae2a5..d43532090c 100644 --- a/src/compiler/scala/reflect/reify/Phases.scala +++ b/src/compiler/scala/reflect/reify/Phases.scala @@ -10,7 +10,6 @@ trait Phases extends Reshape self: Reifier => import global._ - import definitions._ private var alreadyRun = false @@ -26,7 +25,7 @@ trait Phases extends Reshape if (reifyDebug) println("[reshape phase]") tree = reshape.transform(tree) if (reifyDebug) println("[interlude]") - if (reifyDebug) println("reifee = " + (if (opt.showTrees) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString)) + if (reifyDebug) println("reifee = " + (if (settings.Xshowtrees.value || settings.XshowtreesCompact.value || settings.XshowtreesStringified.value) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString)) if (reifyDebug) println("[calculate phase]") calculate.traverse(tree) @@ -41,4 +40,4 @@ trait Phases extends Reshape result } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/reflect/reify/Reifier.scala b/src/compiler/scala/reflect/reify/Reifier.scala index 47669f57b0..b3224b1aa6 100644 --- a/src/compiler/scala/reflect/reify/Reifier.scala +++ b/src/compiler/scala/reflect/reify/Reifier.scala @@ -57,7 +57,7 @@ abstract class Reifier extends States val result = reifee match { case tree: Tree => - reifyTrace("reifying = ")(if (opt.showTrees) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString) + reifyTrace("reifying = ")(if (settings.Xshowtrees.value || settings.XshowtreesCompact.value || settings.XshowtreesStringified.value) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString) reifyTrace("reifee is located at: ")(tree.pos) reifyTrace("universe = ")(universe) reifyTrace("mirror = ")(mirror) diff --git a/src/compiler/scala/reflect/reify/States.scala b/src/compiler/scala/reflect/reify/States.scala index 58455c9f3c..29bfa19845 100644 --- a/src/compiler/scala/reflect/reify/States.scala +++ b/src/compiler/scala/reflect/reify/States.scala @@ -4,7 +4,6 @@ trait States { self: Reifier => import global._ - import definitions._ /** Encapsulates reifier state * diff --git a/src/compiler/scala/reflect/reify/Taggers.scala b/src/compiler/scala/reflect/reify/Taggers.scala index cbaee41890..af0341fd38 100644 --- a/src/compiler/scala/reflect/reify/Taggers.scala +++ b/src/compiler/scala/reflect/reify/Taggers.scala @@ -8,7 +8,6 @@ abstract class Taggers { import c.universe._ import definitions._ - import treeBuild._ val coreTags = Map( ByteTpe -> nme.Byte, diff --git a/src/compiler/scala/reflect/reify/codegen/GenAnnotationInfos.scala b/src/compiler/scala/reflect/reify/codegen/GenAnnotationInfos.scala index dec491aabe..5a454e1e07 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenAnnotationInfos.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenAnnotationInfos.scala @@ -5,7 +5,6 @@ trait GenAnnotationInfos { self: Reifier => import global._ - import definitions._ // usually annotations are reified as their originals from Modifiers // however, when reifying free and tough types, we're forced to reify annotation infos as is @@ -52,4 +51,4 @@ trait GenAnnotationInfos { val reifiedAssocs = ann.assocs map (assoc => scalaFactoryCall(nme.Tuple2, reify(assoc._1), reifyClassfileAnnotArg(assoc._2))) mirrorFactoryCall(nme.Annotation, reify(ann.atp), mkList(reifiedArgs), mkListMap(reifiedAssocs)) } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/reflect/reify/codegen/GenNames.scala b/src/compiler/scala/reflect/reify/codegen/GenNames.scala index 4abf88f475..7c3c1d1149 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenNames.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenNames.scala @@ -5,10 +5,9 @@ trait GenNames { self: Reifier => import global._ - import definitions._ def reifyName(name: Name) = { val factory = if (name.isTypeName) nme.nmeNewTypeName else nme.nmeNewTermName mirrorCall(factory, Literal(Constant(name.toString))) } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/reflect/reify/codegen/GenPositions.scala b/src/compiler/scala/reflect/reify/codegen/GenPositions.scala index 8c5db04454..1d151c5135 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenPositions.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenPositions.scala @@ -5,7 +5,6 @@ trait GenPositions { self: Reifier => import global._ - import definitions._ // we do not reify positions because this inflates resulting trees, but doesn't buy as anything // where would one use positions? right, in error messages @@ -14,4 +13,4 @@ trait GenPositions { // however both macros and toolboxes have their own means to report errors in synthetic trees def reifyPosition(pos: Position): Tree = reifyMirrorObject(NoPosition) -}
\ No newline at end of file +} diff --git a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala index 22a834d2e4..39103b801e 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala @@ -5,7 +5,6 @@ trait GenSymbols { self: Reifier => import global._ - import definitions._ /** Symbol table of the reifee. * diff --git a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala index bdcc7383b0..86ad23cd15 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala @@ -64,7 +64,7 @@ trait GenTrees { // usually we don't reify symbols/types, because they can be re-inferred during subsequent reflective compilation // however, reification of AnnotatedTypes is special. see ``reifyType'' to find out why. - if (reifyTreeSymbols && tree.hasSymbol) { + if (reifyTreeSymbols && tree.hasSymbolField) { if (reifyDebug) println("reifying symbol %s for tree %s".format(tree.symbol, tree)) rtree = mirrorBuildCall(nme.setSymbol, rtree, reify(tree.symbol)) } @@ -86,8 +86,8 @@ trait GenTrees { // see ``Metalevels'' for more info about metalevel breaches // and about how we deal with splices that contain them - val isMetalevelBreach = splicee exists (sub => sub.hasSymbol && sub.symbol != NoSymbol && sub.symbol.metalevel > 0) - val isRuntimeEval = splicee exists (sub => sub.hasSymbol && sub.symbol == ExprSplice) + val isMetalevelBreach = splicee exists (sub => sub.hasSymbolField && sub.symbol != NoSymbol && sub.symbol.metalevel > 0) + val isRuntimeEval = splicee exists (sub => sub.hasSymbolField && sub.symbol == ExprSplice) if (isMetalevelBreach || isRuntimeEval) { // we used to convert dynamic splices into runtime evals transparently, but we no longer do that // why? see comments in ``Metalevels'' diff --git a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala index 7aa87dc2f8..ca44938f50 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala @@ -74,7 +74,6 @@ trait GenTypes { if (reifyDebug) println("splicing " + tpe) val tagFlavor = if (concrete) tpnme.TypeTag.toString else tpnme.WeakTypeTag.toString - val key = (tagFlavor, tpe.typeSymbol) // if this fails, it might produce the dreaded "erroneous or inaccessible type" error // to find out the whereabouts of the error run scalac with -Ydebug if (reifyDebug) println("launching implicit search for %s.%s[%s]".format(universe, tagFlavor, tpe)) diff --git a/src/compiler/scala/reflect/reify/codegen/GenUtils.scala b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala index 49877b4286..e2275f79ff 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenUtils.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala @@ -5,7 +5,6 @@ trait GenUtils { self: Reifier => import global._ - import definitions._ def reifyList(xs: List[Any]): Tree = mkList(xs map reify) @@ -91,22 +90,6 @@ trait GenUtils { /** An (unreified) path that refers to term definition with given fully qualified name */ def termPath(fullname: String): Tree = path(fullname, newTermName) - /** An (unreified) path that refers to type definition with given fully qualified name */ - def typePath(fullname: String): Tree = path(fullname, newTypeName) - - def isTough(tpe: Type) = { - def isTough(tpe: Type) = tpe match { - case _: RefinedType => true - case _: ExistentialType => true - case _: ClassInfoType => true - case _: MethodType => true - case _: PolyType => true - case _ => false - } - - tpe != null && (tpe exists isTough) - } - object TypedOrAnnotated { def unapply(tree: Tree): Option[Tree] = tree match { case ty @ Typed(_, _) => @@ -118,15 +101,6 @@ trait GenUtils { } } - def isAnnotated(tpe: Type) = { - def isAnnotated(tpe: Type) = tpe match { - case _: AnnotatedType => true - case _ => false - } - - tpe != null && (tpe exists isAnnotated) - } - def isSemiConcreteTypeMember(tpe: Type) = tpe match { case TypeRef(SingleType(_, _), sym, _) if sym.isAbstractType && !sym.isExistential => true case _ => false @@ -145,4 +119,4 @@ trait GenUtils { if (origin == "") origin = "of unknown origin" origin } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/reflect/reify/package.scala b/src/compiler/scala/reflect/reify/package.scala index 55f8684df2..7be57c0cb7 100644 --- a/src/compiler/scala/reflect/reify/package.scala +++ b/src/compiler/scala/reflect/reify/package.scala @@ -1,11 +1,10 @@ package scala.reflect -import scala.language.implicitConversions -import scala.reflect.macros.{Context, ReificationException, UnexpectedReificationException} +import scala.reflect.macros.ReificationException import scala.tools.nsc.Global package object reify { - private def mkReifier(global1: Global)(typer: global1.analyzer.Typer, universe: global1.Tree, mirror: global1.Tree, reifee: Any, concrete: Boolean = false): Reifier { val global: global1.type } = { + private def mkReifier(global1: Global)(typer: global1.analyzer.Typer, universe: global1.Tree, mirror: global1.Tree, reifee: Any, concrete: Boolean): Reifier { val global: global1.type } = { val typer1: typer.type = typer val universe1: universe.type = universe val mirror1: mirror.type = mirror @@ -24,7 +23,8 @@ package object reify { private[reify] def mkDefaultMirrorRef(global: Global)(universe: global.Tree, typer0: global.analyzer.Typer): global.Tree = { import global._ - import definitions._ + import definitions.JavaUniverseClass + val enclosingErasure = { val rClassTree = reifyEnclosingRuntimeClass(global)(typer0) // HACK around SI-6259 @@ -71,7 +71,6 @@ package object reify { // a class/object body, this will return an EmptyTree. def reifyEnclosingRuntimeClass(global: Global)(typer0: global.analyzer.Typer): global.Tree = { import global._ - import definitions._ def isThisInScope = typer0.context.enclosingContextChain exists (_.tree.isInstanceOf[ImplDef]) if (isThisInScope) { val enclosingClasses = typer0.context.enclosingContextChain map (_.tree) collect { case classDef: ClassDef => classDef } diff --git a/src/compiler/scala/reflect/reify/phases/Calculate.scala b/src/compiler/scala/reflect/reify/phases/Calculate.scala index 4d1e22abe7..5566fd7a77 100644 --- a/src/compiler/scala/reflect/reify/phases/Calculate.scala +++ b/src/compiler/scala/reflect/reify/phases/Calculate.scala @@ -5,7 +5,6 @@ trait Calculate { self: Reifier => import global._ - import definitions._ implicit class RichCalculateSymbol(sym: Symbol) { def metalevel: Int = { assert(sym != null && sym != NoSymbol); localSymbols.getOrElse(sym, 0) } diff --git a/src/compiler/scala/reflect/reify/phases/Metalevels.scala b/src/compiler/scala/reflect/reify/phases/Metalevels.scala index fbbd12a42f..cccf080dbf 100644 --- a/src/compiler/scala/reflect/reify/phases/Metalevels.scala +++ b/src/compiler/scala/reflect/reify/phases/Metalevels.scala @@ -1,11 +1,12 @@ package scala.reflect.reify package phases +import scala.collection.{ mutable } + trait Metalevels { self: Reifier => import global._ - import definitions._ /** * Makes sense of cross-stage bindings. @@ -102,7 +103,7 @@ trait Metalevels { */ val metalevels = new Transformer { var insideSplice = false - var inlineableBindings = scala.collection.mutable.Map[TermName, Tree]() + val inlineableBindings = mutable.Map[TermName, Tree]() def withinSplice[T](op: => T) = { val old = insideSplice @@ -124,7 +125,7 @@ trait Metalevels { withinSplice { super.transform(TreeSplice(ReifiedTree(universe, mirror, symtab1, rtree, tpe, rtpe, concrete))) } case TreeSplice(splicee) => if (reifyDebug) println("entering splice: " + splicee) - val breaches = splicee filter (sub => sub.hasSymbol && sub.symbol != NoSymbol && sub.symbol.metalevel > 0) + val breaches = splicee filter (sub => sub.hasSymbolField && sub.symbol != NoSymbol && sub.symbol.metalevel > 0) if (!insideSplice && breaches.nonEmpty) { // we used to convert dynamic splices into runtime evals transparently, but we no longer do that // why? see comments above diff --git a/src/compiler/scala/reflect/reify/phases/Reify.scala b/src/compiler/scala/reflect/reify/phases/Reify.scala index dc0028be38..2741785752 100644 --- a/src/compiler/scala/reflect/reify/phases/Reify.scala +++ b/src/compiler/scala/reflect/reify/phases/Reify.scala @@ -2,7 +2,6 @@ package scala.reflect.reify package phases import scala.runtime.ScalaRunTime.isAnyVal -import scala.runtime.ScalaRunTime.isTuple import scala.reflect.reify.codegen._ trait Reify extends GenSymbols @@ -16,7 +15,6 @@ trait Reify extends GenSymbols self: Reifier => import global._ - import definitions._ private object reifyStack { def currents: List[Any] = state.reifyStack @@ -56,4 +54,4 @@ trait Reify extends GenSymbols case _ => throw new Error("reifee %s of type %s is not supported".format(reifee, reifee.getClass)) }) -}
\ No newline at end of file +} diff --git a/src/compiler/scala/reflect/reify/phases/Reshape.scala b/src/compiler/scala/reflect/reify/phases/Reshape.scala index 1b7509fdbe..f31c3d4755 100644 --- a/src/compiler/scala/reflect/reify/phases/Reshape.scala +++ b/src/compiler/scala/reflect/reify/phases/Reshape.scala @@ -48,13 +48,13 @@ trait Reshape { val Template(parents, self, body) = impl var body1 = trimAccessors(classDef, reshapeLazyVals(body)) body1 = trimSyntheticCaseClassMembers(classDef, body1) - var impl1 = Template(parents, self, body1).copyAttrs(impl) + val impl1 = Template(parents, self, body1).copyAttrs(impl) ClassDef(mods, name, params, impl1).copyAttrs(classDef) case moduledef @ ModuleDef(mods, name, impl) => val Template(parents, self, body) = impl var body1 = trimAccessors(moduledef, reshapeLazyVals(body)) body1 = trimSyntheticCaseClassMembers(moduledef, body1) - var impl1 = Template(parents, self, body1).copyAttrs(impl) + val impl1 = Template(parents, self, body1).copyAttrs(impl) ModuleDef(mods, name, impl1).copyAttrs(moduledef) case template @ Template(parents, self, body) => val discardedParents = parents collect { case tt: TypeTree => tt } filter isDiscarded @@ -116,7 +116,6 @@ trait Reshape { private def toPreTyperModifiers(mods: Modifiers, sym: Symbol) = { if (!sym.annotations.isEmpty) { - val Modifiers(flags, privateWithin, annotations) = mods val postTyper = sym.annotations filter (_.original != EmptyTree) if (reifyDebug && !postTyper.isEmpty) println("reify symbol annotations for: " + sym) if (reifyDebug && !postTyper.isEmpty) println("originals are: " + sym.annotations) @@ -252,7 +251,7 @@ trait Reshape { val DefDef(mods0, name0, _, _, tpt0, rhs0) = ddef val name1 = nme.dropLocalSuffix(name0) val Modifiers(flags0, privateWithin0, annotations0) = mods0 - var flags1 = (flags0 & GetterFlags) & ~(STABLE | ACCESSOR | METHOD) + val flags1 = (flags0 & GetterFlags) & ~(STABLE | ACCESSOR | METHOD) val mods1 = Modifiers(flags1, privateWithin0, annotations0) setPositions mods0.positions val mods2 = toPreTyperModifiers(mods1, ddef.symbol) ValDef(mods2, name1, tpt0, extractRhs(rhs0)) @@ -267,7 +266,7 @@ trait Reshape { def detectBeanAccessors(prefix: String): Unit = { if (defdef.name.startsWith(prefix)) { - var name = defdef.name.toString.substring(prefix.length) + val name = defdef.name.toString.substring(prefix.length) def uncapitalize(s: String) = if (s.length == 0) "" else { val chars = s.toCharArray; chars(0) = chars(0).toLower; new String(chars) } def findValDef(name: String) = (symdefs.values collect { case vdef: ValDef if nme.dropLocalSuffix(vdef.name).toString == name => vdef }).headOption val valdef = findValDef(name).orElse(findValDef(uncapitalize(name))).orNull @@ -279,11 +278,11 @@ trait Reshape { detectBeanAccessors("is") }); - var stats1 = stats flatMap { + val stats1 = stats flatMap { case vdef @ ValDef(mods, name, tpt, rhs) if !mods.isLazy => val mods1 = if (accessors.contains(vdef)) { val ddef = accessors(vdef)(0) // any accessor will do - val Modifiers(flags, privateWithin, annotations) = mods + val Modifiers(flags, _, annotations) = mods var flags1 = flags & ~LOCAL if (!ddef.symbol.isPrivate) flags1 = flags1 & ~PRIVATE val privateWithin1 = ddef.mods.privateWithin @@ -326,7 +325,8 @@ trait Reshape { case Some(ddef) => toPreTyperLazyVal(ddef) case None => - CannotReifyInvalidLazyVal(vdef) + if (reifyDebug) println("couldn't find corresponding lazy val accessor") + vdef } if (reifyDebug) println(s"reconstructed lazy val is $vdef1") vdef1::Nil diff --git a/src/compiler/scala/reflect/reify/utils/Extractors.scala b/src/compiler/scala/reflect/reify/utils/Extractors.scala index b60d15c1d4..50bd309b52 100644 --- a/src/compiler/scala/reflect/reify/utils/Extractors.scala +++ b/src/compiler/scala/reflect/reify/utils/Extractors.scala @@ -187,7 +187,7 @@ trait Extractors { Literal(Constant(origin: String))))) if uref1.name == nme.UNIVERSE_SHORT && build1 == nme.build && newFreeTerm == nme.newFreeTerm && uref2.name == nme.UNIVERSE_SHORT && build2 == nme.build && flagsFromBits == nme.flagsFromBits => - Some(uref1, name, reifyBinding(tree), flags, origin) + Some((uref1, name, reifyBinding(tree), flags, origin)) case _ => None } @@ -204,7 +204,7 @@ trait Extractors { Literal(Constant(origin: String))))) if uref1.name == nme.UNIVERSE_SHORT && build1 == nme.build && newFreeType == nme.newFreeType && uref2.name == nme.UNIVERSE_SHORT && build2 == nme.build && flagsFromBits == nme.flagsFromBits => - Some(uref1, name, reifyBinding(tree), flags, origin) + Some((uref1, name, reifyBinding(tree), flags, origin)) case _ => None } diff --git a/src/compiler/scala/reflect/reify/utils/NodePrinters.scala b/src/compiler/scala/reflect/reify/utils/NodePrinters.scala index aca18c7df7..97ec479a6c 100644 --- a/src/compiler/scala/reflect/reify/utils/NodePrinters.scala +++ b/src/compiler/scala/reflect/reify/utils/NodePrinters.scala @@ -11,8 +11,6 @@ trait NodePrinters { self: Utils => import global._ - import definitions._ - import Flag._ object reifiedNodeToString extends (Tree => String) { def apply(tree: Tree): String = { @@ -25,8 +23,8 @@ trait NodePrinters { // Rolling a full-fledged, robust TreePrinter would be several times more code. // Also as of late we have tests that ensure that UX won't be broken by random changes to the reifier. val lines = (tree.toString.split(EOL) drop 1 dropRight 1).toList splitAt 2 - var (List(universe, mirror), reification) = lines - reification = (for (line <- reification) yield { + val (List(universe, mirror), reification0) = lines + val reification = (for (line <- reification0) yield { var s = line substring 2 s = s.replace(nme.UNIVERSE_PREFIX.toString, "") s = s.replace(".apply", "") diff --git a/src/compiler/scala/reflect/reify/utils/SymbolTables.scala b/src/compiler/scala/reflect/reify/utils/SymbolTables.scala index dbb0836e0a..5f8de9894f 100644 --- a/src/compiler/scala/reflect/reify/utils/SymbolTables.scala +++ b/src/compiler/scala/reflect/reify/utils/SymbolTables.scala @@ -8,8 +8,6 @@ trait SymbolTables { self: Utils => import global._ - import definitions._ - import Flag._ class SymbolTable private[SymbolTable] ( private[SymbolTable] val symtab: immutable.ListMap[Symbol, Tree] = immutable.ListMap[Symbol, Tree](), @@ -17,9 +15,6 @@ trait SymbolTables { private[SymbolTable] val original: Option[List[Tree]] = None) { def syms: List[Symbol] = symtab.keys.toList - def isConcrete: Boolean = symtab.values forall (sym => !FreeTypeDef.unapply(sym).isDefined) - -// def aliases: Map[Symbol, List[TermName]] = aliases.distinct groupBy (_._1) mapValues (_ map (_._2)) def symDef(sym: Symbol): Tree = symtab.getOrElse(sym, EmptyTree) @@ -89,11 +84,6 @@ trait SymbolTables { add(ValDef(NoMods, freshName(name0), TypeTree(), reification) updateAttachment bindingAttachment) } - private def add(sym: Symbol, name: TermName): SymbolTable = { - if (!(syms contains sym)) error("cannot add an alias to a symbol not in the symbol table") - add(sym, name, EmptyTree) - } - private def remove(sym: Symbol): SymbolTable = { val newSymtab = symtab - sym val newAliases = aliases filter (_._1 != sym) @@ -107,7 +97,7 @@ trait SymbolTables { newSymtab = newSymtab map { case ((sym, tree)) => val ValDef(mods, primaryName, tpt, rhs) = tree val tree1 = - if (!(newAliases contains (sym, primaryName))) { + if (!(newAliases contains ((sym, primaryName)))) { val primaryName1 = newAliases.find(_._1 == sym).get._2 ValDef(mods, primaryName1, tpt, rhs).copyAttrs(tree) } else tree @@ -143,7 +133,7 @@ trait SymbolTables { var result = new SymbolTable(original = Some(encoded)) encoded foreach (entry => (entry.attachments.get[ReifyBindingAttachment], entry.attachments.get[ReifyAliasAttachment]) match { case (Some(ReifyBindingAttachment(_)), _) => result += entry - case (_, Some(ReifyAliasAttachment(sym, alias))) => result = new SymbolTable(result.symtab, result.aliases :+ (sym, alias)) + case (_, Some(ReifyAliasAttachment(sym, alias))) => result = new SymbolTable(result.symtab, result.aliases :+ ((sym, alias))) case _ => // do nothing, this is boilerplate that can easily be recreated by subsequent `result.encode` }) result @@ -214,4 +204,4 @@ trait SymbolTables { } } } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/ant/Pack200Task.scala b/src/compiler/scala/tools/ant/Pack200Task.scala index 255efe55ec..3180911414 100644 --- a/src/compiler/scala/tools/ant/Pack200Task.scala +++ b/src/compiler/scala/tools/ant/Pack200Task.scala @@ -99,8 +99,8 @@ class Pack200Task extends ScalaMatchingTask { private def getFileList: List[File] = { var files: List[File] = Nil val fs = getImplicitFileSet - var ds = fs.getDirectoryScanner(getProject()) - var dir = fs.getDir(getProject()) + val ds = fs.getDirectoryScanner(getProject()) + val dir = fs.getDir(getProject()) for (filename <- ds.getIncludedFiles() if filename.toLowerCase.endsWith(".jar")) { val file = new File(dir, filename) diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala index 73d09e82ba..cf3b5f949b 100644 --- a/src/compiler/scala/tools/ant/Scalac.scala +++ b/src/compiler/scala/tools/ant/Scalac.scala @@ -19,6 +19,7 @@ import org.apache.tools.ant.util.facade.{FacadeTaskHelper, ImplementationSpecificArgument} import scala.tools.nsc.{Global, Settings, CompilerCommand} +import scala.tools.nsc.interactive.RangePositions import scala.tools.nsc.io.{Path => SPath} import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} @@ -518,7 +519,10 @@ class Scalac extends ScalaMatchingTask with ScalacShared { new Settings(error) protected def newGlobal(settings: Settings, reporter: Reporter) = - new Global(settings, reporter) + if (settings.Yrangepos.value) + new Global(settings, reporter) with RangePositions + else + new Global(settings, reporter) /*============================================================================*\ ** The big execute method ** diff --git a/src/compiler/scala/tools/ant/sabbus/Settings.scala b/src/compiler/scala/tools/ant/sabbus/Settings.scala index fde61e9564..d0fefdaa03 100644 --- a/src/compiler/scala/tools/ant/sabbus/Settings.scala +++ b/src/compiler/scala/tools/ant/sabbus/Settings.scala @@ -10,7 +10,7 @@ package scala.tools.ant.sabbus import java.io.File -import org.apache.tools.ant.types.{Path, Reference} +import org.apache.tools.ant.types.Path class Settings { diff --git a/src/compiler/scala/tools/cmd/CommandLine.scala b/src/compiler/scala/tools/cmd/CommandLine.scala index 75f96d3c4b..cf0463423c 100644 --- a/src/compiler/scala/tools/cmd/CommandLine.scala +++ b/src/compiler/scala/tools/cmd/CommandLine.scala @@ -19,7 +19,7 @@ class CommandLine(val spec: Reference, val originalArgs: List[String]) extends C def this(spec: Reference, line: String) = this(spec, Parser tokenize line) def this(spec: Reference, args: Array[String]) = this(spec, args.toList) - import spec.{ isAnyOption, isUnaryOption, isBinaryOption, isExpandOption } + import spec.{ isUnaryOption, isBinaryOption, isExpandOption } val Terminator = "--" val ValueForUnaryOption = "true" // so if --opt is given, x(--opt) = true diff --git a/src/compiler/scala/tools/cmd/FromString.scala b/src/compiler/scala/tools/cmd/FromString.scala index cba2e99998..433bbb167e 100644 --- a/src/compiler/scala/tools/cmd/FromString.scala +++ b/src/compiler/scala/tools/cmd/FromString.scala @@ -6,7 +6,7 @@ package scala.tools package cmd -import nsc.io.{ Path, File, Directory } +import scala.tools.nsc.io.{ File, Directory } import scala.reflect.runtime.{universe => ru} import scala.tools.reflect.StdRuntimeTags._ @@ -24,18 +24,11 @@ abstract class FromString[+T](implicit t: ru.TypeTag[T]) extends PartialFunction } object FromString { - // We need these because we clash with the String => Path implicits. - private def toFile(s: String) = new File(new java.io.File(s)) + // We need this because we clash with the String => Path implicits. private def toDir(s: String) = new Directory(new java.io.File(s)) /** Path related stringifiers. */ - val ExistingFile: FromString[File] = new FromString[File]()(tagOfFile) { - override def isDefinedAt(s: String) = toFile(s).isFile - def apply(s: String): File = - if (isDefinedAt(s)) toFile(s) - else cmd.runAndExit(println("'%s' is not an existing file." format s)) - } val ExistingDir: FromString[Directory] = new FromString[Directory]()(tagOfDirectory) { override def isDefinedAt(s: String) = toDir(s).isDirectory def apply(s: String): Directory = diff --git a/src/compiler/scala/tools/cmd/Reference.scala b/src/compiler/scala/tools/cmd/Reference.scala index bcbb454771..ec2a414065 100644 --- a/src/compiler/scala/tools/cmd/Reference.scala +++ b/src/compiler/scala/tools/cmd/Reference.scala @@ -26,7 +26,6 @@ trait Reference extends Spec { def isUnaryOption(s: String) = unary contains toOpt(s) def isBinaryOption(s: String) = binary contains toOpt(s) def isExpandOption(s: String) = expansionMap contains toOpt(s) - def isAnyOption(s: String) = isUnaryOption(s) || isBinaryOption(s) || isExpandOption(s) def expandArg(arg: String) = expansionMap.getOrElse(fromOpt(arg), List(arg)) @@ -46,7 +45,7 @@ object Reference { val MaxLine = 80 class Accumulators() { - private var _help = new ListBuffer[() => String] + private val _help = new ListBuffer[() => String] private var _unary = List[String]() private var _binary = List[String]() private var _expand = Map[String, List[String]]() diff --git a/src/compiler/scala/tools/cmd/gen/CodegenSpec.scala b/src/compiler/scala/tools/cmd/gen/CodegenSpec.scala index 903517c5b4..ee7e605425 100644 --- a/src/compiler/scala/tools/cmd/gen/CodegenSpec.scala +++ b/src/compiler/scala/tools/cmd/gen/CodegenSpec.scala @@ -12,8 +12,6 @@ trait CodegenSpec extends Spec with Meta.StdOpts with Interpolation { def referenceSpec = CodegenSpec def programInfo = Spec.Info("codegen", "", "scala.tools.cmd.gen.Codegen") - import FromString.ExistingDir - help("Usage: codegen [<options>]") // val inDir = "in" / "directory containing templates" --^ ExistingDir diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index 4e7ba60d5e..663fbeceb0 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -6,7 +6,7 @@ package scala.tools.nsc import util.FreshNameCreator -import scala.reflect.internal.util.{ Position, NoPosition, BatchSourceFile, SourceFile, NoSourceFile } +import scala.reflect.internal.util.{ SourceFile, NoSourceFile } import scala.collection.mutable import scala.collection.mutable.{ LinkedHashSet, ListBuffer } @@ -26,7 +26,7 @@ trait CompilationUnits { self: Global => class CompilationUnit(val source: SourceFile) extends CompilationUnitContextApi { /** the fresh name creator */ - var fresh: FreshNameCreator = new FreshNameCreator.Default + val fresh: FreshNameCreator = new FreshNameCreator.Default def freshTermName(prefix: String): TermName = newTermName(fresh.newName(prefix)) def freshTypeName(prefix: String): TypeName = newTypeName(fresh.newName(prefix)) @@ -36,16 +36,6 @@ trait CompilationUnits { self: Global => def exists = source != NoSourceFile && source != null -// def parseSettings() = { -// val argsmarker = "SCALAC_ARGS" -// if(comments nonEmpty) { -// val pragmas = comments find (_.text.startsWith("//#")) // only parse first one -// pragmas foreach { p => -// val i = p.text.indexOf(argsmarker) -// if(i > 0) -// } -// } -// } /** Note: depends now contains toplevel classes. * To get their sourcefiles, you need to dereference with .sourcefile */ @@ -107,18 +97,5 @@ trait CompilationUnits { self: Global => lazy val isJava = source.file.name.endsWith(".java") override def toString() = source.toString() - - def clear() { - fresh = new FreshNameCreator.Default - body = EmptyTree - depends.clear() - defined.clear() - synthetics.clear() - toCheck.clear() - checkedFeatures = Set() - icode.clear() - } } } - - diff --git a/src/compiler/scala/tools/nsc/CompileClient.scala b/src/compiler/scala/tools/nsc/CompileClient.scala index 731f6926f0..c756a1b0d9 100644 --- a/src/compiler/scala/tools/nsc/CompileClient.scala +++ b/src/compiler/scala/tools/nsc/CompileClient.scala @@ -5,7 +5,6 @@ package scala.tools.nsc -import java.io.{ BufferedReader, File, InputStreamReader, PrintWriter } import settings.FscSettings import scala.tools.util.CompileOutputCommon import sys.SystemProperties.preferIPv4Stack diff --git a/src/compiler/scala/tools/nsc/CompileServer.scala b/src/compiler/scala/tools/nsc/CompileServer.scala index c23c1e6154..f79990d526 100644 --- a/src/compiler/scala/tools/nsc/CompileServer.scala +++ b/src/compiler/scala/tools/nsc/CompileServer.scala @@ -5,7 +5,7 @@ package scala.tools.nsc -import java.io.{ BufferedOutputStream, FileOutputStream, PrintStream } +import java.io.PrintStream import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} import scala.reflect.internal.util.FakePos //Position import scala.tools.util.SocketServer @@ -29,8 +29,6 @@ class StandardCompileServer extends SocketServer { var shutdown = false var verbose = false - val versionMsg = "Fast " + Properties.versionMsg - val MaxCharge = 0.8 private val runtime = Runtime.getRuntime() diff --git a/src/compiler/scala/tools/nsc/CompileSocket.scala b/src/compiler/scala/tools/nsc/CompileSocket.scala index 9a3e8d1530..6b55537195 100644 --- a/src/compiler/scala/tools/nsc/CompileSocket.scala +++ b/src/compiler/scala/tools/nsc/CompileSocket.scala @@ -5,13 +5,9 @@ package scala.tools.nsc -import java.io.{ IOException, FileNotFoundException, PrintWriter, FileOutputStream } -import java.io.{ BufferedReader, FileReader } -import java.util.regex.Pattern -import java.net._ +import java.io.{ FileNotFoundException, PrintWriter, FileOutputStream } import java.security.SecureRandom import io.{ File, Path, Directory, Socket } -import scala.util.control.Exception.catching import scala.tools.util.CompileOutputCommon import scala.reflect.internal.util.StringOps.splitWhere import scala.sys.process._ diff --git a/src/compiler/scala/tools/nsc/CompilerCommand.scala b/src/compiler/scala/tools/nsc/CompilerCommand.scala index e994150f6f..0462e69f74 100644 --- a/src/compiler/scala/tools/nsc/CompilerCommand.scala +++ b/src/compiler/scala/tools/nsc/CompilerCommand.scala @@ -5,7 +5,6 @@ package scala.tools.nsc -import scala.collection.mutable.ListBuffer import io.File /** A class representing command line info for scalac */ @@ -15,9 +14,6 @@ class CompilerCommand(arguments: List[String], val settings: Settings) { type Setting = Settings#Setting - /** file extensions of files that the compiler can process */ - lazy val fileEndings = Properties.fileEndings - private val processArgumentsResult = if (shouldProcessArguments) processArguments else (true, Nil) @@ -41,8 +37,6 @@ class CompilerCommand(arguments: List[String], val settings: Settings) { """.stripMargin.trim + "\n" def shortUsage = "Usage: %s <options> <source files>" format cmdName - def createUsagePreface(shouldExplain: Boolean) = - if (shouldExplain) shortUsage + "\n" + explainAdvanced else "" /** Creates a help message for a subset of options based on cond */ def createUsageMsg(cond: Setting => Boolean): String = { diff --git a/src/compiler/scala/tools/nsc/CompilerRun.scala b/src/compiler/scala/tools/nsc/CompilerRun.scala deleted file mode 100644 index 6746b08155..0000000000 --- a/src/compiler/scala/tools/nsc/CompilerRun.scala +++ /dev/null @@ -1,21 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Martin Odersky - */ - -package scala.tools.nsc - -class CompilerRun { - def firstPhase: Phase = NoPhase - def terminalPhase: Phase = NoPhase - def namerPhase: Phase = NoPhase - def typerPhase: Phase = NoPhase - def refchecksPhase: Phase = NoPhase - def explicitouterPhase: Phase = NoPhase - def erasurePhase: Phase = NoPhase - def flattenPhase: Phase = NoPhase - def mixinPhase: Phase = NoPhase - def icodePhase: Phase = NoPhase - def phaseNamed(name: String): Phase = NoPhase -} - diff --git a/src/compiler/scala/tools/nsc/Driver.scala b/src/compiler/scala/tools/nsc/Driver.scala index 1775602122..b5fd20e1cc 100644 --- a/src/compiler/scala/tools/nsc/Driver.scala +++ b/src/compiler/scala/tools/nsc/Driver.scala @@ -1,11 +1,11 @@ package scala.tools.nsc -import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} +import scala.tools.nsc.reporters.ConsoleReporter import Properties.{ versionString, copyrightString, residentPromptString } -import scala.reflect.internal.util.{ BatchSourceFile, FakePos } +import scala.reflect.internal.util.FakePos abstract class Driver { - + val prompt = residentPromptString val versionMsg = "Scala compiler " + @@ -68,4 +68,4 @@ abstract class Driver { sys.exit(if (reporter.hasErrors) 1 else 0) } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala index 9c2db11a56..ad75d02bff 100644 --- a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala +++ b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala @@ -39,7 +39,4 @@ class GenericRunnerSettings(error: String => Unit) extends Settings(error) { val nc = BooleanSetting( "-nc", "do not use the fsc compilation daemon") withAbbreviation "-nocompdaemon" - - @deprecated("Use `nc` instead", "2.9.0") def nocompdaemon = nc - @deprecated("Use `save` instead", "2.9.0") def savecompiled = save } diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index b0288c0149..397e6c42d7 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -8,14 +8,12 @@ package scala.tools.nsc import java.io.{ File, FileOutputStream, PrintWriter, IOException, FileNotFoundException } import java.nio.charset.{ Charset, CharsetDecoder, IllegalCharsetNameException, UnsupportedCharsetException } import scala.compat.Platform.currentTime -import scala.tools.util.PathResolver import scala.collection.{ mutable, immutable } import io.{ SourceReader, AbstractFile, Path } import reporters.{ Reporter, ConsoleReporter } -import util.{ Exceptional, ClassPath, MergedClassPath, StatisticsInfo, ScalaClassLoader, returning } -import scala.reflect.internal.util.{ NoPosition, OffsetPosition, SourceFile, NoSourceFile, BatchSourceFile, ScriptSourceFile } +import util.{ ClassPath, MergedClassPath, StatisticsInfo, returning, stackTraceString, stackTraceHeadString } +import scala.reflect.internal.util.{ OffsetPosition, SourceFile, NoSourceFile, BatchSourceFile, ScriptSourceFile } import scala.reflect.internal.pickling.{ PickleBuffer, PickleFormat } -import settings.{ AestheticSettings } import symtab.{ Flags, SymbolTable, SymbolLoaders, SymbolTrackers } import symtab.classfile.Pickler import dependencies.DependencyAnalysis @@ -30,8 +28,6 @@ import backend.jvm.{GenJVM, GenASM} import backend.opt.{ Inliners, InlineExceptionHandlers, ClosureElimination, DeadCodeElimination } import backend.icode.analysis._ import scala.language.postfixOps -import scala.reflect.internal.StdAttachments -import scala.reflect.ClassTag class Global(var currentSettings: Settings, var reporter: Reporter) extends SymbolTable @@ -74,8 +70,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def this(settings: Settings) = this(settings, new ConsoleReporter(settings)) - def mkAttributedQualifier(tpe: Type, termSym: Symbol): Tree = gen.mkAttributedQualifier(tpe, termSym) - def picklerPhase: Phase = if (currentRun.isDefined) currentRun.picklerPhase else NoPhase // platform specific elements @@ -172,7 +166,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) if (lastPrintedSource == source) println(": tree is unchanged since " + lastPrintedPhase) else { - lastPrintedPhase = phase.prev // since we're running inside "afterPhase" + lastPrintedPhase = phase.prev // since we're running inside "exitingPhase" lastPrintedSource = source println("") println(source) @@ -257,27 +251,26 @@ class Global(var currentSettings: Settings, var reporter: Reporter) if (settings.debug.value) body } - // Warnings issued only under -Ydebug. For messages which should reach - // developer ears, but are not adequately actionable by users. - @inline final override def debugwarn(msg: => String) { - if (settings.debug.value) - warning(msg) + /** This is for WARNINGS which should reach the ears of scala developers + * whenever they occur, but are not useful for normal users. They should + * be precise, explanatory, and infrequent. Please don't use this as a + * logging mechanism. !!! is prefixed to all messages issued via this route + * to make them visually distinct. + */ + @inline final override def devWarning(msg: => String) { + if (settings.developer.value || settings.debug.value) + warning("!!! " + msg) } private def elapsedMessage(msg: String, start: Long) = msg + " in " + (currentTime - start) + "ms" def informComplete(msg: String): Unit = reporter.withoutTruncating(inform(msg)) - def informProgress(msg: String) = if (opt.verbose) inform("[" + msg + "]") - def inform[T](msg: String, value: T): T = returning(value)(x => inform(msg + x)) + def informProgress(msg: String) = if (settings.verbose.value) inform("[" + msg + "]") def informTime(msg: String, start: Long) = informProgress(elapsedMessage(msg, start)) def logError(msg: String, t: Throwable): Unit = () - def logAfterEveryPhase[T](msg: String)(op: => T) { - log("Running operation '%s' after every phase.\n".format(msg) + describeAfterEveryPhase(op)) - } - override def shouldLogAtThisPhase = settings.log.isSetByUser && ( (settings.log containsPhase globalPhase) || (settings.log containsPhase phase) ) @@ -299,7 +292,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) private val reader: SourceReader = { val defaultEncoding = Properties.sourceEncoding - val defaultReader = Properties.sourceReader def loadCharset(name: String) = try Some(Charset.forName(name)) @@ -312,7 +304,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) None } - val charset = opt.encoding flatMap loadCharset getOrElse { + val charset = ( if (settings.encoding.isSetByUser) Some(settings.encoding.value) else None ) flatMap loadCharset getOrElse { settings.encoding.value = defaultEncoding // A mandatory charset Charset.forName(defaultEncoding) } @@ -327,7 +319,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } } - opt.sourceReader flatMap loadReader getOrElse { + ( if (settings.sourceReader.isSetByUser) Some(settings.sourceReader.value) else None ) flatMap loadReader getOrElse { new SourceReader(charset.newDecoder(), reporter) } } @@ -335,54 +327,12 @@ class Global(var currentSettings: Settings, var reporter: Reporter) if (!dependencyAnalysis.off) dependencyAnalysis.loadDependencyAnalysis() - if (opt.verbose || opt.logClasspath) { + if (settings.verbose.value || settings.Ylogcp.value) { // Uses the "do not truncate" inform informComplete("[search path for source files: " + classPath.sourcepaths.mkString(",") + "]") informComplete("[search path for class files: " + classPath.asClasspathString + "]") } - object opt extends AestheticSettings { - def settings = Global.this.settings - - // protected implicit lazy val globalPhaseOrdering: Ordering[Phase] = Ordering[Int] on (_.id) - def isActive(ph: Settings#PhasesSetting) = ph containsPhase globalPhase - def wasActive(ph: Settings#PhasesSetting) = ph containsPhase globalPhase.prev - - // Allows for syntax like scalac -Xshow-class Random@erasure,typer - private def splitClassAndPhase(str: String, term: Boolean): Name = { - def mkName(s: String) = if (term) newTermName(s) else newTypeName(s) - (str indexOf '@') match { - case -1 => mkName(str) - case idx => - val phasePart = str drop (idx + 1) - settings.Yshow.tryToSetColon(phasePart split ',' toList) - mkName(str take idx) - } - } - - // behavior - - // debugging - def checkPhase = wasActive(settings.check) - def logPhase = isActive(settings.log) - - // Write *.icode files right after GenICode when -Xprint-icode was given. - def writeICodeAtICode = settings.writeICode.isSetByUser && isActive(settings.writeICode) - - // showing/printing things - def browsePhase = isActive(settings.browse) - def echoFilenames = opt.debug && (opt.verbose || currentRun.size < 5) - def noShow = settings.Yshow.isDefault - def printLate = settings.printLate.value - def printPhase = isActive(settings.Xprint) - def showNames = List(showClass, showObject).flatten - def showPhase = isActive(settings.Yshow) - def showSymbols = settings.Yshowsyms.value - def showTrees = settings.Xshowtrees.value || settings.XshowtreesCompact.value || settings.XshowtreesStringified.value - val showClass = optSetting[String](settings.Xshowcls) map (x => splitClassAndPhase(x, false)) - val showObject = optSetting[String](settings.Xshowobj) map (x => splitClassAndPhase(x, true)) - } - // The current division between scala.reflect.* and scala.tools.nsc.* is pretty // clunky. It is often difficult to have a setting influence something without having // to create it on that side. For this one my strategy is a constant def at the file @@ -391,11 +341,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter) // Here comes another one... override protected val enableTypeVarExperimentals = settings.Xexperimental.value - // True if -Xscript has been set, indicating a script run. - def isScriptRun = opt.script.isDefined - def getSourceFile(f: AbstractFile): BatchSourceFile = - if (isScriptRun) ScriptSourceFile(f, reader read f) + if (settings.script.isSetByUser) ScriptSourceFile(f, reader read f) else new BatchSourceFile(f, reader read f) def getSourceFile(name: String): SourceFile = { @@ -450,7 +397,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) if ((unit ne null) && unit.exists) lastSeenSourceFile = unit.source - if (opt.echoFilenames) + if (settings.debug.value && (settings.verbose.value || currentRun.size < 5)) inform("[running phase " + name + " on " + unit + "]") val unit0 = currentUnit @@ -469,8 +416,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } /** Switch to turn on detailed type logs */ - var printTypings = settings.Ytyperdebug.value - var printInfers = settings.Yinferdebug.value + val printTypings = settings.Ytyperdebug.value + val printInfers = settings.Yinferdebug.value // phaseName = "parser" object syntaxAnalyzer extends { @@ -688,13 +635,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } } - // phaseName = "SAMPLE PHASE" - object sampleTransform extends { - val global: Global.this.type = Global.this - val runsAfter = List[String]() - val runsRightAfter = None - } with SampleTransform - /** The checkers are for validating the compiler data structures * at phase boundaries. */ @@ -828,48 +768,16 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** Returns List of (phase, value) pairs, including only those * where the value compares unequal to the previous phase's value. */ - def afterEachPhase[T](op: => T): List[(Phase, T)] = { + def afterEachPhase[T](op: => T): List[(Phase, T)] = { // used in tests phaseDescriptors.map(_.ownPhase).filterNot(_ eq NoPhase).foldLeft(List[(Phase, T)]()) { (res, ph) => - val value = afterPhase(ph)(op) + val value = exitingPhase(ph)(op) if (res.nonEmpty && res.head._2 == value) res else ((ph, value)) :: res } reverse } - /** Returns List of ChangeAfterPhase objects, encapsulating those - * phase transitions where the result of the operation gave a different - * list than it had when run during the previous phase. - */ - def changesAfterEachPhase[T](op: => List[T]): List[ChangeAfterPhase[T]] = { - val ops = ((NoPhase, Nil)) :: afterEachPhase(op) - - ops sliding 2 map { - case (_, before) :: (ph, after) :: Nil => - val lost = before filterNot (after contains _) - val gained = after filterNot (before contains _) - ChangeAfterPhase(ph, lost, gained) - case _ => ??? - } toList - } private def numberedPhase(ph: Phase) = "%2d/%s".format(ph.id, ph.name) - case class ChangeAfterPhase[+T](ph: Phase, lost: List[T], gained: List[T]) { - private def mkStr(what: String, xs: List[_]) = ( - if (xs.isEmpty) "" - else xs.mkString(what + " after " + numberedPhase(ph) + " {\n ", "\n ", "\n}\n") - ) - override def toString = mkStr("Lost", lost) + mkStr("Gained", gained) - } - - def describeAfterEachPhase[T](op: => T): List[String] = - afterEachPhase(op) map { case (ph, t) => "[after %-15s] %s".format(numberedPhase(ph), t) } - - def describeAfterEveryPhase[T](op: => T): String = - describeAfterEachPhase(op) map (" " + _ + "\n") mkString - - def printAfterEachPhase[T](op: => T): Unit = - describeAfterEachPhase(op) foreach (m => println(" " + m)) - // ------------ Invalidations --------------------------------- /** Is given package class a system package class that cannot be invalidated? @@ -1092,40 +1000,37 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def currentUnit: CompilationUnit = if (currentRun eq null) NoCompilationUnit else currentRun.currentUnit def currentSource: SourceFile = if (currentUnit.exists) currentUnit.source else lastSeenSourceFile - // TODO - trim these to the absolute minimum. - @inline final def afterErasure[T](op: => T): T = afterPhase(currentRun.erasurePhase)(op) - @inline final def afterPostErasure[T](op: => T): T = afterPhase(currentRun.posterasurePhase)(op) - @inline final def afterExplicitOuter[T](op: => T): T = afterPhase(currentRun.explicitouterPhase)(op) - @inline final def afterFlatten[T](op: => T): T = afterPhase(currentRun.flattenPhase)(op) - @inline final def afterIcode[T](op: => T): T = afterPhase(currentRun.icodePhase)(op) - @inline final def afterMixin[T](op: => T): T = afterPhase(currentRun.mixinPhase)(op) - @inline final def afterPickler[T](op: => T): T = afterPhase(currentRun.picklerPhase)(op) - @inline final def afterRefchecks[T](op: => T): T = afterPhase(currentRun.refchecksPhase)(op) - @inline final def afterSpecialize[T](op: => T): T = afterPhase(currentRun.specializePhase)(op) - @inline final def afterTyper[T](op: => T): T = afterPhase(currentRun.typerPhase)(op) - @inline final def afterUncurry[T](op: => T): T = afterPhase(currentRun.uncurryPhase)(op) - @inline final def beforeErasure[T](op: => T): T = beforePhase(currentRun.erasurePhase)(op) - @inline final def beforeExplicitOuter[T](op: => T): T = beforePhase(currentRun.explicitouterPhase)(op) - @inline final def beforeFlatten[T](op: => T): T = beforePhase(currentRun.flattenPhase)(op) - @inline final def beforeIcode[T](op: => T): T = beforePhase(currentRun.icodePhase)(op) - @inline final def beforeMixin[T](op: => T): T = beforePhase(currentRun.mixinPhase)(op) - @inline final def beforePickler[T](op: => T): T = beforePhase(currentRun.picklerPhase)(op) - @inline final def beforeRefchecks[T](op: => T): T = beforePhase(currentRun.refchecksPhase)(op) - @inline final def beforeSpecialize[T](op: => T): T = beforePhase(currentRun.specializePhase)(op) - @inline final def beforeTyper[T](op: => T): T = beforePhase(currentRun.typerPhase)(op) - @inline final def beforeUncurry[T](op: => T): T = beforePhase(currentRun.uncurryPhase)(op) - - def explainContext(c: analyzer.Context): String = ( - if (c == null) "" else ( - """| context owners: %s - | - |Enclosing block or template: - |%s""".format( - c.owner.ownerChain.takeWhile(!_.isPackageClass).mkString(" -> "), - nodePrinters.nodeToString(c.enclClassOrMethod.tree) - ) - ) + def isGlobalInitialized = ( + definitions.isDefinitionsInitialized + && rootMirror.isMirrorInitialized ) + override def isPastTyper = ( + (curRun ne null) + && isGlobalInitialized // defense against init order issues + && (globalPhase.id > currentRun.typerPhase.id) + ) + + // TODO - trim these to the absolute minimum. + @inline final def exitingErasure[T](op: => T): T = exitingPhase(currentRun.erasurePhase)(op) + @inline final def exitingPostErasure[T](op: => T): T = exitingPhase(currentRun.posterasurePhase)(op) + @inline final def exitingExplicitOuter[T](op: => T): T = exitingPhase(currentRun.explicitouterPhase)(op) + @inline final def exitingFlatten[T](op: => T): T = exitingPhase(currentRun.flattenPhase)(op) + @inline final def exitingMixin[T](op: => T): T = exitingPhase(currentRun.mixinPhase)(op) + @inline final def exitingPickler[T](op: => T): T = exitingPhase(currentRun.picklerPhase)(op) + @inline final def exitingRefchecks[T](op: => T): T = exitingPhase(currentRun.refchecksPhase)(op) + @inline final def exitingSpecialize[T](op: => T): T = exitingPhase(currentRun.specializePhase)(op) + @inline final def exitingTyper[T](op: => T): T = exitingPhase(currentRun.typerPhase)(op) + @inline final def exitingUncurry[T](op: => T): T = exitingPhase(currentRun.uncurryPhase)(op) + @inline final def enteringErasure[T](op: => T): T = enteringPhase(currentRun.erasurePhase)(op) + @inline final def enteringExplicitOuter[T](op: => T): T = enteringPhase(currentRun.explicitouterPhase)(op) + @inline final def enteringFlatten[T](op: => T): T = enteringPhase(currentRun.flattenPhase)(op) + @inline final def enteringIcode[T](op: => T): T = enteringPhase(currentRun.icodePhase)(op) + @inline final def enteringMixin[T](op: => T): T = enteringPhase(currentRun.mixinPhase)(op) + @inline final def enteringPickler[T](op: => T): T = enteringPhase(currentRun.picklerPhase)(op) + @inline final def enteringRefchecks[T](op: => T): T = enteringPhase(currentRun.refchecksPhase)(op) + @inline final def enteringTyper[T](op: => T): T = enteringPhase(currentRun.typerPhase)(op) + @inline final def enteringUncurry[T](op: => T): T = enteringPhase(currentRun.uncurryPhase)(op) + // Owners up to and including the first package class. private def ownerChainString(sym: Symbol): String = ( if (sym == null) "" @@ -1138,9 +1043,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) pairs.toList collect { case (k, v) if v != null => "%20s: %s".format(k, v) } mkString "\n" ) - def explainTree(t: Tree): String = formatExplain( - ) - /** Don't want to introduce new errors trying to report errors, * so swallow exceptions. */ @@ -1152,7 +1054,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val info1 = formatExplain( "while compiling" -> currentSource.path, - "during phase" -> ( if (globalPhase eq phase) phase else "global=%s, atPhase=%s".format(globalPhase, phase) ), + "during phase" -> ( if (globalPhase eq phase) phase else "global=%s, enteringPhase=%s".format(globalPhase, phase) ), "library version" -> scala.util.Properties.versionString, "compiler version" -> Properties.versionString, "reconstructed args" -> settings.recreateArgs.mkString(" ") @@ -1168,7 +1070,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val info3: List[String] = ( ( List("== Enclosing template or block ==", nodePrinters.nodeToString(enclosing).trim) ) ++ ( if (tpe eq null) Nil else List("== Expanded type of tree ==", typeDeconstruct.show(tpe)) ) - ++ ( if (!opt.debug) Nil else List("== Current unit body ==", nodePrinters.nodeToString(currentUnit.body)) ) + ++ ( if (!settings.debug.value) Nil else List("== Current unit body ==", nodePrinters.nodeToString(currentUnit.body)) ) ++ ( List(errorMessage) ) ) @@ -1182,7 +1084,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def echoPhaseSummary(ph: Phase) = { /** Only output a summary message under debug if we aren't echoing each file. */ - if (opt.debug && !opt.echoFilenames) + if (settings.debug.value && !(settings.verbose.value || currentRun.size < 5)) inform("[running phase " + ph.name + " on " + currentRun.size + " compilation units]") } @@ -1198,7 +1100,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } def newUnitParser(code: String) = new syntaxAnalyzer.UnitParser(newCompilationUnit(code)) - def newUnitScanner(code: String) = new syntaxAnalyzer.UnitScanner(newCompilationUnit(code)) def newCompilationUnit(code: String) = new CompilationUnit(newSourceFile(code)) def newSourceFile(code: String) = new BatchSourceFile("<console>", code) @@ -1221,18 +1122,14 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val inlinerWarnings = new ConditionalWarning("inliner", settings.YinlinerWarnings) val allConditionalWarnings = List(deprecationWarnings0, uncheckedWarnings0, featureWarnings, inlinerWarnings) - // for sbt's benefit - def uncheckedWarnings: List[(Position, String)] = uncheckedWarnings0.warnings.toList - def deprecationWarnings: List[(Position, String)] = deprecationWarnings0.warnings.toList + def uncheckedWarnings: List[(Position, String)] = uncheckedWarnings0.warnings.toList // used in sbt + def deprecationWarnings: List[(Position, String)] = deprecationWarnings0.warnings.toList // used in sbt var reportedFeature = Set[Symbol]() /** Has any macro expansion used a fallback during this run? */ var seenMacroExpansionsFallingBack = false - /** To be initialized from firstPhase. */ - private var terminalPhase: Phase = NoPhase - private val unitbuf = new mutable.ListBuffer[CompilationUnit] val compiledFiles = new mutable.HashSet[String] @@ -1393,7 +1290,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val namerPhase = phaseNamed("namer") // val packageobjectsPhase = phaseNamed("packageobjects") val typerPhase = phaseNamed("typer") - val inlineclassesPhase = phaseNamed("inlineclasses") + // val inlineclassesPhase = phaseNamed("inlineclasses") // val superaccessorsPhase = phaseNamed("superaccessors") val picklerPhase = phaseNamed("pickler") val refchecksPhase = phaseNamed("refchecks") @@ -1406,7 +1303,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val erasurePhase = phaseNamed("erasure") val posterasurePhase = phaseNamed("posterasure") // val lazyvalsPhase = phaseNamed("lazyvals") - val lambdaliftPhase = phaseNamed("lambdalift") + // val lambdaliftPhase = phaseNamed("lambdalift") // val constructorsPhase = phaseNamed("constructors") val flattenPhase = phaseNamed("flatten") val mixinPhase = phaseNamed("mixin") @@ -1416,12 +1313,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val inlineExceptionHandlersPhase = phaseNamed("inlineExceptionHandlers") val closelimPhase = phaseNamed("closelim") val dcePhase = phaseNamed("dce") - val jvmPhase = phaseNamed("jvm") + // val jvmPhase = phaseNamed("jvm") // val msilPhase = phaseNamed("msil") def runIsAt(ph: Phase) = globalPhase.id == ph.id - def runIsPast(ph: Phase) = globalPhase.id > ph.id - // def runIsAtBytecodeGen = (runIsAt(jvmPhase) || runIsAt(msilPhase)) def runIsAtOptimiz = { runIsAt(inlinerPhase) || // listing phases in full for robustness when -Ystop-after has been given. runIsAt(inlineExceptionHandlersPhase) || @@ -1490,8 +1385,24 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } } - private def showMembers() = - opt.showNames foreach (x => showDef(x, opt.declsOnly, globalPhase)) + private def showMembers() = { + // Allows for syntax like scalac -Xshow-class Random@erasure,typer + def splitClassAndPhase(str: String, term: Boolean): Name = { + def mkName(s: String) = if (term) newTermName(s) else newTypeName(s) + (str indexOf '@') match { + case -1 => mkName(str) + case idx => + val phasePart = str drop (idx + 1) + settings.Yshow.tryToSetColon(phasePart split ',' toList) + mkName(str take idx) + } + } + if (settings.Xshowcls.isSetByUser) + showDef(splitClassAndPhase(settings.Xshowcls.value, false), false, globalPhase) + + if (settings.Xshowobj.isSetByUser) + showDef(splitClassAndPhase(settings.Xshowobj.value, true), false, globalPhase) + } // Similarly, this will only be created under -Yshow-syms. object trackerFactory extends SymbolTrackers { @@ -1499,7 +1410,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) lazy val trackers = currentRun.units.toList map (x => SymbolTracker(x)) def snapshot() = { inform("\n[[symbol layout at end of " + phase + "]]") - afterPhase(phase) { + exitingPhase(phase) { trackers foreach { t => t.snapshot() inform(t.show("Heading from " + phase.prev.name + " to " + phase.name)) @@ -1509,6 +1420,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } def reportCompileErrors() { + if (!reporter.hasErrors && reporter.hasWarnings && settings.fatalWarnings.value) + globalError("No warnings can be incurred under -Xfatal-warnings.") + if (reporter.hasErrors) { for ((sym, file) <- symSource.iterator) { sym.reset(new loaders.SourcefileLoader(file)) @@ -1528,8 +1442,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** Compile list of source files */ def compileSources(_sources: List[SourceFile]) { - val depSources = dependencyAnalysis calculateFiles _sources.distinct - val sources = coreClassesFirst(depSources) + val sources = dependencyAnalysis calculateFiles _sources.distinct // there is a problem already, e.g. a plugin was passed a bad option if (reporter.hasErrors) return @@ -1547,12 +1460,11 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def compileUnits(units: List[CompilationUnit], fromPhase: Phase) { try compileUnitsInternal(units, fromPhase) catch { case ex: Throwable => - val shown = if (settings.verbose.value) { - val pw = new java.io.PrintWriter(new java.io.StringWriter) - ex.printStackTrace(pw) - pw.toString - } else ex.getClass.getName - // ex.printStackTrace(Console.out) // DEBUG for fsc, note that error stacktraces do not print in fsc + val shown = if (settings.verbose.value) + stackTraceString(ex) + else + stackTraceHeadString(ex) // note that error stacktraces do not print in fsc + globalError(supplementErrorMessage("uncaught exception during compilation: " + shown)) throw ex } @@ -1576,37 +1488,40 @@ class Global(var currentSettings: Settings, var reporter: Reporter) // progress update informTime(globalPhase.description, startTime) phaseTimings(globalPhase) = currentTime - startTime - - if (opt.writeICodeAtICode || (opt.printPhase && runIsAtOptimiz)) { + val shouldWriteIcode = ( + (settings.writeICode.isSetByUser && (settings.writeICode containsPhase globalPhase)) + || (!settings.Xprint.doAllPhases && (settings.Xprint containsPhase globalPhase) && runIsAtOptimiz) + ) + if (shouldWriteIcode) { // Write *.icode files when -Xprint-icode or -Xprint:<some-optimiz-phase> was given. writeICode() - } else if (opt.printPhase || opt.printLate && runIsAt(cleanupPhase)) { + } else if ((settings.Xprint containsPhase globalPhase) || settings.printLate.value && runIsAt(cleanupPhase)) { // print trees - if (opt.showTrees) nodePrinters.printAll() + if (settings.Xshowtrees.value || settings.XshowtreesCompact.value || settings.XshowtreesStringified.value) nodePrinters.printAll() else printAllUnits() } // print the symbols presently attached to AST nodes - if (opt.showSymbols) + if (settings.Yshowsyms.value) trackerFactory.snapshot() // print members - if (opt.showPhase) + if (settings.Yshow containsPhase globalPhase) showMembers() // browse trees with swing tree viewer - if (opt.browsePhase) + if (settings.browse containsPhase globalPhase) treeBrowser browse (phase.name, units) // move the pointer globalPhase = globalPhase.next // run tree/icode checkers - if (opt.checkPhase) + if (settings.check containsPhase globalPhase.prev) runCheckers() // output collected statistics - if (opt.printStats) + if (settings.Ystatistics.value) statistics.print(phase) advancePhase @@ -1616,7 +1531,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) units map (_.body) foreach (traceSymbols recordSymbolsInTree _) // In case no phase was specified for -Xshow-class/object, show it now for sure. - if (opt.noShow) + if (settings.Yshow.isDefault) showMembers() reportCompileErrors() @@ -1632,7 +1547,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) // Reset project if (!stopPhase("namer")) { - atPhase(namerPhase) { + enteringPhase(namerPhase) { resetProjectClasses(RootClass) } } @@ -1648,7 +1563,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def compile(filenames: List[String]) { try { val sources: List[SourceFile] = - if (isScriptRun && filenames.size > 1) returning(Nil)(_ => globalError("can only compile one script at a time")) + if (settings.script.isSetByUser && filenames.size > 1) returning(Nil)(_ => globalError("can only compile one script at a time")) else filenames map getSourceFile compileSources(sources) @@ -1672,7 +1587,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) if (firstPhase ne null) { // we might get here during initialization, is a source is newer than the binary val maxId = math.max(globalPhase.id, typerPhase.id) firstPhase.iterator takeWhile (_.id < maxId) foreach (ph => - atPhase(ph)(ph.asInstanceOf[GlobalPhase] applyPhase unit)) + enteringPhase(ph)(ph.asInstanceOf[GlobalPhase] applyPhase unit)) refreshProgress } } @@ -1681,56 +1596,16 @@ class Global(var currentSettings: Settings, var reporter: Reporter) * is needed for?) */ private def resetPackageClass(pclazz: Symbol) { - atPhase(firstPhase) { - pclazz.setInfo(atPhase(typerPhase)(pclazz.info)) + enteringPhase(firstPhase) { + pclazz.setInfo(enteringPhase(typerPhase)(pclazz.info)) } if (!pclazz.isRoot) resetPackageClass(pclazz.owner) } - - /** - * Re-orders the source files to - * 1. This Space Intentionally Left Blank - * 2. LowPriorityImplicits / EmbeddedControls (i.e. parents of Predef) - * 3. the rest - * - * 1 is to avoid cyclic reference errors. - * 2 is due to the following. When completing "Predef" (*), typedIdent is called - * for its parents (e.g. "LowPriorityImplicits"). typedIdent checks whether - * the symbol reallyExists, which tests if the type of the symbol after running - * its completer is != NoType. - * If the "namer" phase has not yet run for "LowPriorityImplicits", the symbol - * has a SourcefileLoader as type. Calling "doComplete" on it does nothing at - * all, because the source file is part of the files to be compiled anyway. - * So the "reallyExists" test will return "false". - * Only after the namer, the symbol has a lazy type which actually computes - * the info, and "reallyExists" behaves as expected. - * So we need to make sure that the "namer" phase is run on predef's parents - * before running it on predef. - * - * (*) Predef is completed early when calling "mkAttributedRef" during the - * addition of "import Predef._" to sourcefiles. So this situation can't - * happen for user classes. - * - */ - private def coreClassesFirst(files: List[SourceFile]) = { - val goLast = 4 - def rank(f: SourceFile) = { - if (f.file.container.name != "scala") goLast - else f.file.name match { - case "LowPriorityImplicits.scala" => 2 - case "StandardEmbeddings.scala" => 2 - case "EmbeddedControls.scala" => 2 - case "Predef.scala" => 3 /* Predef.scala before Any.scala, etc. */ - case _ => goLast - } - } - files sortBy rank - } } // class Run def printAllUnits() { print("[[syntax trees at end of %25s]]".format(phase)) - afterPhase(phase)(currentRun.units foreach { unit => + exitingPhase(phase)(currentRun.units foreach { unit => nodePrinters showUnit unit }) } @@ -1739,7 +1614,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) */ def showDef(fullName: Name, declsOnly: Boolean, ph: Phase) = { val boringOwners = Set[Symbol](definitions.AnyClass, definitions.AnyRefClass, definitions.ObjectClass) - def phased[T](body: => T): T = afterPhase(ph)(body) + def phased[T](body: => T): T = exitingPhase(ph)(body) def boringMember(sym: Symbol) = boringOwners(sym.owner) def symString(sym: Symbol) = if (sym.isTerm) sym.defString else sym.toString @@ -1785,7 +1660,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val printer = new icodes.TextPrinter(null, icodes.linearizer) icodes.classes.values.foreach((cls) => { val suffix = if (cls.symbol.hasModuleFlag) "$.icode" else ".icode" - var file = getFile(cls.symbol, suffix) + val file = getFile(cls.symbol, suffix) // if (file.exists()) // file = new File(file.getParentFile(), file.getName() + "1") try { @@ -1795,7 +1670,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) informProgress("wrote " + file) } catch { case ex: IOException => - if (opt.debug) ex.printStackTrace() + if (settings.debug.value) ex.printStackTrace() globalError("could not write file " + file) } }) @@ -1806,14 +1681,11 @@ class Global(var currentSettings: Settings, var reporter: Reporter) // and forScaladoc default to onlyPresentation, which is the same as defaulting // to false except in old code. The downside is that this leaves us calling a // deprecated method: but I see no simple way out, so I leave it for now. - def forJVM = opt.jvm - override def forMSIL = opt.msil - def forInteractive = onlyPresentation - def forScaladoc = onlyPresentation + // def forJVM = settings.target.value startsWith "jvm" + override def forMSIL = settings.target.value startsWith "msil" + def forInteractive = false + def forScaladoc = false def createJavadoc = false - - @deprecated("Use forInteractive or forScaladoc, depending on what you're after", "2.9.0") - def onlyPresentation = false } object Global { diff --git a/src/compiler/scala/tools/nsc/Main.scala b/src/compiler/scala/tools/nsc/Main.scala index 7d112dfb3e..5a3ea56f67 100644 --- a/src/compiler/scala/tools/nsc/Main.scala +++ b/src/compiler/scala/tools/nsc/Main.scala @@ -7,15 +7,12 @@ package scala.tools.nsc import java.io.File import File.pathSeparator - import scala.tools.nsc.interactive.{ RefinedBuildManager, SimpleBuildManager } import scala.tools.nsc.io.AbstractFile -import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} -import scala.reflect.internal.util.{ BatchSourceFile, FakePos } //{Position} import Properties.msilLibPath /** The main class for NSC, a compiler for the programming - * language Scala. + * language Scala. */ object Main extends Driver with EvalLoop { diff --git a/src/compiler/scala/tools/nsc/MainBench.scala b/src/compiler/scala/tools/nsc/MainBench.scala index f18ff19d7d..03190a63f3 100644 --- a/src/compiler/scala/tools/nsc/MainBench.scala +++ b/src/compiler/scala/tools/nsc/MainBench.scala @@ -5,28 +5,20 @@ package scala.tools.nsc -import java.io.File -import File.pathSeparator - -import scala.tools.nsc.interactive.{ RefinedBuildManager, SimpleBuildManager } -import scala.tools.nsc.io.AbstractFile -import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} -import scala.reflect.internal.util.{ BatchSourceFile, FakePos } //{Position} -import Properties.{ versionString, copyrightString, residentPromptString, msilLibPath } import scala.reflect.internal.util.Statistics /** The main class for NSC, a compiler for the programming * language Scala. */ object MainBench extends Driver with EvalLoop { - + lazy val theCompiler = Global(settings, reporter) - + override def newCompiler() = theCompiler - + val NIter = 50 val NBest = 10 - + override def main(args: Array[String]) = { val times = new Array[Long](NIter) var start = System.nanoTime() diff --git a/src/compiler/scala/tools/nsc/MainGenericRunner.scala b/src/compiler/scala/tools/nsc/MainGenericRunner.scala index e4a20b4a8c..adb03ca374 100644 --- a/src/compiler/scala/tools/nsc/MainGenericRunner.scala +++ b/src/compiler/scala/tools/nsc/MainGenericRunner.scala @@ -5,8 +5,6 @@ package scala.tools.nsc -import java.net.URL -import scala.tools.util.PathResolver import io.{ File } import util.{ ClassPath, ScalaClassLoader } import Properties.{ versionString, copyrightString } diff --git a/src/compiler/scala/tools/nsc/ObjectRunner.scala b/src/compiler/scala/tools/nsc/ObjectRunner.scala index f5123513c4..95264aeda6 100644 --- a/src/compiler/scala/tools/nsc/ObjectRunner.scala +++ b/src/compiler/scala/tools/nsc/ObjectRunner.scala @@ -8,15 +8,9 @@ package scala.tools.nsc import java.net.URL import util.ScalaClassLoader -import java.lang.reflect.InvocationTargetException import util.Exceptional.unwrap trait CommonRunner { - /** Check whether a class with the specified name - * exists on the specified class path. */ - def classExists(urls: List[URL], objectName: String): Boolean = - ScalaClassLoader.classExists(urls, objectName) - /** Run a given object, specified by name, using a * specified classpath and argument list. * diff --git a/src/compiler/scala/tools/nsc/PhaseAssembly.scala b/src/compiler/scala/tools/nsc/PhaseAssembly.scala index cff3590b3f..67dc1e3b66 100644 --- a/src/compiler/scala/tools/nsc/PhaseAssembly.scala +++ b/src/compiler/scala/tools/nsc/PhaseAssembly.scala @@ -55,7 +55,7 @@ trait PhaseAssembly { * node object does not exist, then create it. */ def getNodeByPhase(phs: SubComponent): Node = { - var node: Node = getNodeByPhase(phs.phaseName) + val node: Node = getNodeByPhase(phs.phaseName) node.phaseobj match { case None => node.phaseobj = Some(List[SubComponent](phs)) @@ -75,7 +75,7 @@ trait PhaseAssembly { * list of the nodes */ def softConnectNodes(frm: Node, to: Node) { - var e = new Edge(frm, to, false) + val e = new Edge(frm, to, false) this.edges += e frm.after += e @@ -87,7 +87,7 @@ trait PhaseAssembly { * list of the nodes */ def hardConnectNodes(frm: Node, to: Node) { - var e = new Edge(frm, to, true) + val e = new Edge(frm, to, true) this.edges += e frm.after += e @@ -164,7 +164,7 @@ trait PhaseAssembly { } else { - var promote = hl.to.before.filter(e => (!e.hard)) + val promote = hl.to.before.filter(e => (!e.hard)) hl.to.before.clear sanity foreach (edge => hl.to.before += edge) for (edge <- promote) { @@ -182,7 +182,7 @@ trait PhaseAssembly { /** Remove all nodes in the given graph, that have no phase object * Make sure to clean up all edges when removing the node object - * <code>Inform</code> with warnings, if an external phase has a + * `Inform` with warnings, if an external phase has a * dependency on something that is dropped. */ def removeDanglingNodes() { @@ -245,7 +245,7 @@ trait PhaseAssembly { for (phs <- phsSet) { - var fromnode = graph.getNodeByPhase(phs) + val fromnode = graph.getNodeByPhase(phs) phs.runsRightAfter match { case None => @@ -306,7 +306,7 @@ trait PhaseAssembly { sbuf.append("\"" + node.allPhaseNames + "(" + node.level + ")" + "\" [color=\"#0000ff\"]\n") } sbuf.append("}\n") - var out = new BufferedWriter(new FileWriter(filename)) + val out = new BufferedWriter(new FileWriter(filename)) out.write(sbuf.toString) out.flush() out.close() diff --git a/src/compiler/scala/tools/nsc/Phases.scala b/src/compiler/scala/tools/nsc/Phases.scala index c914344fd5..1266622b6d 100644 --- a/src/compiler/scala/tools/nsc/Phases.scala +++ b/src/compiler/scala/tools/nsc/Phases.scala @@ -5,7 +5,6 @@ package scala.tools.nsc -import symtab.Flags import scala.reflect.internal.util.TableDef import scala.language.postfixOps @@ -21,7 +20,6 @@ object Phases { } val values = new Array[Cell](MaxPhases + 1) def results = values filterNot (_ == null) - def apply(ph: Phase): T = values(ph.id).value def update(ph: Phase, value: T): Unit = values(ph.id) = Cell(ph, value) } /** A class for recording the elapsed time of each phase in the @@ -39,7 +37,6 @@ object Phases { >> ("ms" -> (_.value)) >+ " " << ("share" -> (_.value.toDouble * 100 / total formatted "%.2f")) } - def formatted = "" + table() } } diff --git a/src/compiler/scala/tools/nsc/Properties.scala b/src/compiler/scala/tools/nsc/Properties.scala index 55fd196716..570d5572d6 100644 --- a/src/compiler/scala/tools/nsc/Properties.scala +++ b/src/compiler/scala/tools/nsc/Properties.scala @@ -21,5 +21,4 @@ object Properties extends scala.util.PropertiesTrait { // derived values def isEmacsShell = propOrEmpty("env.emacs") != "" - def fileEndings = fileEndingString.split("""\|""").toList } diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala index 107c4b3df3..92b2dc79ed 100644 --- a/src/compiler/scala/tools/nsc/ScriptRunner.scala +++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala @@ -7,7 +7,6 @@ package scala.tools.nsc import io.{ Directory, File, Path } import java.io.IOException -import java.net.URL import scala.tools.nsc.reporters.{Reporter,ConsoleReporter} import util.Exceptional.unwrap @@ -49,25 +48,12 @@ class ScriptRunner extends HasCompileSocket { case x => x } - def isScript(settings: Settings) = settings.script.value != "" - /** Choose a jar filename to hold the compiled version of a script. */ private def jarFileFor(scriptFile: String)= File( if (scriptFile endsWith ".jar") scriptFile else scriptFile.stripSuffix(".scala") + ".jar" ) - /** Read the entire contents of a file as a String. */ - private def contentsOfFile(filename: String) = File(filename).slurp() - - /** Split a fully qualified object name into a - * package and an unqualified object name */ - private def splitObjectName(fullname: String): (Option[String], String) = - (fullname lastIndexOf '.') match { - case -1 => (None, fullname) - case idx => (Some(fullname take idx), fullname drop (idx + 1)) - } - /** Compile a script using the fsc compilation daemon. */ private def compileWithDaemon(settings: GenericRunnerSettings, scriptFileIn: String) = { diff --git a/src/compiler/scala/tools/nsc/SubComponent.scala b/src/compiler/scala/tools/nsc/SubComponent.scala index a0468a22b9..9b8582ae02 100644 --- a/src/compiler/scala/tools/nsc/SubComponent.scala +++ b/src/compiler/scala/tools/nsc/SubComponent.scala @@ -47,8 +47,8 @@ abstract class SubComponent { private var ownPhaseCache: WeakReference[Phase] = new WeakReference(null) private var ownPhaseRunId = global.NoRunId - @inline final def beforeOwnPhase[T](op: => T) = global.beforePhase(ownPhase)(op) - @inline final def afterOwnPhase[T](op: => T) = global.afterPhase(ownPhase)(op) + @inline final def beforeOwnPhase[T](op: => T) = global.enteringPhase(ownPhase)(op) + @inline final def afterOwnPhase[T](op: => T) = global.exitingPhase(ownPhase)(op) /** The phase corresponding to this subcomponent in the current compiler run */ def ownPhase: Phase = { diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala index 5a4be5125d..023f3c229c 100755 --- a/src/compiler/scala/tools/nsc/ast/DocComments.scala +++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala @@ -7,10 +7,7 @@ package scala.tools.nsc package ast import symtab._ -import reporters._ -import scala.reflect.internal.util.{Position, NoPosition} import util.DocStrings._ -import scala.reflect.internal.Chars._ import scala.collection.mutable /* @@ -24,11 +21,6 @@ trait DocComments { self: Global => /** The raw doc comment map */ val docComments = mutable.HashMap[Symbol, DocComment]() - /** Associate comment with symbol `sym` at position `pos`. */ - def docComment(sym: Symbol, docStr: String, pos: Position = NoPosition) = - if ((sym ne null) && (sym ne NoSymbol)) - docComments += (sym -> DocComment(docStr, pos)) - /** The raw doc comment of symbol `sym`, as it appears in the source text, "" if missing. */ def rawDocComment(sym: Symbol): String = @@ -123,8 +115,6 @@ trait DocComments { self: Global => getDocComment(sym) map getUseCases getOrElse List() } - def useCases(sym: Symbol): List[(Symbol, String, Position)] = useCases(sym, sym.enclClass) - /** Returns the javadoc format of doc comment string `s`, including wiki expansion */ def toJavaDoc(s: String): String = expandWiki(s) @@ -464,7 +454,7 @@ trait DocComments { self: Global => //val (classes, pkgs) = site.ownerChain.span(!_.isPackageClass) //val sites = (classes ::: List(pkgs.head, rootMirror.RootClass))) //findIn(sites) - findIn(site.ownerChain ::: List(definitions.EmptyPackage)) + findIn(site.ownerChain ::: List(rootMirror.EmptyPackage)) } def getType(str: String, variable: String): Type = { diff --git a/src/compiler/scala/tools/nsc/ast/Positions.scala b/src/compiler/scala/tools/nsc/ast/Positions.scala index d8fb632f73..77acbba056 100644 --- a/src/compiler/scala/tools/nsc/ast/Positions.scala +++ b/src/compiler/scala/tools/nsc/ast/Positions.scala @@ -1,7 +1,7 @@ package scala.tools.nsc package ast -import scala.reflect.internal.util.{ SourceFile, Position, OffsetPosition, NoPosition } +import scala.reflect.internal.util.{ SourceFile, OffsetPosition } trait Positions extends scala.reflect.internal.Positions { self: Global => diff --git a/src/compiler/scala/tools/nsc/ast/Printers.scala b/src/compiler/scala/tools/nsc/ast/Printers.scala index 83222a24b4..b9f348632a 100644 --- a/src/compiler/scala/tools/nsc/ast/Printers.scala +++ b/src/compiler/scala/tools/nsc/ast/Printers.scala @@ -7,8 +7,6 @@ package scala.tools.nsc package ast import java.io.{ OutputStream, PrintWriter, StringWriter, Writer } -import symtab.Flags._ -import symtab.SymbolTable trait Printers extends scala.reflect.internal.Printers { this: Global => @@ -202,91 +200,12 @@ trait Printers extends scala.reflect.internal.Printers { this: Global => override def printTree(tree: Tree) { print(safe(tree)) } } - class TreeMatchTemplate { - // non-trees defined in Trees - // - // case class ImportSelector(name: Name, namePos: Int, rename: Name, renamePos: Int) - // case class Modifiers(flags: Long, privateWithin: Name, annotations: List[Tree], positions: Map[Long, Position]) - // - def apply(t: Tree): Unit = t match { - // eliminated by typer - case Annotated(annot, arg) => - case AssignOrNamedArg(lhs, rhs) => - case DocDef(comment, definition) => - case Import(expr, selectors) => - - // eliminated by refchecks - case ModuleDef(mods, name, impl) => - case TypeTreeWithDeferredRefCheck() => - - // eliminated by erasure - case TypeDef(mods, name, tparams, rhs) => - case Typed(expr, tpt) => - - // eliminated by cleanup - case ApplyDynamic(qual, args) => - - // eliminated by explicitouter - case Alternative(trees) => - case Bind(name, body) => - case CaseDef(pat, guard, body) => - case Star(elem) => - case UnApply(fun, args) => - - // eliminated by lambdalift - case Function(vparams, body) => - - // eliminated by uncurry - case AppliedTypeTree(tpt, args) => - case CompoundTypeTree(templ) => - case ExistentialTypeTree(tpt, whereClauses) => - case SelectFromTypeTree(qual, selector) => - case SingletonTypeTree(ref) => - case TypeBoundsTree(lo, hi) => - - // survivors - case Apply(fun, args) => - case ArrayValue(elemtpt, trees) => - case Assign(lhs, rhs) => - case Block(stats, expr) => - case ClassDef(mods, name, tparams, impl) => - case DefDef(mods, name, tparams, vparamss, tpt, rhs) => - case EmptyTree => - case Ident(name) => - case If(cond, thenp, elsep) => - case LabelDef(name, params, rhs) => - case Literal(value) => - case Match(selector, cases) => - case New(tpt) => - case PackageDef(pid, stats) => - case Return(expr) => - case Select(qualifier, selector) => - case Super(qual, mix) => - case Template(parents, self, body) => - case This(qual) => - case Throw(expr) => - case Try(block, catches, finalizer) => - case TypeApply(fun, args) => - case TypeTree() => - case ValDef(mods, name, tpt, rhs) => - - // missing from the Trees comment - case Parens(args) => // only used during parsing - case SelectFromArray(qual, name, erasure) => // only used during erasure - } - } - def asString(t: Tree): String = render(t, newStandardTreePrinter, settings.printtypes.value, settings.uniqid.value, settings.Yshowsymkinds.value) def asCompactString(t: Tree): String = render(t, newCompactTreePrinter, settings.printtypes.value, settings.uniqid.value, settings.Yshowsymkinds.value) def asCompactDebugString(t: Tree): String = render(t, newCompactTreePrinter, true, true, true) def newStandardTreePrinter(writer: PrintWriter): TreePrinter = new TreePrinter(writer) - def newStandardTreePrinter(stream: OutputStream): TreePrinter = newStandardTreePrinter(new PrintWriter(stream)) - def newStandardTreePrinter(): TreePrinter = newStandardTreePrinter(new PrintWriter(ConsoleWriter)) - def newCompactTreePrinter(writer: PrintWriter): CompactTreePrinter = new CompactTreePrinter(writer) - def newCompactTreePrinter(stream: OutputStream): CompactTreePrinter = newCompactTreePrinter(new PrintWriter(stream)) - def newCompactTreePrinter(): CompactTreePrinter = newCompactTreePrinter(new PrintWriter(ConsoleWriter)) override def newTreePrinter(writer: PrintWriter): TreePrinter = if (settings.Ycompacttrees.value) newCompactTreePrinter(writer) diff --git a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala index 5c954096f4..30a9348fb0 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala @@ -16,8 +16,6 @@ import javax.swing.tree._ import scala.concurrent.Lock import scala.text._ -import symtab.Flags._ -import symtab.SymbolTable import scala.language.implicitConversions /** @@ -509,7 +507,7 @@ abstract class TreeBrowsers { /** Return a textual representation of this t's symbol */ def symbolText(t: Tree): String = { val prefix = - if (t.hasSymbol) "[has] " + if (t.hasSymbolField) "[has] " else if (t.isDef) "[defines] " else "" @@ -529,10 +527,9 @@ abstract class TreeBrowsers { * attributes */ def symbolAttributes(t: Tree): String = { val s = t.symbol - var att = "" if ((s ne null) && (s != NoSymbol)) { - var str = flagsToString(s.flags) + var str = s.flagString if (s.isStaticMember) str = str + " isStatic "; (str + " annotations: " + s.annotations.mkString("", " ", "") + (if (s.isTypeSkolem) "\ndeSkolemized annotations: " + s.deSkolemize.annotations.mkString("", " ", "") else "")) diff --git a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala index 9a5b92e795..e8bc932bf5 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala @@ -21,7 +21,6 @@ trait TreeDSL { import global._ import definitions._ - import gen.{ scalaDot } object CODE { // Add a null check to a Tree => Tree function @@ -85,16 +84,12 @@ trait TreeDSL { def ANY_EQ (other: Tree) = OBJ_EQ(other AS ObjectClass.tpe) def ANY_== (other: Tree) = fn(target, Any_==, other) def ANY_!= (other: Tree) = fn(target, Any_!=, other) - def OBJ_== (other: Tree) = fn(target, Object_==, other) def OBJ_!= (other: Tree) = fn(target, Object_!=, other) def OBJ_EQ (other: Tree) = fn(target, Object_eq, other) def OBJ_NE (other: Tree) = fn(target, Object_ne, other) - def INT_| (other: Tree) = fn(target, getMember(IntClass, nme.OR), other) - def INT_& (other: Tree) = fn(target, getMember(IntClass, nme.AND), other) def INT_>= (other: Tree) = fn(target, getMember(IntClass, nme.GE), other) def INT_== (other: Tree) = fn(target, getMember(IntClass, nme.EQ), other) - def INT_!= (other: Tree) = fn(target, getMember(IntClass, nme.NE), other) // generic operations on ByteClass, IntClass, LongClass def GEN_| (other: Tree, kind: ClassSymbol) = fn(target, getMember(kind, nme.OR), other) @@ -102,9 +97,6 @@ trait TreeDSL { def GEN_== (other: Tree, kind: ClassSymbol) = fn(target, getMember(kind, nme.EQ), other) def GEN_!= (other: Tree, kind: ClassSymbol) = fn(target, getMember(kind, nme.NE), other) - def BOOL_&& (other: Tree) = fn(target, Boolean_and, other) - def BOOL_|| (other: Tree) = fn(target, Boolean_or, other) - /** Apply, Select, Match **/ def APPLY(params: Tree*) = Apply(target, params.toList) def APPLY(params: List[Tree]) = Apply(target, params) @@ -130,8 +122,6 @@ trait TreeDSL { def IS(tpe: Type) = gen.mkIsInstanceOf(target, tpe, true) def IS_OBJ(tpe: Type) = gen.mkIsInstanceOf(target, tpe, false) - // XXX having some difficulty expressing nullSafe in a way that doesn't freak out value types - // def TOSTRING() = nullSafe(fn(_: Tree, nme.toString_), LIT("null"))(target) def TOSTRING() = fn(target, nme.toString_) def GETCLASS() = fn(target, Object_getClass) } @@ -159,7 +149,6 @@ trait TreeDSL { def mkTree(rhs: Tree): ResultTreeType def ===(rhs: Tree): ResultTreeType - private var _mods: Modifiers = null private var _tpt: Tree = null private var _pos: Position = null @@ -167,19 +156,12 @@ trait TreeDSL { _tpt = TypeTree(tp) this } - def withFlags(flags: Long*): this.type = { - if (_mods == null) - _mods = defaultMods - - _mods = flags.foldLeft(_mods)(_ | _) - this - } def withPos(pos: Position): this.type = { _pos = pos this } - final def mods = if (_mods == null) defaultMods else _mods + final def mods = defaultMods final def tpt = if (_tpt == null) defaultTpt else _tpt final def pos = if (_pos == null) defaultPos else _pos } @@ -244,7 +226,6 @@ trait TreeDSL { } class TryStart(body: Tree, catches: List[CaseDef], fin: Tree) { def CATCH(xs: CaseDef*) = new TryStart(body, xs.toList, fin) - def FINALLY(x: Tree) = Try(body, catches, x) def ENDTRY = Try(body, catches, fin) } @@ -252,16 +233,9 @@ trait TreeDSL { def DEFAULT: CaseStart = new CaseStart(WILD.empty, EmptyTree) class SymbolMethods(target: Symbol) { - def BIND(body: Tree) = Bind(target, body) - def IS_NULL() = REF(target) OBJ_EQ NULL - def NOT_NULL() = REF(target) OBJ_NE NULL - - def GET() = fn(REF(target), nme.get) - - // name of nth indexed argument to a method (first parameter list), defaults to 1st - def ARG(idx: Int = 0) = Ident(target.paramss.head(idx)) - def ARGS = target.paramss.head - def ARGNAMES = ARGS map Ident + def IS_NULL() = REF(target) OBJ_EQ NULL + def GET() = fn(REF(target), nme.get) + def ARGS = target.paramss.head } /** Top level accessible. */ @@ -269,32 +243,13 @@ trait TreeDSL { 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.tpe, args: _*) - - def DEF(name: Name, tp: Type): DefTreeStart = DEF(name) withType tp - def DEF(name: Name): DefTreeStart = new DefTreeStart(name) def DEF(sym: Symbol): DefSymStart = new DefSymStart(sym) - - def VAL(name: Name, tp: Type): ValTreeStart = VAL(name) withType tp - def VAL(name: Name): ValTreeStart = new ValTreeStart(name) def VAL(sym: Symbol): ValSymStart = new ValSymStart(sym) - def VAR(name: Name, tp: Type): ValTreeStart = VAL(name, tp) withFlags Flags.MUTABLE - def VAR(name: Name): ValTreeStart = VAL(name) withFlags Flags.MUTABLE - def VAR(sym: Symbol): ValSymStart = VAL(sym) withFlags Flags.MUTABLE - - def LAZYVAL(name: Name, tp: Type): ValTreeStart = VAL(name, tp) withFlags Flags.LAZY - def LAZYVAL(name: Name): ValTreeStart = VAL(name) withFlags Flags.LAZY - def LAZYVAL(sym: Symbol): ValSymStart = VAL(sym) withFlags Flags.LAZY - def AND(guards: Tree*) = if (guards.isEmpty) EmptyTree else guards reduceLeft gen.mkAnd - def OR(guards: Tree*) = - if (guards.isEmpty) EmptyTree - else guards reduceLeft gen.mkOr - def IF(tree: Tree) = new IfStart(tree, EmptyTree) def TRY(tree: Tree) = new TryStart(tree, Nil, EmptyTree) def BLOCK(xs: Tree*) = Block(xs.init.toList, xs.last) @@ -312,11 +267,6 @@ trait TreeDSL { case List(tree) if flattenUnary => tree case _ => Apply(TupleClass(trees.length).companionModule, trees: _*) } - def makeTupleType(trees: List[Tree], flattenUnary: Boolean): Tree = trees match { - case Nil => gen.scalaUnitConstr - case List(tree) if flattenUnary => tree - case _ => AppliedTypeTree(REF(TupleClass(trees.length)), trees) - } /** Implicits - some of these should probably disappear **/ implicit def mkTreeMethods(target: Tree): TreeMethods = new TreeMethods(target) diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index 53d35791b6..1adcf46958 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -8,7 +8,6 @@ package ast import scala.collection.mutable.ListBuffer import symtab.Flags._ -import symtab.SymbolTable import scala.language.postfixOps /** XXX to resolve: TreeGen only assumes global is a SymbolTable, but @@ -22,7 +21,7 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { def mkCheckInit(tree: Tree): Tree = { val tpe = - if (tree.tpe != null || !tree.hasSymbol) tree.tpe + if (tree.tpe != null || !tree.hasSymbolField) tree.tpe else tree.symbol.tpe if (!global.phase.erasedTypes && settings.warnSelectNullable.value && @@ -52,7 +51,10 @@ abstract class TreeGen extends scala.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.tpe, expr)) + def mkSoftRef(expr: Tree): Tree = atPos(expr.pos) { + val constructor = SoftReferenceClass.info.nonPrivateMember(nme.CONSTRUCTOR).suchThat(_.paramss.flatten.size == 1) + NewFromConstructor(constructor, expr) + } // annotate the expression with @unchecked def mkUnchecked(expr: Tree): Tree = atPos(expr.pos) { @@ -60,72 +62,6 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { // are very picky about things and it crashes the compiler with "unexpected new". Annotated(New(scalaDot(UncheckedClass.name), ListOfNil), expr) } - // if it's a Match, mark the selector unchecked; otherwise nothing. - def mkUncheckedMatch(tree: Tree) = tree match { - case Match(selector, cases) => atPos(tree.pos)(Match(mkUnchecked(selector), cases)) - case _ => tree - } - - def mkSynthSwitchSelector(expr: Tree): Tree = atPos(expr.pos) { - // This can't be "Annotated(New(SwitchClass), expr)" because annotations - // are very picky about things and it crashes the compiler with "unexpected new". - Annotated(Ident(nme.synthSwitch), expr) - } - - // TODO: would be so much nicer if we would know during match-translation (i.e., type checking) - // whether we should emit missingCase-style apply (and isDefinedAt), instead of transforming trees post-factum - class MatchMatcher { - def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = unknownTree(orig) - def caseVirtualizedMatch(orig: Tree, _match: Tree, targs: List[Tree], scrut: Tree, matcher: Tree): Tree = unknownTree(orig) - def caseVirtualizedMatchOpt(orig: Tree, prologue: List[Tree], cases: List[Tree], matchEndDef: Tree, wrap: Tree => Tree): Tree = unknownTree(orig) - - def genVirtualizedMatch(prologue: List[Tree], cases: List[Tree], matchEndDef: Tree): Tree = Block(prologue ++ cases, matchEndDef) - - def apply(matchExpr: Tree): Tree = matchExpr match { - // old-style match or virtpatmat switch - case Match(selector, cases) => // println("simple match: "+ (selector, cases) + "for:\n"+ matchExpr ) - caseMatch(matchExpr, selector, cases, identity) - // old-style match or virtpatmat switch - case Block((vd: ValDef) :: Nil, orig@Match(selector, cases)) => // println("block match: "+ (selector, cases, vd) + "for:\n"+ matchExpr ) - caseMatch(matchExpr, selector, cases, m => copyBlock(matchExpr, List(vd), m)) - // virtpatmat - case Apply(Apply(TypeApply(Select(tgt, nme.runOrElse), targs), List(scrut)), List(matcher)) if opt.virtPatmat => // println("virt match: "+ (tgt, targs, scrut, matcher) + "for:\n"+ matchExpr ) - caseVirtualizedMatch(matchExpr, tgt, targs, scrut, matcher) - // optimized version of virtpatmat - case Block(stats, matchEndDef) if opt.virtPatmat && (stats forall treeInfo.hasSynthCaseSymbol) => - // the assumption is once we encounter a case, the remainder of the block will consist of cases - // the prologue may be empty, usually it is the valdef that stores the scrut - val (prologue, cases) = stats span (s => !s.isInstanceOf[LabelDef]) - caseVirtualizedMatchOpt(matchExpr, prologue, cases, matchEndDef, identity) - // optimized version of virtpatmat - case Block(outerStats, orig@Block(stats, matchEndDef)) if opt.virtPatmat && (stats forall treeInfo.hasSynthCaseSymbol) => - val (prologue, cases) = stats span (s => !s.isInstanceOf[LabelDef]) - caseVirtualizedMatchOpt(matchExpr, prologue, cases, matchEndDef, m => copyBlock(matchExpr, outerStats, m)) - case other => - unknownTree(other) - } - - def unknownTree(t: Tree): Tree = throw new MatchError(t) - def copyBlock(orig: Tree, stats: List[Tree], expr: Tree): Block = Block(stats, expr) - - def dropSyntheticCatchAll(cases: List[CaseDef]): List[CaseDef] = - if (!opt.virtPatmat) cases - else cases filter { - case CaseDef(pat, EmptyTree, Throw(Apply(Select(New(exTpt), nme.CONSTRUCTOR), _))) if (treeInfo.isWildcardArg(pat) && (exTpt.tpe.typeSymbol eq MatchErrorClass)) => false - case CaseDef(pat, guard, body) => true - } - } - - def mkCached(cvar: Symbol, expr: Tree): Tree = { - val cvarRef = mkUnattributedRef(cvar) - Block( - List( - If(Apply(Select(cvarRef, nme.eq), List(Literal(Constant(null)))), - Assign(cvarRef, expr), - EmptyTree)), - cvarRef - ) - } // Builds a tree of the form "{ lhs = rhs ; lhs }" def mkAssignAndReturn(lhs: Symbol, rhs: Tree): Tree = { @@ -148,11 +84,6 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { ValDef(mval) } - // def m: T = { if (m$ eq null) m$ = new m$class(...) m$ } - // where (...) are eventual outer accessors - def mkCachedModuleAccessDef(accessor: Symbol, mvar: Symbol) = - DefDef(accessor, mkCached(mvar, newModule(accessor, mvar.tpe))) - def mkModuleAccessDef(accessor: Symbol, msym: Symbol) = DefDef(accessor, Select(This(msym.owner), msym)) @@ -162,10 +93,6 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { else New(tpe, This(accessor.owner.enclClass)) } - // def m: T; - def mkModuleAccessDcl(accessor: Symbol) = - DefDef(accessor setFlag lateDEFERRED, EmptyTree) - def mkRuntimeCall(meth: Name, args: List[Tree]): Tree = mkRuntimeCall(meth, Nil, args) @@ -206,7 +133,7 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { else AppliedTypeTree(Ident(clazz), targs map TypeTree) )) } - def mkSuperSelect = Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR) + def mkSuperInitCall: Select = Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR) def wildcardStar(tree: Tree) = atPos(tree.pos) { Typed(tree, Ident(tpnme.WILDCARD_STAR)) } @@ -262,25 +189,6 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { else mkCast(tree, pt) - def mkZeroContravariantAfterTyper(tp: Type): Tree = { - // contravariant -- for replacing an argument in a method call - // must use subtyping, as otherwise we miss types like `Any with Int` - val tree = - if (NullClass.tpe <:< tp) Literal(Constant(null)) - else if (UnitClass.tpe <:< tp) Literal(Constant()) - else if (BooleanClass.tpe <:< tp) Literal(Constant(false)) - else if (FloatClass.tpe <:< tp) Literal(Constant(0.0f)) - else if (DoubleClass.tpe <:< tp) Literal(Constant(0.0d)) - else if (ByteClass.tpe <:< tp) Literal(Constant(0.toByte)) - else if (ShortClass.tpe <:< tp) Literal(Constant(0.toShort)) - else if (IntClass.tpe <:< tp) Literal(Constant(0)) - else if (LongClass.tpe <:< tp) Literal(Constant(0L)) - else if (CharClass.tpe <:< tp) Literal(Constant(0.toChar)) - else mkCast(Literal(Constant(null)), tp) - - tree - } - /** Translate names in Select/Ident nodes to type names. */ def convertToTypeName(tree: Tree): Option[RefTree] = tree match { diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala index cbbb4c8ba8..f53f99a279 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala @@ -6,10 +6,6 @@ package scala.tools.nsc package ast -import scala.reflect.internal.HasFlags -import scala.reflect.internal.Flags._ -import symtab._ - /** This class ... * * @author Martin Odersky @@ -19,8 +15,6 @@ abstract class TreeInfo extends scala.reflect.internal.TreeInfo { val global: Global import global._ - import definitions.ThrowableClass - /** Is tree legal as a member definition of an interface? */ override def isInterfaceMember(tree: Tree): Boolean = tree match { @@ -42,7 +36,4 @@ abstract class TreeInfo extends scala.reflect.internal.TreeInfo { case ClassDef(_, `name`, _, _) :: Nil => true case _ => super.firstDefinesClassOrObject(trees, name) } - - def isInterface(mods: HasFlags, body: List[Tree]) = - mods.isTrait && (body forall isInterfaceMember) } diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 296d55fec5..e796258967 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -116,7 +116,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => // convert (implicit ... ) to ()(implicit ... ) if its the only parameter section if (vparamss1.isEmpty || !vparamss1.head.isEmpty && vparamss1.head.head.mods.isImplicit) vparamss1 = List() :: vparamss1; - val superRef: Tree = atPos(superPos)(gen.mkSuperSelect) + val superRef: Tree = atPos(superPos)(gen.mkSuperInitCall) val superCall = (superRef /: argss) (Apply.apply) List( atPos(wrappingPos(superPos, lvdefs ::: argss.flatten)) ( @@ -341,7 +341,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => tree case _ => val dupl = tree.duplicate - if (tree.hasSymbol && (!localOnly || (locals contains tree.symbol)) && !(keepLabels && tree.symbol.isLabel)) + if (tree.hasSymbolField && (!localOnly || (locals contains tree.symbol)) && !(keepLabels && tree.symbol.isLabel)) dupl.symbol = NoSymbol dupl.tpe = null dupl diff --git a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala index 553a2088a6..639780149e 100755 --- a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala @@ -10,10 +10,8 @@ import scala.collection.mutable import mutable.{ Buffer, ArrayBuffer, ListBuffer } import scala.util.control.ControlThrowable import scala.tools.nsc.util.CharArrayReader -import scala.reflect.internal.util.SourceFile -import scala.xml.{ Text, TextBuffer } +import scala.xml.TextBuffer import scala.xml.parsing.MarkupParserCommon -import scala.xml.Utility.{ isNameStart, isNameChar, isSpace } import scala.reflect.internal.Chars.{ SU, LF } // XXX/Note: many/most of the functions in here are almost direct cut and pastes @@ -26,12 +24,6 @@ import scala.reflect.internal.Chars.{ SU, LF } // I rewrote most of these, but not as yet the library versions: so if you are // tempted to touch any of these, please be aware of that situation and try not // to let it get any worse. -- paulp - -/** This trait ... - * - * @author Burak Emir - * @version 1.0 - */ trait MarkupParsers { self: Parsers => @@ -51,7 +43,7 @@ trait MarkupParsers { class MarkupParser(parser: SourceFileParser, final val preserveWS: Boolean) extends MarkupParserCommon { - import Tokens.{ EMPTY, LBRACE, RBRACE } + import Tokens.{ LBRACE, RBRACE } type PositionType = Position type InputType = CharArrayReader @@ -89,7 +81,7 @@ trait MarkupParsers { var xEmbeddedBlock = false - private var debugLastStartElement = new mutable.Stack[(Int, String)] + private val debugLastStartElement = new mutable.Stack[(Int, String)] private def debugLastPos = debugLastStartElement.top._1 private def debugLastElem = debugLastStartElement.top._2 @@ -124,7 +116,6 @@ trait MarkupParsers { val start = curOffset val key = xName xEQ - val delim = ch val mid = curOffset val value: Tree = ch match { case '"' | '\'' => @@ -219,9 +210,6 @@ trait MarkupParsers { /** Returns true if it encounters an end tag (without consuming it), * appends trees to ts as side-effect. - * - * @param ts ... - * @return ... */ private def content_LT(ts: ArrayBuffer[Tree]): Boolean = { if (ch == '/') @@ -410,7 +398,7 @@ trait MarkupParsers { * | Name [S] '/' '>' */ def xPattern: Tree = { - var start = curOffset + val start = curOffset val qname = xName debugLastStartElement.push((start, qname)) xSpaceOpt diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 074fcabec8..9bb7e1c3df 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -9,7 +9,8 @@ package scala.tools.nsc package ast.parser -import scala.collection.mutable.{ListBuffer, StringBuilder} +import scala.collection.{ mutable, immutable } +import mutable.{ ListBuffer, StringBuilder } import scala.reflect.internal.{ ModifierFlags => Flags } import scala.reflect.internal.Chars.{ isScalaLetter } import scala.reflect.internal.util.{ SourceFile, OffsetPosition } @@ -94,7 +95,7 @@ trait ParsersCommon extends ScannersCommon { * <ol> * <li> * Places all pattern variables in Bind nodes. In a pattern, for - * identifiers <code>x</code>:<pre> + * identifiers `x`:<pre> * x => x @ _ * x:T => x @ (_ : T)</pre> * </li> @@ -167,7 +168,6 @@ self => object symbXMLBuilder extends SymbolicXMLBuilder(this, preserveWS = true) { // DEBUG choices val global: self.global.type = self.global - def freshName(prefix: String): Name = SourceFileParser.this.freshName(prefix) } def xmlLiteral : Tree = xmlp.xLiteral @@ -299,11 +299,7 @@ self => inScalaPackage = false currentPackage = "" } - private lazy val primitiveNames: Set[Name] = tpnme.ScalaValueNames.toSet - - private def inScalaRootPackage = inScalaPackage && currentPackage == "scala" - private def isScalaArray(name: Name) = inScalaRootPackage && name == tpnme.Array - private def isPrimitiveType(name: Name) = inScalaRootPackage && primitiveNames(name) + private def inScalaRootPackage = inScalaPackage && currentPackage == "scala" def parseStartRule: () => Tree @@ -380,7 +376,6 @@ self => * } * }}} */ - import definitions._ def emptyPkg = atPos(0, 0, 0) { Ident(nme.EMPTY_PACKAGE_NAME) } def emptyInit = DefDef( @@ -389,7 +384,7 @@ self => Nil, ListOfNil, TypeTree(), - Block(List(Apply(gen.mkSuperSelect, Nil)), Literal(Constant(()))) + Block(List(Apply(gen.mkSuperInitCall, Nil)), Literal(Constant(()))) ) // def main @@ -468,7 +463,7 @@ self => /* ------------- ERROR HANDLING ------------------------------------------- */ - var assumedClosingParens = scala.collection.mutable.Map(RPAREN -> 0, RBRACKET -> 0, RBRACE -> 0) + val assumedClosingParens = mutable.Map(RPAREN -> 0, RBRACKET -> 0, RBRACE -> 0) private var inFunReturnType = false @inline private def fromWithinReturnType[T](body: => T): T = { @@ -645,8 +640,6 @@ self => case _ => false } - def isTypeIntro: Boolean = isTypeIntroToken(in.token) - def isStatSeqEnd = in.token == RBRACE || in.token == EOF def isStatSep(token: Int): Boolean = @@ -770,10 +763,6 @@ self => } } - def checkSize(kind: String, size: Int, max: Int) { - if (size > max) syntaxError("too many "+kind+", maximum = "+max, false) - } - def checkAssoc(offset: Int, op: Name, leftAssoc: Boolean) = if (treeInfo.isLeftAssoc(op) != leftAssoc) syntaxError( @@ -923,7 +912,7 @@ self => ) def compoundTypeRest(t: Tree): Tree = { - var ts = new ListBuffer[Tree] += t + val ts = new ListBuffer[Tree] += t while (in.token == WITH) { in.nextToken() ts += annotType() @@ -980,11 +969,8 @@ self => /** Assumed (provisionally) to be TermNames. */ def ident(skipIt: Boolean): Name = - if (isIdent) { - val name = in.name.encode - in.nextToken() - name - } else { + if (isIdent) rawIdent().encode + else { syntaxErrorOrIncomplete(expectedMsg(IDENTIFIER), skipIt) nme.ERROR } @@ -1138,16 +1124,7 @@ self => }) } - private def stringOp(t: Tree, op: TermName) = { - val str = in.strVal - in.nextToken() - if (str.length == 0) t - else atPos(t.pos.startOrPoint) { - Apply(Select(t, op), List(Literal(Constant(str)))) - } - } - - private def interpolatedString(inPattern: Boolean = false): Tree = atPos(in.offset) { + private def interpolatedString(inPattern: Boolean): Tree = atPos(in.offset) { val start = in.offset val interpolator = in.name @@ -1231,15 +1208,6 @@ self => /* ----------- EXPRESSIONS ------------------------------------------------ */ - /** {{{ - * EqualsExpr ::= `=' Expr - * }}} - */ - def equalsExpr(): Tree = { - accept(EQUALS) - expr() - } - def condExpr(): Tree = { if (in.token == LPAREN) { in.nextToken() @@ -1283,7 +1251,7 @@ self => def expr(): Tree = expr(Local) def expr(location: Int): Tree = { - var savedPlaceholderParams = placeholderParams + val savedPlaceholderParams = placeholderParams placeholderParams = List() var res = expr0(location) if (!placeholderParams.isEmpty && !isWildcard(res)) { @@ -1333,7 +1301,6 @@ self => parseTry case WHILE => def parseWhile = { - val start = in.offset atPos(in.skipToken()) { val lname: Name = freshTermName(nme.WHILE_PREFIX) val cond = condExpr() @@ -1345,7 +1312,6 @@ self => parseWhile case DO => def parseDo = { - val start = in.offset atPos(in.skipToken()) { val lname: Name = freshTermName(nme.DO_WHILE_PREFIX) val body = expr() @@ -1809,7 +1775,6 @@ self => * }}} */ def pattern2(): Tree = { - val nameOffset = in.offset val p = pattern3() if (in.token != AT) p @@ -1922,7 +1887,7 @@ self => val start = in.offset in.token match { case IDENTIFIER | BACKQUOTED_IDENT | THIS => - var t = stableId() + val t = stableId() in.token match { case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => t match { @@ -1984,7 +1949,6 @@ self => /** Default entry points into some pattern contexts. */ def pattern(): Tree = noSeq.pattern() - def patterns(): List[Tree] = noSeq.patterns() def seqPatterns(): List[Tree] = seqOK.patterns() def xmlSeqPatterns(): List[Tree] = xmlSeqOK.patterns() // Called from xml parser def argumentPatterns(): List[Tree] = inParens { @@ -2629,7 +2593,6 @@ self => in.nextToken() newLinesOpt() atPos(start, in.offset) { - val nameOffset = in.offset val name = identForType() // @M! a type alias as well as an abstract type may declare type parameters val tparams = typeParamClauseOpt(name, null) @@ -2906,7 +2869,6 @@ self => * }}} */ def packaging(start: Int): Tree = { - val nameOffset = in.offset val pkg = pkgQualId() val stats = inBracesOrNil(topStatSeq()) makePackaging(start, pkg, stats) @@ -3116,7 +3078,6 @@ self => ts ++= topStatSeq() } } else { - val nameOffset = in.offset in.flushDoc val pkg = pkgQualId() diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 4f564c5d0b..af7f48988f 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -10,7 +10,8 @@ import scala.reflect.internal.util._ import scala.reflect.internal.Chars._ import Tokens._ import scala.annotation.switch -import scala.collection.mutable.{ ListBuffer, ArrayBuffer } +import scala.collection.{ mutable, immutable } +import mutable.{ ListBuffer, ArrayBuffer } import scala.xml.Utility.{ isNameStart } /** See Parsers.scala / ParsersCommon for some explanation of ScannersCommon. @@ -26,7 +27,6 @@ trait ScannersCommon { trait ScannerCommon extends CommonTokenData { // things to fill in, in addition to buf, decodeUni which come from CharArrayReader - def warning(off: Int, msg: String): Unit def error (off: Int, msg: String): Unit def incompleteInputError(off: Int, msg: String): Unit def deprecationWarning(off: Int, msg: String): Unit @@ -50,9 +50,6 @@ trait Scanners extends ScannersCommon { /** Offset into source character array */ type Offset = Int - /** An undefined offset */ - val NoOffset: Offset = -1 - trait TokenData extends CommonTokenData { /** the next token */ @@ -88,8 +85,6 @@ trait Scanners extends ScannersCommon { def isAtEnd = charOffset >= buf.length - def flush = { charOffset = offset; nextChar(); this } - def resume(lastCode: Int) = { token = lastCode if (next.token != EMPTY && !reporter.hasErrors) @@ -98,10 +93,6 @@ trait Scanners extends ScannersCommon { nextToken() } - /** the last error offset - */ - var errOffset: Offset = NoOffset - /** A character buffer for literals */ val cbuf = new StringBuilder @@ -283,10 +274,16 @@ trait Scanners extends ScannersCommon { prev copyFrom this val nextLastOffset = charOffset - 1 fetchToken() + def resetOffset() { + offset = prev.offset + lastOffset = prev.lastOffset + } if (token == CLASS) { token = CASECLASS + resetOffset() } else if (token == OBJECT) { token = CASEOBJECT + resetOffset() } else { lastOffset = nextLastOffset next copyFrom this @@ -402,7 +399,7 @@ trait Scanners extends ScannersCommon { * there a realistic situation where one would need it? */ if (isDigit(ch)) { - if (opt.future) syntaxError("Non-zero numbers may not have a leading zero.") + if (settings.future.value) syntaxError("Non-zero numbers may not have a leading zero.") else deprecationWarning("Treating numbers with a leading zero as octal is deprecated.") } base = 8 @@ -607,7 +604,10 @@ trait Scanners extends ScannersCommon { if (ch == '`') { nextChar() finishNamed(BACKQUOTED_IDENT) - if (name.length == 0) syntaxError("empty quoted identifier") + if (name.length == 0) + syntaxError("empty quoted identifier") + else if (name == nme.WILDCARD) + syntaxError("wildcard invalid as backquoted identifier") } else syntaxError("unclosed quoted identifier") } @@ -998,9 +998,9 @@ trait Scanners extends ScannersCommon { val c = lookahead.getc() /** As of scala 2.11, it isn't a number unless c here is a digit, so - * opt.future excludes the rest of the logic. + * settings.future.value excludes the rest of the logic. */ - if (opt.future && !isDigit(c)) + if (settings.future.value && !isDigit(c)) return setStrVal() val isDefinitelyNumber = (c: @switch) match { @@ -1054,7 +1054,6 @@ trait Scanners extends ScannersCommon { def syntaxError(off: Offset, msg: String) { error(off, msg) token = ERROR - errOffset = off } /** generate an error at the current token offset @@ -1067,7 +1066,6 @@ trait Scanners extends ScannersCommon { def incompleteInputError(msg: String) { incompleteInputError(offset, msg) token = EOF - errOffset = offset } override def toString() = token match { @@ -1232,7 +1230,6 @@ trait Scanners extends ScannersCommon { override val decodeUni: Boolean = !settings.nouescape.value // suppress warnings, throw exception on errors - def warning(off: Offset, msg: String): Unit = () def deprecationWarning(off: Offset, msg: String): Unit = () def error (off: Offset, msg: String): Unit = throw new MalformedInput(off, msg) def incompleteInputError(off: Offset, msg: String): Unit = throw new MalformedInput(off, msg) @@ -1243,7 +1240,6 @@ trait Scanners extends ScannersCommon { class UnitScanner(unit: CompilationUnit, patches: List[BracePatch]) extends SourceFileScanner(unit.source) { def this(unit: CompilationUnit) = this(unit, List()) - override def warning(off: Offset, msg: String) = unit.warning(unit.position(off), msg) override def deprecationWarning(off: Offset, msg: String) = unit.deprecationWarning(unit.position(off), msg) override def error (off: Offset, msg: String) = unit.error(unit.position(off), msg) override def incompleteInputError(off: Offset, msg: String) = unit.incompleteInputError(unit.position(off), msg) @@ -1302,7 +1298,7 @@ trait Scanners extends ScannersCommon { } class ParensAnalyzer(unit: CompilationUnit, patches: List[BracePatch]) extends UnitScanner(unit, patches) { - var balance = scala.collection.mutable.Map(RPAREN -> 0, RBRACKET -> 0, RBRACE -> 0) + val balance = mutable.Map(RPAREN -> 0, RBRACKET -> 0, RBRACE -> 0) init() @@ -1424,18 +1420,6 @@ trait Scanners extends ScannersCommon { else bp :: insertPatch(bps, patch) } - def leftColumn(offset: Int) = - if (offset == -1) -1 else column(lineStart(line(offset))) - - def rightColumn(offset: Int, default: Int) = - if (offset == -1) -1 - else { - val rlin = line(offset) - if (lineStart(rlin) == offset) column(offset) - else if (rlin + 1 < lineStart.length) column(lineStart(rlin + 1)) - else default - } - def insertRBrace(): List[BracePatch] = { def insert(bps: List[BracePair]): List[BracePatch] = bps match { case List() => patches @@ -1477,17 +1461,6 @@ trait Scanners extends ScannersCommon { delete(bracePairs) } - def imbalanceMeasure: Int = { - def measureList(bps: List[BracePair]): Int = - (bps map measure).sum - def measure(bp: BracePair): Int = - (if (bp.lindent != bp.rindent) 1 else 0) + measureList(bp.nested) - measureList(bracePairs) - } - - def improves(patches1: List[BracePatch]): Boolean = - imbalanceMeasure > new ParensAnalyzer(unit, patches1).imbalanceMeasure - override def error(offset: Int, msg: String) {} } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala index e8ef670222..4329ccefc7 100755 --- a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala @@ -11,7 +11,6 @@ import scala.xml.{ EntityRef, Text } import scala.xml.XML.{ xmlns } import symtab.Flags.MUTABLE import scala.reflect.internal.util.StringOps.splitWhere -import scala.language.implicitConversions /** This class builds instance of `Tree` that represent XML. * diff --git a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala index c3fd414426..5a7dc4950d 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala @@ -6,15 +6,11 @@ package scala.tools.nsc package ast.parser -import scala.annotation.switch - /** Common code between JavaTokens and Tokens. Not as much (and not as concrete) * as one might like because JavaTokens for no clear reason chose new numbers for * identical token sets. */ abstract class Tokens { - import scala.reflect.internal.Chars._ - /** special tokens */ final val EMPTY = -3 final val UNDEF = -2 @@ -34,14 +30,6 @@ abstract class Tokens { def isIdentifier(code: Int): Boolean def isLiteral(code: Int): Boolean - def isKeyword(code: Int): Boolean - def isSymbol(code: Int): Boolean - - final def isSpace(at: Char) = at == ' ' || at == '\t' - final def isNewLine(at: Char) = at == CR || at == LF || at == FF - final def isBrace(code: Int) = code >= LPAREN && code <= RBRACE - final def isOpenBrace(code: Int) = isBrace(code) && (code % 2 == 0) - final def isCloseBrace(code: Int) = isBrace(code) && (code % 2 == 1) } object Tokens extends Tokens { @@ -52,20 +40,10 @@ object Tokens extends Tokens { def isLiteral(code: Int) = code >= CHARLIT && code <= INTERPOLATIONID - /** identifiers */ final val IDENTIFIER = 10 final val BACKQUOTED_IDENT = 11 - def isIdentifier(code: Int) = - code >= IDENTIFIER && code <= BACKQUOTED_IDENT - - @switch def canBeginExpression(code: Int) = code match { - case IDENTIFIER|BACKQUOTED_IDENT|USCORE => true - case LBRACE|LPAREN|LBRACKET|COMMENT => true - case IF|DO|WHILE|FOR|NEW|TRY|THROW => true - case NULL|THIS|TRUE|FALSE => true - case code => isLiteral(code) - } + def isIdentifier(code: Int) = code >= IDENTIFIER && code <= BACKQUOTED_IDENT // used by ide /** keywords */ final val IF = 20 @@ -113,17 +91,6 @@ object Tokens extends Tokens { final val MACRO = 62 // not yet used in 2.10 final val THEN = 63 // not yet used in 2.10 - def isKeyword(code: Int) = - code >= IF && code <= LAZY - - @switch def isDefinition(code: Int) = code match { - case CLASS|TRAIT|OBJECT => true - case CASECLASS|CASEOBJECT => true - case DEF|VAL|VAR => true - case TYPE => true - case _ => false - } - /** special symbols */ final val COMMA = 70 final val SEMI = 71 @@ -141,9 +108,6 @@ object Tokens extends Tokens { final val AT = 83 final val VIEWBOUND = 84 - def isSymbol(code: Int) = - code >= COMMA && code <= VIEWBOUND - /** parenthesis */ final val LPAREN = 90 final val RPAREN = 91 diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 0ac46a18bc..d6c499d838 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -26,15 +26,11 @@ abstract class TreeBuilder { def o2p(offset: Int): Position def r2p(start: Int, point: Int, end: Int): Position - def rootId(name: Name) = gen.rootId(name) def rootScalaDot(name: Name) = gen.rootScalaDot(name) def scalaDot(name: Name) = gen.scalaDot(name) def scalaAnyRefConstr = scalaDot(tpnme.AnyRef) - def scalaAnyValConstr = scalaDot(tpnme.AnyVal) - def scalaAnyConstr = scalaDot(tpnme.Any) def scalaUnitConstr = scalaDot(tpnme.Unit) def productConstr = scalaDot(tpnme.Product) - def productConstrN(n: Int) = scalaDot(newTypeName("Product" + n)) def serializableConstr = scalaDot(tpnme.Serializable) def convertToTypeName(t: Tree) = gen.convertToTypeName(t) @@ -191,7 +187,7 @@ abstract class TreeBuilder { } else { val x = freshTermName() Block( - List(ValDef(Modifiers(SYNTHETIC), x, TypeTree(), stripParens(left))), + List(ValDef(Modifiers(SYNTHETIC | ARTIFACT), x, TypeTree(), stripParens(left))), Apply(atPos(opPos union right.pos) { Select(stripParens(right), op.encode) }, List(Ident(x)))) } } else { @@ -379,13 +375,6 @@ abstract class TreeBuilder { def makeCombination(pos: Position, meth: TermName, qual: Tree, pat: Tree, body: Tree): Tree = Apply(Select(qual, meth) setPos qual.pos, List(makeClosure(pos, pat, body))) setPos pos - /** Optionally, if pattern is a `Bind`, the bound name, otherwise None. - */ - def patternVar(pat: Tree): Option[Name] = pat match { - case Bind(name, _) => Some(name) - case _ => None - } - /** If `pat` is not yet a `Bind` wrap it in one with a fresh name */ def makeBind(pat: Tree): Tree = pat match { @@ -451,18 +440,6 @@ abstract class TreeBuilder { def makeForYield(enums: List[Enumerator], body: Tree): Tree = makeFor(nme.map, nme.flatMap, enums, body) - /** Create tree for a lifted expression XX-LIFTING - */ - def makeLifted(gs: List[ValFrom], body: Tree): Tree = { - def combine(gs: List[ValFrom]): ValFrom = (gs: @unchecked) match { - case g :: Nil => g - case ValFrom(pos1, pat1, rhs1) :: gs2 => - val ValFrom(pos2, pat2, rhs2) = combine(gs2) - ValFrom(pos1, makeTuple(List(pat1, pat2), false), Apply(Select(rhs1, nme.zip), List(rhs2))) - } - makeForYield(List(combine(gs)), body) - } - /** Create tree for a pattern alternative */ def makeAlternative(ts: List[Tree]): Tree = { def alternatives(t: Tree): List[Tree] = t match { @@ -497,7 +474,7 @@ abstract class TreeBuilder { def makeCatchFromExpr(catchExpr: Tree): CaseDef = { val binder = freshTermName("x") val pat = Bind(binder, Typed(Ident(nme.WILDCARD), Ident(tpnme.Throwable))) - val catchDef = ValDef(NoMods, freshTermName("catchExpr"), TypeTree(), catchExpr) + val catchDef = ValDef(Modifiers(ARTIFACT), freshTermName("catchExpr"), TypeTree(), catchExpr) val catchFn = Ident(catchDef.name) val body = atPos(catchExpr.pos.makeTransparent)(Block( List(catchDef), @@ -568,7 +545,7 @@ abstract class TreeBuilder { val tmp = freshTermName() val firstDef = atPos(matchExpr.pos) { - ValDef(Modifiers(PrivateLocal | SYNTHETIC | (mods.flags & LAZY)), + ValDef(Modifiers(PrivateLocal | SYNTHETIC | ARTIFACT | (mods.flags & LAZY)), tmp, TypeTree(), matchExpr) } var cnt = 0 diff --git a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala index fc5d4372c5..fd4366baf1 100644 --- a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala +++ b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala @@ -8,7 +8,6 @@ package backend import io.AbstractFile import util.{ClassPath,JavaClassPath,MergedClassPath,DeltaClassPath} -import util.ClassPath.{ JavaContext, DefaultJavaContext } import scala.tools.util.PathResolver trait JavaPlatform extends Platform { diff --git a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala index 8cbb5bc980..f6b0701f86 100644 --- a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala +++ b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala @@ -6,7 +6,6 @@ package scala.tools.nsc package backend -import scala.tools.nsc.backend.icode._ import scala.collection.{ mutable, immutable } /** Scala primitive operations are represented as methods in `Any` and @@ -565,7 +564,7 @@ abstract class ScalaPrimitives { import definitions._ val code = getPrimitive(fun) - def elementType = beforeTyper { + def elementType = enteringTyper { val arrayParent = tpe :: tpe.parents collectFirst { case TypeRef(_, ArrayClass, elem :: Nil) => elem } diff --git a/src/compiler/scala/tools/nsc/backend/WorklistAlgorithm.scala b/src/compiler/scala/tools/nsc/backend/WorklistAlgorithm.scala index 798a80ea37..45ca39fee4 100644 --- a/src/compiler/scala/tools/nsc/backend/WorklistAlgorithm.scala +++ b/src/compiler/scala/tools/nsc/backend/WorklistAlgorithm.scala @@ -6,8 +6,7 @@ package scala.tools.nsc package backend -import scala.tools.nsc.ast._ -import scala.collection.{ mutable, immutable } +import scala.collection.mutable /** * Simple implementation of a worklist algorithm. A processing @@ -32,8 +31,6 @@ trait WorklistAlgorithm { * Run the iterative algorithm until the worklist remains empty. * The initializer is run once before the loop starts and should * initialize the worklist. - * - * @param initWorklist ... */ def run(initWorklist: => Unit) = { initWorklist diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala index 068836fe4f..34bdc1ede4 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala @@ -17,7 +17,7 @@ trait BasicBlocks { self: ICodes => import opcodes._ - import global.{ ifDebug, settings, log, nme } + import global.{ settings, log, nme } import nme.isExceptionResultName /** Override Array creation for efficiency (to not go through reflection). */ @@ -122,7 +122,7 @@ trait BasicBlocks { def closed: Boolean = hasFlag(CLOSED) def closed_=(b: Boolean) = if (b) setFlag(CLOSED) else resetFlag(CLOSED) - /** When set, the <code>emit</code> methods will be ignored. */ + /** When set, the `emit` methods will be ignored. */ def ignore: Boolean = hasFlag(IGNORING) def ignore_=(b: Boolean) = if (b) setFlag(IGNORING) else resetFlag(IGNORING) @@ -260,7 +260,7 @@ trait BasicBlocks { } } - /** Replaces <code>oldInstr</code> with <code>is</code>. It does not update + /** Replaces `oldInstr` with `is`. It does not update * the position field in the newly inserted instructions, so it behaves * differently than the one-instruction versions of this function. * @@ -280,17 +280,7 @@ trait BasicBlocks { } } - /** Insert instructions in 'is' immediately after index 'idx'. */ - def insertAfter(idx: Int, is: List[Instruction]) { - assert(closed, "Instructions can be replaced only after the basic block is closed") - - instrs = instrs.patch(idx + 1, is, 0) - code.touched = true - } - /** Removes instructions found at the given positions. - * - * @param positions ... */ def removeInstructionsAt(positions: Int*) { assert(closed, this) @@ -311,8 +301,6 @@ trait BasicBlocks { } /** Replaces all instructions found in the map. - * - * @param map ... */ def subst(map: Map[Instruction, Instruction]): Unit = if (!closed) @@ -339,10 +327,6 @@ trait BasicBlocks { * is closed, which sets the DIRTYSUCCS flag. */ def emit(instr: Instruction, pos: Position) { -/* if (closed) { - print() - Console.println("trying to emit: " + instr) - } */ assert(!closed || ignore, this) if (ignore) { @@ -436,11 +420,6 @@ trait BasicBlocks { ignore = true } - def exitIgnoreMode() { - assert(ignore, "Exit ignore mode when not in ignore mode: " + this) - ignore = false - } - /** Return the last instruction of this basic block. */ def lastInstruction = if (closed) instrs(instrs.length - 1) @@ -497,17 +476,6 @@ trait BasicBlocks { override def hashCode = label * 41 + code.hashCode - // Instead of it, rather use a printer - def print() { print(java.lang.System.out) } - - def print(out: java.io.PrintStream) { - out.println("block #"+label+" :") - foreach(i => out.println(" " + i)) - out.print("Successors: ") - successors.foreach((x: BasicBlock) => out.print(" "+x.label.toString())) - out.println() - } - private def succString = if (successors.isEmpty) "[S: N/A]" else successors.distinct.mkString("[S: ", ", ", "]") private def predString = if (predecessors.isEmpty) "[P: N/A]" else predecessors.distinct.mkString("[P: ", ", ", "]") diff --git a/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala b/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala index 2cebf7ad99..7c2961778f 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala @@ -7,7 +7,7 @@ package scala.tools.nsc package backend package icode -import scala.collection.{ mutable, immutable } +import scala.collection.immutable /** * Exception handlers are pieces of code that `handle` exceptions on @@ -71,10 +71,4 @@ trait ExceptionHandlers { override def toString() = "finalizer_" + label override def dup: Finalizer = new Finalizer(method, label, pos) } - - object NoFinalizer extends Finalizer(null, newTermNameCached("<no finalizer>"), NoPosition) { - override def startBlock: BasicBlock = sys.error("NoFinalizer cannot have a start block."); - override def setStartBlock(b: BasicBlock): Unit = sys.error("NoFinalizer cannot have a start block."); - override def dup = this - } } diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index ea4e8475f9..f07c331fb0 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -13,10 +13,8 @@ import scala.collection.mutable.{ ListBuffer, Buffer } import scala.tools.nsc.symtab._ import scala.annotation.switch import PartialFunction._ -import scala.language.postfixOps -/** This class ... - * +/** * @author Iulian Dragos * @version 1.0 */ @@ -160,8 +158,6 @@ abstract class GenICode extends SubComponent { * and not produce any value. Use genLoad for expressions which leave * a value on top of the stack. * - * @param tree ... - * @param ctx ... * @return a new context. This is necessary for control flow instructions * which may change the current basic block. */ @@ -264,11 +260,6 @@ abstract class GenICode extends SubComponent { } /** Generate primitive array operations. - * - * @param tree ... - * @param ctx ... - * @param code ... - * @return ... */ private def genArrayOp(tree: Tree, ctx: Context, code: Int, expectedType: TypeKind): (Context, TypeKind) = { import scalaPrimitives._ @@ -432,7 +423,7 @@ abstract class GenICode extends SubComponent { private def genPrimitiveOp(tree: Apply, ctx: Context, expectedType: TypeKind): (Context, TypeKind) = { val sym = tree.symbol - val Apply(fun @ Select(receiver, _), args) = tree + val Apply(fun @ Select(receiver, _), _) = tree val code = scalaPrimitives.getPrimitive(sym, receiver.tpe) if (scalaPrimitives.isArithmeticOp(code)) @@ -543,9 +534,8 @@ abstract class GenICode extends SubComponent { // emits CIL_LOAD_ARRAY_ITEM_ADDRESS case Apply(fun, args) => if (isPrimitive(fun.symbol)) { - val sym = tree.symbol - val Apply(fun @ Select(receiver, _), args) = tree + val Select(receiver, _) = fun val code = scalaPrimitives.getPrimitive(sym, receiver.tpe) if (isArrayOp(code)) { @@ -858,7 +848,7 @@ abstract class GenICode extends SubComponent { // we store this boxed value to a local, even if not really needed. // boxing optimization might use it, and dead code elimination will // take care of unnecessary stores - var loc1 = ctx.makeLocal(tree.pos, expr.tpe, "boxed") + val loc1 = ctx.makeLocal(tree.pos, expr.tpe, "boxed") ctx1.bb.emit(STORE_LOCAL(loc1)) ctx1.bb.emit(LOAD_LOCAL(loc1)) } @@ -1104,7 +1094,7 @@ abstract class GenICode extends SubComponent { case Match(selector, cases) => def genLoadMatch = { debuglog("Generating SWITCH statement."); - var ctx1 = genLoad(selector, ctx, INT) // TODO: Java 7 allows strings in switches (so, don't assume INT and don't convert the literals using intValue) + val ctx1 = genLoad(selector, ctx, INT) // TODO: Java 7 allows strings in switches (so, don't assume INT and don't convert the literals using intValue) val afterCtx = ctx1.newBlock var caseCtx: Context = null generatedType = toTypeKind(tree.tpe) @@ -1163,34 +1153,30 @@ abstract class GenICode extends SubComponent { resCtx } - private def adapt(from: TypeKind, to: TypeKind, ctx: Context, pos: Position): Unit = { - if (!(from <:< to) && !(from == NullReference && to == NothingReference)) { - to match { - case UNIT => - ctx.bb.emit(DROP(from), pos) - debuglog("Dropped an " + from); - - case _ => - debugassert(from != UNIT, "Can't convert from UNIT to " + to + " at: " + pos) - assert(!from.isReferenceType && !to.isReferenceType, - "type error: can't convert from " + from + " to " + to +" in unit " + unit.source + " at " + pos) - - ctx.bb.emit(CALL_PRIMITIVE(Conversion(from, to)), pos) - } - } else if (from == NothingReference) { - ctx.bb.emit(THROW(ThrowableClass)) - ctx.bb.enterIgnoreMode - } else if (from == NullReference) { - ctx.bb.emit(DROP(from)) - ctx.bb.emit(CONSTANT(Constant(null))) + private def adapt(from: TypeKind, to: TypeKind, ctx: Context, pos: Position) { + // An awful lot of bugs explode here - let's leave ourselves more clues. + // A typical example is an overloaded type assigned after typer. + log(s"GenICode#adapt($from, $to, $ctx, $pos)") + + val conforms = (from <:< to) || (from == NullReference && to == NothingReference) + def coerce(from: TypeKind, to: TypeKind) = ctx.bb.emit(CALL_PRIMITIVE(Conversion(from, to)), pos) + def checkAssertions() { + def msg = s"Can't convert from $from to $to in unit ${unit.source} at $pos" + debugassert(from != UNIT, msg) + assert(!from.isReferenceType && !to.isReferenceType, msg) } - else if (from == ThrowableReference && !(ThrowableClass.tpe <:< to.toType)) { - log("Inserted check-cast on throwable to " + to + " at " + pos) - ctx.bb.emit(CHECK_CAST(to)) + if (conforms) from match { + case NothingReference => ctx.bb.emit(THROW(ThrowableClass)) ; ctx.bb.enterIgnoreMode + case NullReference => ctx.bb.emit(Seq(DROP(from), CONSTANT(Constant(null)))) + case ThrowableReference if !(ThrowableClass.tpe <:< to.toType) => ctx.bb.emit(CHECK_CAST(to)) // downcast throwables + case _ => + // widen subrange types + if (from.isIntSizedType && to == LONG) + coerce(INT, LONG) } - else (from, to) match { - case (BYTE, LONG) | (SHORT, LONG) | (CHAR, LONG) | (INT, LONG) => ctx.bb.emit(CALL_PRIMITIVE(Conversion(INT, LONG))) - case _ => () + else to match { + case UNIT => ctx.bb.emit(DROP(from), pos) // value discarding + case _ => checkAssertions() ; coerce(from, to) // other primitive coercions } } @@ -1257,8 +1243,11 @@ abstract class GenICode extends SubComponent { val sym = ( if (!tree.symbol.isPackageClass) tree.symbol else tree.symbol.info.member(nme.PACKAGE) match { - case NoSymbol => assert(false, "Cannot use package as value: " + tree) ; NoSymbol - case s => debugwarn("Bug: found package class where package object expected. Converting.") ; s.moduleClass + case NoSymbol => + abort("Cannot use package as value: " + tree) + case s => + devWarning(s"Found ${tree.symbol} where a package object is required. Converting to ${s.moduleClass}") + s.moduleClass } ) debuglog("LOAD_MODULE from %s: %s".format(tree.shortClass, sym)) @@ -1392,10 +1381,6 @@ abstract class GenICode extends SubComponent { // } /** Generate string concatenation. - * - * @param tree ... - * @param ctx ... - * @return ... */ def genStringConcat(tree: Tree, ctx: Context): Context = { liftStringConcat(tree) match { @@ -1709,8 +1694,6 @@ abstract class GenICode extends SubComponent { * If the block consists of a single unconditional jump, prune * it by replacing the instructions in the predecessor to jump * directly to the JUMP target of the block. - * - * @param method ... */ def prune(method: IMethod) = { var changed = false @@ -1906,18 +1889,8 @@ abstract class GenICode extends SubComponent { var handlerCount = 0 - override def toString(): String = { - val buf = new StringBuilder() - buf.append("\tpackage: ").append(packg).append('\n') - buf.append("\tclazz: ").append(clazz).append('\n') - buf.append("\tmethod: ").append(method).append('\n') - buf.append("\tbb: ").append(bb).append('\n') - buf.append("\tlabels: ").append(labels).append('\n') - buf.append("\texception handlers: ").append(handlers).append('\n') - buf.append("\tcleanups: ").append(cleanups).append('\n') - buf.append("\tscope: ").append(scope).append('\n') - buf.toString() - } + override def toString = + s"package $packg { class $clazz { def $method { bb=$bb } } }" def loadException(ctx: Context, exh: ExceptionHandler, pos: Position) = { debuglog("Emitting LOAD_EXCEPTION for class: " + exh.loadExceptionClass) @@ -1976,18 +1949,7 @@ abstract class GenICode extends SubComponent { this } - def removeFinalizer(f: Tree): this.type = { - assert(cleanups.head contains f, - "Illegal nesting of cleanup operations: " + cleanups + " while exiting finalizer " + f); - cleanups = cleanups.tail - this - } - /** Prepare a new context upon entry into a method. - * - * @param m ... - * @param d ... - * @return ... */ def enterMethod(m: IMethod, d: DefDef): Context = { val ctx1 = new Context(this) setMethod(m) @@ -2059,16 +2021,6 @@ abstract class GenICode extends SubComponent { currentExceptionHandlers = currentExceptionHandlers.tail } - /** Remove the given handler from the list of active exception handlers. */ - def removeActiveHandler(exh: ExceptionHandler): Unit = { - assert(handlerCount > 0 && handlers.head == exh, - "Wrong nesting of exception handlers." + this + " for " + exh) - handlerCount -= 1 - handlers = handlers.tail - debuglog("removed handler: " + exh); - - } - /** Clone the current context */ def dup: Context = new Context(this) @@ -2087,14 +2039,14 @@ abstract class GenICode extends SubComponent { * It returns the resulting context, with the same active handlers as * before the call. Use it like: * - * <code> ctx.Try( ctx => { + * ` ctx.Try( ctx => { * ctx.bb.emit(...) // protected block * }, (ThrowableClass, * ctx => { * ctx.bb.emit(...); // exception handler * }), (AnotherExceptionClass, * ctx => {... - * } ))</code> + * } ))` */ def Try(body: Context => Context, handlers: List[(Symbol, TypeKind, Context => Context)], @@ -2130,7 +2082,7 @@ abstract class GenICode extends SubComponent { } else ctx - val finalizerExh = if (finalizer != EmptyTree) Some({ + if (finalizer != EmptyTree) { val exh = outerCtx.newExceptionHandler(NoSymbol, toTypeKind(finalizer.tpe), finalizer.pos) // finalizer covers exception handlers this.addActiveHandler(exh) // .. and body aswell val ctx = finalizerCtx.enterExceptionHandler(exh) @@ -2143,21 +2095,20 @@ abstract class GenICode extends SubComponent { ctx1.bb.enterIgnoreMode; ctx1.bb.close finalizerCtx.endHandler() - exh - }) else None - - val exhs = handlers.map { case (sym, kind, handler) => // def genWildcardHandler(sym: Symbol): (Symbol, TypeKind, Context => Context) = - val exh = this.newExceptionHandler(sym, kind, tree.pos) - var ctx1 = outerCtx.enterExceptionHandler(exh) - ctx1.addFinalizer(finalizer, finalizerCtx) - loadException(ctx1, exh, tree.pos) - ctx1 = handler(ctx1) - // emit finalizer - val ctx2 = emitFinalizer(ctx1) - ctx2.bb.closeWith(JUMP(afterCtx.bb)) - outerCtx.endHandler() - exh - } + } + + for ((sym, kind, handler) <- handlers) { + val exh = this.newExceptionHandler(sym, kind, tree.pos) + var ctx1 = outerCtx.enterExceptionHandler(exh) + ctx1.addFinalizer(finalizer, finalizerCtx) + loadException(ctx1, exh, tree.pos) + ctx1 = handler(ctx1) + // emit finalizer + val ctx2 = emitFinalizer(ctx1) + ctx2.bb.closeWith(JUMP(afterCtx.bb)) + outerCtx.endHandler() + } + val bodyCtx = this.newBlock if (finalizer != EmptyTree) bodyCtx.addFinalizer(finalizer, finalizerCtx) @@ -2356,7 +2307,6 @@ abstract class GenICode extends SubComponent { val locals: ListBuffer[Local] = new ListBuffer def add(l: Local) = locals += l - def remove(l: Local) = locals -= l /** Return all locals that are in scope. */ def varsInScope: Buffer[Local] = outer.varsInScope.clone() ++= locals diff --git a/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala b/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala index f05def3123..95913c7768 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala @@ -9,7 +9,6 @@ package icode import scala.collection.mutable import scala.collection.mutable.ListBuffer -import scala.tools.nsc.symtab._ abstract class ICodeCheckers { val global: Global @@ -49,7 +48,7 @@ abstract class ICodeCheckers { * @author Iulian Dragos * @version 1.0, 06/09/2005 * - * @todo Better checks for <code>MONITOR_ENTER/EXIT</code> + * @todo Better checks for `MONITOR_ENTER/EXIT` * Better checks for local var initializations * * @todo Iulian says: I think there's some outdated logic in the checker. @@ -103,7 +102,6 @@ abstract class ICodeCheckers { private def posStr(p: Position) = if (p.isDefined) p.line.toString else "<??>" - private def indent(s: String, spaces: Int): String = indent(s, " " * spaces) private def indent(s: String, prefix: String): String = { val lines = s split "\\n" lines map (prefix + _) mkString "\n" @@ -170,7 +168,6 @@ abstract class ICodeCheckers { val preds = bl.predecessors def hasNothingType(s: TypeStack) = s.nonEmpty && (s.head == NothingReference) - def hasNullType(s: TypeStack) = s.nonEmpty && (s.head == NullReference) /** XXX workaround #1: one stack empty, the other has BoxedUnit. * One example where this arises is: @@ -296,7 +293,7 @@ abstract class ICodeCheckers { else prefix + " with initial stack " + initial.types.mkString("[", ", ", "]") }) - var stack = new TypeStack(initial) + val stack = new TypeStack(initial) def checkStack(len: Int) { if (stack.length < len) ICodeChecker.this.icodeError("Expected at least " + len + " elements on the stack", stack) @@ -369,11 +366,6 @@ abstract class ICodeCheckers { } } - /** Return true if k1 is a subtype of any of the following types, - * according to the somewhat relaxed subtyping standards in effect here. - */ - def isOneOf(k1: TypeKind, kinds: TypeKind*) = kinds exists (k => isSubtype(k1, k)) - def subtypeTest(k1: TypeKind, k2: TypeKind): Unit = if (isSubtype(k1, k2)) () else typeError(k2, k1) @@ -381,10 +373,9 @@ abstract class ICodeCheckers { for (instr <- b) { this.instruction = instr - def checkLocal(local: Local): Unit = { - method lookupLocal local.sym.name getOrElse { - icodeError(" " + local + " is not defined in method " + method) - } + def checkLocal(local: Local) { + if ((method lookupLocal local.sym.name).isEmpty) + icodeError(s" $local is not defined in method $method") } def checkField(obj: TypeKind, field: Symbol): Unit = obj match { case REFERENCE(sym) => @@ -422,10 +413,7 @@ abstract class ICodeCheckers { } /** Checks that the object passed as receiver has a method - * <code>method</code> and that it is callable from the current method. - * - * @param receiver ... - * @param method ... + * `method` and that it is callable from the current method. */ def checkMethod(receiver: TypeKind, method: Symbol) = receiver match { @@ -495,7 +483,7 @@ abstract class ICodeCheckers { case LOAD_MODULE(module) => checkBool((module.isModule || module.isModuleClass), - "Expected module: " + module + " flags: " + Flags.flagsToString(module.flags)); + "Expected module: " + module + " flags: " + module.flagString); pushStack(toTypeKind(module.tpe)); case STORE_THIS(kind) => diff --git a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala index 93201089e4..e2d387c65d 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala @@ -8,8 +8,6 @@ package backend package icode import java.io.PrintWriter -import scala.collection.mutable -import scala.tools.nsc.symtab._ import analysis.{ Liveness, ReachingDefinitions } import scala.tools.nsc.symtab.classfile.ICodeReader @@ -30,14 +28,14 @@ abstract class ICodes extends AnyRef with Repository { val global: Global - import global.{ log, definitions, settings, perRunCaches } + import global.{ log, definitions, settings, perRunCaches, devWarning } /** The ICode representation of classes */ val classes = perRunCaches.newMap[global.Symbol, IClass]() /** Debugging flag */ def shouldCheckIcode = settings.check contains global.genicode.phaseName - def checkerDebug(msg: String) = if (shouldCheckIcode && global.opt.debug) println(msg) + def checkerDebug(msg: String) = if (shouldCheckIcode && global.settings.debug.value) println(msg) /** The ICode linearizer. */ val linearizer: Linearizer = settings.Xlinearizer.value match { @@ -84,7 +82,7 @@ abstract class ICodes extends AnyRef // Something is leaving open/empty blocks around (see SI-4840) so // let's not kill the deal unless it's nonempty. if (b.isEmpty) { - log("!!! Found open but empty block while inlining " + m + ": removing from block list.") + devWarning(s"Found open but empty block while inlining $m: removing from block list.") m.code removeBlock b } else dumpMethodAndAbort(m, b) diff --git a/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala b/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala index a38eab4515..b8a98955c9 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala @@ -8,7 +8,6 @@ package scala.tools.nsc package backend package icode -import scala.tools.nsc.ast._ import scala.collection.{ mutable, immutable } import mutable.ListBuffer diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala index 7ba212f42e..12daa32186 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala @@ -7,10 +7,8 @@ package scala.tools.nsc package backend package icode -import java.io.PrintWriter import scala.collection.{ mutable, immutable } import scala.reflect.internal.util.{ SourceFile, NoSourceFile } -import symtab.Flags.{ DEFERRED } trait ReferenceEquality { override def hashCode = System.identityHashCode(this) @@ -128,9 +126,7 @@ trait Members { override def toString() = symbol.fullName - def lookupField(s: Symbol) = fields find (_.symbol == s) def lookupMethod(s: Symbol) = methods find (_.symbol == s) - def lookupMethod(s: Name) = methods find (_.symbol.name == s) /* returns this methods static ctor if it has one. */ def lookupStaticCtor: Option[IMethod] = methods find (_.symbol.isStaticConstructor) @@ -161,7 +157,6 @@ trait Members { def linearizedBlocks(lin: Linearizer = self.linearizer): List[BasicBlock] = lin linearize this def foreachBlock[U](f: BasicBlock => U): Unit = blocks foreach f - def foreachInstr[U](f: Instruction => U): Unit = foreachBlock(_.toList foreach f) var native = false @@ -194,7 +189,6 @@ trait Members { } def addLocals(ls: List[Local]) = ls foreach addLocal - def addParams(as: List[Local]) = as foreach addParam def lookupLocal(n: Name): Option[Local] = locals find (_.sym.name == n) def lookupLocal(sym: Symbol): Option[Local] = locals find (_.sym == sym) @@ -209,28 +203,7 @@ trait Members { override def toString() = symbol.fullName - def matchesSignature(other: IMethod) = { - (symbol.name == other.symbol.name) && - (params corresponds other.params)(_.kind == _.kind) && - (returnType == other.returnType) - } - import opcodes._ - def checkLocals(): Unit = { - def localsSet = (code.blocks flatMap { bb => - bb.iterator collect { - case LOAD_LOCAL(l) => l - case STORE_LOCAL(l) => l - } - }).toSet - - if (hasCode) { - log("[checking locals of " + this + "]") - locals filterNot localsSet foreach { l => - log("Local " + l + " is not declared in " + this) - } - } - } /** Merge together blocks that have a single successor which has a * single predecessor. Exception handlers are taken into account (they @@ -296,9 +269,6 @@ trait Members { /** Starting PC for this local's visibility range. */ var start: Int = _ - /** Ending PC for this local's visibility range. */ - var end: Int = _ - /** PC-based ranges for this local variable's visibility */ var ranges: List[(Int, Int)] = Nil diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala index 8c9a72638d..eaa742a1da 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala @@ -3,13 +3,10 @@ * @author Martin Odersky */ - - package scala.tools.nsc package backend package icode -import scala.tools.nsc.ast._ import scala.reflect.internal.util.{Position,NoPosition} /* @@ -67,7 +64,7 @@ import scala.reflect.internal.util.{Position,NoPosition} * in the source files. */ trait Opcodes { self: ICodes => - import global.{Symbol, NoSymbol, Type, Name, Constant}; + import global.{Symbol, NoSymbol, Name, Constant}; // categories of ICode instructions final val localsCat = 1 @@ -111,17 +108,11 @@ trait Opcodes { self: ICodes => // Vlad: I wonder why we keep producedTypes around -- it looks like an useless thing to have def producedTypes: List[TypeKind] = Nil - /** This method returns the difference of size of the stack when the instruction is used */ - def difference = produced-consumed - /** The corresponding position in the source file */ private var _pos: Position = NoPosition def pos: Position = _pos - /** Used by dead code elimination. */ - var useful: Boolean = false - def setPos(p: Position): this.type = { _pos = p this @@ -133,13 +124,6 @@ trait Opcodes { self: ICodes => } object opcodes { - - def mayThrow(i: Instruction): Boolean = i match { - case LOAD_LOCAL(_) | STORE_LOCAL(_) | CONSTANT(_) | THIS(_) | CZJUMP(_, _, _, _) - | DROP(_) | DUP(_) | RETURN(_) | LOAD_EXCEPTION(_) | JUMP(_) | CJUMP(_, _, _, _) => false - case _ => true - } - /** Loads "this" on top of the stack. * Stack: ... * ->: ...:ref @@ -715,8 +699,6 @@ trait Opcodes { self: ICodes => /** Is this a static method call? */ def isStatic: Boolean = false - def isSuper: Boolean = false - /** Is this an instance method call? */ def hasInstance: Boolean = true @@ -750,7 +732,6 @@ trait Opcodes { self: ICodes => * On JVM, translated to `invokespecial`. */ case class SuperCall(mix: Name) extends InvokeStyle { - override def isSuper = true override def toString(): String = { "super(" + mix + ")" } } @@ -815,7 +796,7 @@ trait Opcodes { self: ICodes => case class CIL_NEWOBJ(method: Symbol) extends Instruction { override def toString(): String = "CIL_NEWOBJ " + hostClass.fullName + method.fullName - var hostClass: Symbol = method.owner; + val hostClass: Symbol = method.owner; override def consumed = method.tpe.paramTypes.length override def consumedTypes = method.tpe.paramTypes map toTypeKind override def produced = 1 diff --git a/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala b/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala index c8579041ba..351d99f51a 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala @@ -76,25 +76,12 @@ trait Primitives { self: ICodes => /** Pretty printer for primitives */ class PrimitivePrinter(out: PrintWriter) { - def print(s: String): PrimitivePrinter = { out.print(s) this } def print(o: AnyRef): PrimitivePrinter = print(o.toString()) - - def printPrimitive(prim: Primitive) = prim match { - case Negation(kind) => - print("!") - - case Test(op, kind, zero) => - print(op).print(kind) - - case Comparison(op, kind) => - print(op).print("(").print(kind) - - } } /** This class represents a comparison operation. */ diff --git a/src/compiler/scala/tools/nsc/backend/icode/Printers.scala b/src/compiler/scala/tools/nsc/backend/icode/Printers.scala index 6cac641e3e..61af6e5119 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Printers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Printers.scala @@ -8,13 +8,9 @@ package backend package icode import java.io.PrintWriter -import scala.tools.nsc.symtab.Flags -import scala.reflect.internal.util.Position trait Printers { self: ICodes => import global._ - import global.icodes.opcodes._ - import global.icodes._ class TextPrinter(writer: PrintWriter, lin: Linearizer) { private var margin = 0 diff --git a/src/compiler/scala/tools/nsc/backend/icode/Repository.scala b/src/compiler/scala/tools/nsc/backend/icode/Repository.scala index e73015c4da..e92e61c957 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Repository.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Repository.scala @@ -26,17 +26,6 @@ trait Repository { /** The icode of the given class, if available */ def icode(sym: Symbol): Option[IClass] = (classes get sym) orElse (loaded get sym) - /** The icode of the given class. If not available, it loads - * its bytecode. - */ - def icode(sym: Symbol, force: Boolean): IClass = - icode(sym) getOrElse { - log("loading " + sym) - load(sym) - assert(available(sym)) - loaded(sym) - } - /** Load bytecode for given symbol. */ def load(sym: Symbol): Boolean = { try { diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala index 4f8fda8024..0990cfba6f 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala @@ -55,7 +55,7 @@ trait TypeKinds { self: ICodes => def toType: Type = reversePrimitiveMap get this map (_.tpe) getOrElse { this match { - case REFERENCE(cls) => cls.tpe + case REFERENCE(cls) => cls.tpe_* case ARRAY(elem) => arrayType(elem.toType) case _ => abort("Unknown type kind.") } @@ -66,7 +66,6 @@ trait TypeKinds { self: ICodes => def isValueType = false def isBoxedType = false final def isRefOrArrayType = isReferenceType || isArrayType - final def isRefArrayOrBoxType = isRefOrArrayType || isBoxedType final def isNothingType = this == NothingReference final def isNullType = this == NullReference final def isInterfaceType = this match { @@ -114,8 +113,6 @@ trait TypeKinds { self: ICodes => } } - var lubs0 = 0 - /** * The least upper bound of two typekinds. They have to be either * REFERENCE or ARRAY kinds. @@ -139,8 +136,7 @@ trait TypeKinds { self: ICodes => * Here we make the adjustment by rewinding to a pre-erasure state and * sifting through the parents for a class type. */ - def lub0(tk1: TypeKind, tk2: TypeKind): Type = beforeUncurry { - import definitions._ + def lub0(tk1: TypeKind, tk2: TypeKind): Type = enteringUncurry { val tp = global.lub(List(tk1.toType, tk2.toType)) val (front, rest) = tp.parents span (_.typeSymbol.isTrait) diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala index 23d3d05c64..57d51dad49 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala @@ -15,15 +15,11 @@ package icode trait TypeStacks { self: ICodes => - import opcodes._ - /* This class simulates the type of the operand * stack of the ICode. */ type Rep = List[TypeKind] - object NoTypeStack extends TypeStack(Nil) { } - class TypeStack(var types: Rep) { if (types.nonEmpty) checkerDebug("Created " + this) @@ -71,14 +67,6 @@ trait TypeStacks { def apply(n: Int): TypeKind = types(n) - /** - * A TypeStack agrees with another one if they have the same - * length and each type kind agrees position-wise. Two - * types agree if one is a subtype of the other. - */ - def agreesWith(other: TypeStack): Boolean = - (types corresponds other.types)((t1, t2) => t1 <:< t2 || t2 <:< t1) - /* This method returns a String representation of the stack */ override def toString() = if (types.isEmpty) "[]" diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala index 53111d0ade..7f32b2b764 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala @@ -26,12 +26,8 @@ abstract class CopyPropagation { case object This extends Location /** Values that can be on the stack. */ - abstract class Value { - def isRecord = false - } - case class Record(cls: Symbol, bindings: mutable.Map[Symbol, Value]) extends Value { - override def isRecord = true - } + abstract class Value { } + case class Record(cls: Symbol, bindings: mutable.Map[Symbol, Value]) extends Value { } /** The value of some location in memory. */ case class Deref(l: Location) extends Value @@ -91,16 +87,6 @@ abstract class CopyPropagation { loop(l) getOrElse Deref(LocalVar(l)) } - /* Return the binding for the given field of the given record */ - def getBinding(r: Record, f: Symbol): Value = { - assert(r.bindings contains f, "Record " + r + " does not contain a field " + f) - - r.bindings(f) match { - case Deref(LocalVar(l)) => getBinding(l) - case target => target - } - } - /** Return a local which contains the same value as this field, if any. * If the field holds a reference to a local, the returned value is the * binding of that local. @@ -463,14 +449,9 @@ abstract class CopyPropagation { } } - /** Update the state <code>s</code> after the call to <code>method</code>. + /** Update the state `s` after the call to `method`. * The stack elements are dropped and replaced by the result of the call. * If the method is impure, all bindings to record fields are cleared. - * - * @param state ... - * @param method ... - * @param static ... - * @return ... */ final def simulateCall(state: copyLattice.State, method: Symbol, static: Boolean): copyLattice.State = { val out = new copyLattice.State(state.bindings, state.stack); @@ -554,10 +535,7 @@ abstract class CopyPropagation { bindings } - /** Is symbol <code>m</code> a pure method? - * - * @param m ... - * @return ... + /** Is symbol `m` a pure method? */ final def isPureMethod(m: Symbol): Boolean = m.isGetter // abstract getters are still pure, as we 'know' diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala index 04c3eedbad..cc3a7eb876 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala @@ -34,15 +34,6 @@ trait DataFlowAnalysis[L <: SemiLattice] { f } - /** Reinitialize, but keep the old solutions. Should be used when reanalyzing the - * same method, after some code transformation. - */ - def reinit(f: => Unit): Unit = { - iterations = 0 - worklist.clear; visited.clear; - f - } - def run(): Unit /** Implements forward dataflow analysis: the transfer function is @@ -82,10 +73,6 @@ trait DataFlowAnalysis[L <: SemiLattice] { sys.error("Could not find element " + e.getMessage) } - /** ... - * - * @param f ... - */ def backwardAnalysis(f: (P, lattice.Elem) => lattice.Elem): Unit = while (worklist.nonEmpty) { if (stat) iterations += 1 diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala index 2717c432e8..48755d4424 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala @@ -52,7 +52,7 @@ abstract class ReachingDefinitions { // it makes it harder to spot the real problems. val result = (a.stack, b.stack).zipped map (_ ++ _) if (settings.debug.value && (a.stack.length != b.stack.length)) - debugwarn("Mismatched stacks in ReachingDefinitions#lub2: " + a.stack + ", " + b.stack + ", returning " + result) + devWarning(s"Mismatched stacks in ReachingDefinitions#lub2: ${a.stack}, ${b.stack}, returning $result") result } ) @@ -155,7 +155,7 @@ abstract class ReachingDefinitions { import lattice.IState def updateReachingDefinition(b: BasicBlock, idx: Int, rd: ListSet[Definition]): ListSet[Definition] = { val STORE_LOCAL(local) = b(idx) - var tmp = local + val tmp = local (rd filter { case (l, _, _) => l != tmp }) + ((tmp, b, idx)) } @@ -197,7 +197,7 @@ abstract class ReachingDefinitions { def findDefs(bb: BasicBlock, idx: Int, m: Int, depth: Int): List[(BasicBlock, Int)] = if (idx > 0) { assert(bb.closed, bb) - var instrs = bb.getArray + val instrs = bb.getArray var res: List[(BasicBlock, Int)] = Nil var i = idx var n = m diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala index b2ecb431ee..c9d295a350 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala @@ -68,7 +68,6 @@ abstract class TypeFlowAnalysis { * names to types and a type stack. */ object typeFlowLattice extends SemiLattice { - import icodes._ type Elem = IState[VarBinding, icodes.TypeStack] val top = new Elem(new VarBinding, typeStackLattice.top) @@ -136,7 +135,7 @@ abstract class TypeFlowAnalysis { timer.start // icodes.lubs0 = 0 forwardAnalysis(blockTransfer) - val t = timer.stop + timer.stop if (settings.debug.value) { linearizer.linearize(method).foreach(b => if (b != method.startBlock) assert(visited.contains(b), @@ -269,36 +268,6 @@ abstract class TypeFlowAnalysis { out } // interpret - - class SimulatedStack { - private var types: List[InferredType] = Nil - private var depth = 0 - - /** Remove and return the topmost element on the stack. If the - * stack is empty, return a reference to a negative index on the - * stack, meaning it refers to elements pushed by a predecessor block. - */ - def pop: InferredType = types match { - case head :: rest => - types = rest - head - case _ => - depth -= 1 - TypeOfStackPos(depth) - } - - def pop2: (InferredType, InferredType) = { - (pop, pop) - } - - def push(t: InferredType) { - depth += 1 - types = types ::: List(t) - } - - def push(k: TypeKind) { push(Const(k)) } - } - abstract class InferredType { /** Return the type kind pointed by this inferred type. */ def getKind(in: lattice.Elem): icodes.TypeKind = this match { @@ -326,7 +295,6 @@ abstract class TypeFlowAnalysis { class TransferFunction(consumed: Int, gens: List[Gen]) extends (lattice.Elem => lattice.Elem) { def apply(in: lattice.Elem): lattice.Elem = { val out = lattice.IState(new VarBinding(in.vars), new TypeStack(in.stack)) - val bindings = out.vars val stack = out.stack out.stack.pop(consumed) @@ -389,7 +357,7 @@ abstract class TypeFlowAnalysis { timer.start forwardAnalysis(blockTransfer) - val t = timer.stop + timer.stop /* Now that `forwardAnalysis(blockTransfer)` has finished, all inlining candidates can be found in `remainingCALLs`, whose keys are callsites and whose values are pieces of information about the typestack just before the callsite in question. @@ -546,9 +514,6 @@ abstract class TypeFlowAnalysis { relevantBBs ++= blocks } - /* the argument is also included in the result */ - private def transitivePreds(b: BasicBlock): Set[BasicBlock] = { transitivePreds(List(b)) } - /* those BBs in the argument are also included in the result */ private def transitivePreds(starters: Traversable[BasicBlock]): Set[BasicBlock] = { val result = mutable.Set.empty[BasicBlock] @@ -562,19 +527,6 @@ abstract class TypeFlowAnalysis { result.toSet } - /* those BBs in the argument are also included in the result */ - private def transitiveSuccs(starters: Traversable[BasicBlock]): Set[BasicBlock] = { - val result = mutable.Set.empty[BasicBlock] - var toVisit: List[BasicBlock] = starters.toList.distinct - while(toVisit.nonEmpty) { - val h = toVisit.head - toVisit = toVisit.tail - result += h - for(p <- h.successors; if !result(p) && !toVisit.contains(p)) { toVisit = p :: toVisit } - } - result.toSet - } - /* A basic block B is "on the perimeter" of the current control-flow subgraph if none of its successors belongs to that subgraph. * In that case, for the purposes of inlining, we're interested in the typestack right before the last inline candidate in B, not in those afterwards. * In particular we can do without computing the outflow at B. */ @@ -685,12 +637,6 @@ abstract class TypeFlowAnalysis { if(!worklist.contains(b)) { worklist += b } } - /* this is not a general purpose method to add to the worklist, - * because the assert is expected to hold only when called from MTFAGrowable.reinit() */ - private def enqueue(bs: Traversable[BasicBlock]) { - bs foreach enqueue - } - private def blankOut(blocks: scala.collection.Set[BasicBlock]) { blocks foreach { b => in(b) = typeFlowLattice.bottom @@ -761,10 +707,6 @@ abstract class TypeFlowAnalysis { private var lastStart = 0L - def reset() { - millis = 0L - } - def start() { lastStart = System.currentTimeMillis } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala index fb1f45fa40..8c8950d295 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala @@ -10,8 +10,7 @@ import java.io.{ DataOutputStream, FileOutputStream, OutputStream, File => JFile import scala.tools.nsc.io._ import scala.tools.nsc.util.ScalaClassLoader import scala.tools.util.JavapClass -import java.util.jar.{ JarEntry, JarOutputStream, Attributes } -import Attributes.Name +import java.util.jar.Attributes.Name import scala.language.postfixOps /** For the last mile: turning generated bytecode in memory into @@ -23,7 +22,7 @@ trait BytecodeWriters { import global._ private def outputDirectory(sym: Symbol): AbstractFile = ( - settings.outputDirs.outputDirFor(beforeFlatten(sym.sourceFile)) + settings.outputDirs.outputDirFor(enteringFlatten(sym.sourceFile)) ) private def getFile(base: AbstractFile, /*cls.getName()*/ clsName: String, suffix: String): AbstractFile = { var dir = base @@ -102,7 +101,7 @@ trait BytecodeWriters { super.writeClass(label, jclassName, jclassBytes, sym) val pathName = jclassName - var dumpFile = pathName.split("[./]").foldLeft(baseDir: Path) (_ / _) changeExtension "class" toFile; + val dumpFile = pathName.split("[./]").foldLeft(baseDir: Path) (_ / _) changeExtension "class" toFile; dumpFile.parent.createDirectory() val outstream = new DataOutputStream(new FileOutputStream(dumpFile.path)) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index 6eb05c4402..d2e641cbf9 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -6,12 +6,9 @@ package scala.tools.nsc package backend.jvm -import java.nio.ByteBuffer import scala.collection.{ mutable, immutable } import scala.reflect.internal.pickling.{ PickleFormat, PickleBuffer } import scala.tools.nsc.symtab._ -import scala.tools.nsc.io.AbstractFile - import scala.tools.asm import asm.Label @@ -32,19 +29,15 @@ abstract class GenASM extends SubComponent with BytecodeWriters { /** Create a new phase */ override def newPhase(p: Phase): Phase = new AsmPhase(p) - private def outputDirectory(sym: Symbol): AbstractFile = - settings.outputDirs outputDirFor beforeFlatten(sym.sourceFile) + /** From the reference documentation of the Android SDK: + * The `Parcelable` interface identifies classes whose instances can be written to and restored from a `Parcel`. + * Classes implementing the `Parcelable` interface must also have a static field called `CREATOR`, + * which is an object implementing the `Parcelable.Creator` interface. + */ + private val androidFieldName = newTermName("CREATOR") - private def getFile(base: AbstractFile, clsName: String, suffix: String): AbstractFile = { - var dir = base - val pathParts = clsName.split("[./]").toList - for (part <- pathParts.init) { - dir = dir.subdirectoryNamed(part) - } - dir.fileNamed(pathParts.last + suffix) - } - private def getFile(sym: Symbol, clsName: String, suffix: String): AbstractFile = - getFile(outputDirectory(sym), clsName, suffix) + private lazy val AndroidParcelableInterface = rootMirror.getClassIfDefined("android.os.Parcelable") + private lazy val AndroidCreatorClass = rootMirror.getClassIfDefined("android.os.Parcelable$Creator") /** JVM code generation phase */ @@ -53,7 +46,9 @@ abstract class GenASM extends SubComponent with BytecodeWriters { override def erasedTypes = true def apply(cls: IClass) = sys.error("no implementation") - val BeanInfoAttr = rootMirror.getRequiredClass("scala.beans.BeanInfo") + // Lazy val; can't have eager vals in Phase constructors which may + // cause cycles before Global has finished initialization. + lazy val BeanInfoAttr = rootMirror.getRequiredClass("scala.beans.BeanInfo") def isJavaEntryPoint(icls: IClass) = { val sym = icls.symbol @@ -81,9 +76,8 @@ abstract class GenASM extends SubComponent with BytecodeWriters { // At this point it's a module with a main-looking method, so either succeed or warn that it isn't. hasApproximate && { // Before erasure so we can identify generic mains. - beforeErasure { + enteringErasure { val companion = sym.linkedClassOfClass - val companionMain = companion.tpe.member(nme.main) if (hasJavaMainMethod(companion)) failNoForwarder("companion contains its own main method") @@ -311,7 +305,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { } def isTopLevelModule(sym: Symbol): Boolean = - afterPickler { sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass } + exitingPickler { sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass } def isStaticModule(sym: Symbol): Boolean = { sym.isModuleClass && !sym.isImplClass && !sym.isLifted @@ -461,7 +455,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { /** basic functionality for class file building */ abstract class JBuilder(bytecodeWriter: BytecodeWriter) { - val EMPTY_JTYPE_ARRAY = Array.empty[asm.Type] val EMPTY_STRING_ARRAY = Array.empty[String] val mdesc_arglessvoid = "()V" @@ -529,7 +522,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { /** Specialized array conversion to prevent calling * java.lang.reflect.Array.newInstance via TraversableOnce.toArray */ - def mkArray(xs: Traversable[asm.Type]): Array[asm.Type] = { val a = new Array[asm.Type](xs.size); xs.copyToArray(a); a } def mkArray(xs: Traversable[String]): Array[String] = { val a = new Array[String](xs.size); xs.copyToArray(a); a } // ----------------------------------------------------------------------------------------- @@ -579,7 +571,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { * of inner class all until root class. */ def collectInnerClass(s: Symbol): Unit = { - // TODO: some beforeFlatten { ... } which accounts for + // TODO: some enteringFlatten { ... } which accounts for // being nested in parameterized classes (if we're going to selectively flatten.) val x = innerClassSymbolFor(s) if(x ne NoSymbol) { @@ -594,7 +586,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { collectInnerClass(sym) - var hasInternalName = (sym.isClass || (sym.isModule && !sym.isMethod)) + val hasInternalName = (sym.isClass || (sym.isModule && !sym.isMethod)) val cachedJN = javaNameCache.getOrElseUpdate(sym, { if (hasInternalName) { sym.javaBinaryName } else { sym.javaSimpleName } @@ -604,12 +596,18 @@ abstract class GenASM extends SubComponent with BytecodeWriters { val internalName = cachedJN.toString() val trackedSym = jsymbol(sym) reverseJavaName.get(internalName) match { - case None => + case Some(oldsym) if oldsym.exists && trackedSym.exists => + assert( + // In contrast, neither NothingClass nor NullClass show up bytecode-level. + (oldsym == trackedSym) || (oldsym == RuntimeNothingClass) || (oldsym == RuntimeNullClass) || (oldsym.isModuleClass && (oldsym.sourceModule == trackedSym.sourceModule)), + s"""|Different class symbols have the same bytecode-level internal name: + | name: $internalName + | oldsym: ${oldsym.fullNameString} + | tracked: ${trackedSym.fullNameString} + """.stripMargin + ) + case _ => reverseJavaName.put(internalName, trackedSym) - case Some(oldsym) => - assert((oldsym == trackedSym) || (oldsym == RuntimeNothingClass) || (oldsym == RuntimeNullClass) || - (oldsym.isModuleClass && (oldsym.sourceModule == trackedSym.sourceModule)), // In contrast, neither NothingClass nor NullClass show up bytecode-level. - "how can getCommonSuperclass() do its job if different class symbols get the same bytecode-level internal name: " + internalName) } } @@ -682,7 +680,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { innerSym.rawname + innerSym.moduleSuffix // add inner classes which might not have been referenced yet - afterErasure { + exitingErasure { for (sym <- List(csym, csym.linkedClassOfClass); m <- sym.info.decls.map(innerClassSymbolFor) if m.isClass) innerClassBuffer += m } @@ -873,7 +871,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { if (!needsGenericSignature(sym)) { return null } - val memberTpe = beforeErasure(owner.thisType.memberInfo(sym)) + val memberTpe = enteringErasure(owner.thisType.memberInfo(sym)) val jsOpt: Option[String] = erasure.javaSig(sym, memberTpe) if (jsOpt.isEmpty) { return null } @@ -890,10 +888,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters { // Run the signature parser to catch bogus signatures. val isValidSignature = wrap { // Alternative: scala.tools.reflect.SigParser (frontend to sun.reflect.generics.parser.SignatureParser) - import scala.tools.asm.util.SignatureChecker - if (sym.isMethod) { SignatureChecker checkMethodSignature sig } // requires asm-util.jar - else if (sym.isTerm) { SignatureChecker checkFieldSignature sig } - else { SignatureChecker checkClassSignature sig } + import scala.tools.asm.util.CheckClassAdapter + if (sym.isMethod) { CheckClassAdapter checkMethodSignature sig } // requires asm-util.jar + else if (sym.isTerm) { CheckClassAdapter checkFieldSignature sig } + else { CheckClassAdapter checkClassSignature sig } } if(!isValidSignature) { @@ -907,7 +905,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { } if ((settings.check containsName phaseName)) { - val normalizedTpe = beforeErasure(erasure.prepareSigMap(memberTpe)) + val normalizedTpe = enteringErasure(erasure.prepareSigMap(memberTpe)) val bytecodeTpe = owner.thisType.memberInfo(sym) if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym)(normalizedTpe) =:= bytecodeTpe)) { getCurrentCUnit().warning(sym.pos, @@ -1168,7 +1166,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { debuglog("Dumping mirror class for object: " + moduleClass) val linkedClass = moduleClass.companionClass - val linkedModule = linkedClass.companionSymbol lazy val conflictingNames: Set[Name] = { (linkedClass.info.members collect { case sym if sym.name.isTermName => sym.name }).toSet } @@ -1194,16 +1191,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { trait JAndroidBuilder { self: JPlainBuilder => - /** From the reference documentation of the Android SDK: - * The `Parcelable` interface identifies classes whose instances can be written to and restored from a `Parcel`. - * Classes implementing the `Parcelable` interface must also have a static field called `CREATOR`, - * which is an object implementing the `Parcelable.Creator` interface. - */ - private val androidFieldName = newTermName("CREATOR") - - private lazy val AndroidParcelableInterface = rootMirror.getClassIfDefined("android.os.Parcelable") - private lazy val AndroidCreatorClass = rootMirror.getClassIfDefined("android.os.Parcelable$Creator") - def isAndroidParcelableClass(sym: Symbol) = (AndroidParcelableInterface != NoSymbol) && (sym.parentSymbols contains AndroidParcelableInterface) @@ -1336,7 +1323,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { // Additional interface parents based on annotations and other cues def newParentForAttr(attr: Symbol): Option[Symbol] = attr match { - case SerializableAttr => Some(SerializableClass) case CloneableAttr => Some(CloneableClass) case RemoteAttr => Some(RemoteInterfaceClass) case _ => None @@ -1440,7 +1426,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { if (lmoc != NoSymbol) { // it must be a top level class (name contains no $s) val isCandidateForForwarders = { - afterPickler { !(lmoc.name.toString contains '$') && lmoc.hasModuleFlag && !lmoc.isImplClass && !lmoc.isNestedClass } + exitingPickler { !(lmoc.name.toString contains '$') && lmoc.hasModuleFlag && !lmoc.isImplClass && !lmoc.isNestedClass } } if (isCandidateForForwarders) { log("Adding static forwarders from '%s' to implementations in '%s'".format(c.symbol, lmoc)) @@ -1769,11 +1755,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { import asm.Opcodes; - def aconst(cst: AnyRef) { - if (cst == null) { jmethod.visitInsn(Opcodes.ACONST_NULL) } - else { jmethod.visitLdcInsn(cst) } - } - final def boolconst(b: Boolean) { iconst(if(b) 1 else 0) } def iconst(cst: Int) { @@ -2219,7 +2200,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { def getMerged(): scala.collection.Map[Local, List[Interval]] = { // TODO should but isn't: unbalanced start(s) of scope(s) - val shouldBeEmpty = pending filter { p => val Pair(k, st) = p; st.nonEmpty }; + val shouldBeEmpty = pending filter { p => val Pair(_, st) = p; st.nonEmpty }; val merged = mutable.Map[Local, List[Interval]]() def addToMerged(lv: Local, start: Label, end: Label) { val intv = Interval(start, end) @@ -2282,7 +2263,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { } // quest for deterministic output that Map.toList doesn't provide (so that ant test.stability doesn't complain). val srtd = fltnd.sortBy { kr => - val Triple(name: String, local: Local, intrvl: Interval) = kr + val Triple(name: String, _, intrvl: Interval) = kr Triple(intrvl.start, intrvl.end - intrvl.start, name) // ie sort by (start, length, name) } @@ -2402,6 +2383,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { import asm.Opcodes (instr.category: @scala.annotation.switch) match { + case icodes.localsCat => def genLocalInstr() = (instr: @unchecked) match { case THIS(_) => jmethod.visitVarInsn(Opcodes.ALOAD, 0) @@ -2440,7 +2422,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { case LOAD_MODULE(module) => // assert(module.isModule, "Expected module: " + module) - debuglog("generating LOAD_MODULE for: " + module + " flags: " + Flags.flagsToString(module.flags)); + debuglog("generating LOAD_MODULE for: " + module + " flags: " + module.flagString); if (clasz.symbol == module.moduleClass && jMethodName != nme.readResolve.toString) { jmethod.visitVarInsn(Opcodes.ALOAD, 0) } else { @@ -2495,7 +2477,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { case icodes.objsCat => def genObjsInstr() = (instr: @unchecked) match { - case BOX(kind) => val MethodNameAndType(mname, mdesc) = jBoxTo(kind) jcode.invokestatic(BoxesRunTime, mname, mdesc) @@ -2517,8 +2498,8 @@ abstract class GenASM extends SubComponent with BytecodeWriters { def genFldsInstr() = (instr: @unchecked) match { case lf @ LOAD_FIELD(field, isStatic) => - var owner = javaName(lf.hostClass) - debuglog("LOAD_FIELD with owner: " + owner + " flags: " + Flags.flagsToString(field.owner.flags)) + val owner = javaName(lf.hostClass) + debuglog("LOAD_FIELD with owner: " + owner + " flags: " + field.owner.flagString) val fieldJName = javaName(field) val fieldDescr = descriptor(field) val opc = if (isStatic) Opcodes.GETSTATIC else Opcodes.GETFIELD @@ -2936,15 +2917,8 @@ abstract class GenASM extends SubComponent with BytecodeWriters { ////////////////////// local vars /////////////////////// - // def sizeOf(sym: Symbol): Int = sizeOf(toTypeKind(sym.tpe)) - def sizeOf(k: TypeKind): Int = if(k.isWideType) 2 else 1 - // def indexOf(m: IMethod, sym: Symbol): Int = { - // val Some(local) = m lookupLocal sym - // indexOf(local) - // } - final def indexOf(local: Local): Int = { assert(local.index >= 0, "Invalid index for: " + local + "{" + local.## + "}: ") local.index @@ -3350,8 +3324,8 @@ abstract class GenASM extends SubComponent with BytecodeWriters { var wasReduced = false val entryPoints: List[BasicBlock] = m.startBlock :: (m.exh map (_.startBlock)); - var elided = mutable.Set.empty[BasicBlock] // debug - var newTargets = mutable.Set.empty[BasicBlock] // debug + val elided = mutable.Set.empty[BasicBlock] // debug + val newTargets = mutable.Set.empty[BasicBlock] // debug for (ep <- entryPoints) { var reachable = directSuccStar(ep) // this list may contain blocks belonging to jump-chains that we'll skip over diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 3d29b2590e..e1484d1f97 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -6,7 +6,6 @@ package scala.tools.nsc package backend.jvm -import java.io.{ByteArrayOutputStream, DataOutputStream, OutputStream } import java.nio.ByteBuffer import scala.collection.{ mutable, immutable } import scala.reflect.internal.pickling.{ PickleFormat, PickleBuffer } @@ -16,8 +15,6 @@ import scala.reflect.internal.ClassfileConstants._ import ch.epfl.lamp.fjbg._ import JAccessFlags._ import JObjectType.{ JAVA_LANG_STRING, JAVA_LANG_OBJECT } -import java.util.jar.{ JarEntry, JarOutputStream } -import scala.tools.nsc.io.AbstractFile import scala.language.postfixOps /** This class ... @@ -37,20 +34,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with /** Create a new phase */ override def newPhase(p: Phase): Phase = new JvmPhase(p) - private def outputDirectory(sym: Symbol): AbstractFile = - settings.outputDirs outputDirFor beforeFlatten(sym.sourceFile) - - private def getFile(base: AbstractFile, clsName: String, suffix: String): AbstractFile = { - var dir = base - val pathParts = clsName.split("[./]").toList - for (part <- pathParts.init) { - dir = dir.subdirectoryNamed(part) - } - dir.fileNamed(pathParts.last + suffix) - } - private def getFile(sym: Symbol, clsName: String, suffix: String): AbstractFile = - getFile(outputDirectory(sym), clsName, suffix) - /** JVM code generation phase */ class JvmPhase(prev: Phase) extends ICodePhase(prev) { @@ -85,9 +68,8 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with // succeed or warn that it isn't. hasApproximate && { // Before erasure so we can identify generic mains. - beforeErasure { + enteringErasure { val companion = sym.linkedClassOfClass - val companionMain = companion.tpe.member(nme.main) if (hasJavaMainMethod(companion)) failNoForwarder("companion contains its own main method") @@ -200,15 +182,9 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with val StringBuilderType = new JObjectType(StringBuilderClassName) // TODO use ASMType.getObjectType val toStringType = new JMethodType(JAVA_LANG_STRING, JType.EMPTY_ARRAY) // TODO use ASMType.getMethodType val arrayCloneType = new JMethodType(JAVA_LANG_OBJECT, JType.EMPTY_ARRAY) - val MethodTypeType = new JObjectType("java.dyn.MethodType") - val JavaLangClassType = new JObjectType("java.lang.Class") - val MethodHandleType = new JObjectType("java.dyn.MethodHandle") // Scala attributes val BeanInfoAttr = rootMirror.getRequiredClass("scala.beans.BeanInfo") - val BeanInfoSkipAttr = rootMirror.getRequiredClass("scala.beans.BeanInfoSkip") - val BeanDisplayNameAttr = rootMirror.getRequiredClass("scala.beans.BeanDisplayName") - val BeanDescriptionAttr = rootMirror.getRequiredClass("scala.beans.BeanDescription") final val ExcludedForwarderFlags = { import Flags._ @@ -218,7 +194,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with // Additional interface parents based on annotations and other cues def newParentForAttr(attr: Symbol): Option[Symbol] = attr match { - case SerializableAttr => Some(SerializableClass) case CloneableAttr => Some(JavaCloneableClass) case RemoteAttr => Some(RemoteInterfaceClass) case _ => None @@ -273,7 +248,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with var method: IMethod = _ var jclass: JClass = _ var jmethod: JMethod = _ - // var jcode: JExtendedCode = _ def isParcelableClass = isAndroidParcelableClass(clasz.symbol) def isRemoteClass = clasz.symbol hasAnnotation RemoteAttr @@ -282,9 +256,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with } val fjbgContext = new FJBGContext(49, 0) - - val emitSource = debugLevel >= 1 - val emitLines = debugLevel >= 2 val emitVars = debugLevel >= 3 // bug had phase with wrong name; leaving enabled for brief pseudo deprecation @@ -318,7 +289,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with * of inner class all until root class. */ def collectInnerClass(s: Symbol): Unit = { - // TODO: some beforeFlatten { ... } which accounts for + // TODO: some enteringFlatten { ... } which accounts for // being nested in parameterized classes (if we're going to selectively flatten.) val x = innerClassSymbolFor(s) if(x ne NoSymbol) { @@ -448,7 +419,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with // it must be a top level class (name contains no $s) def isCandidateForForwarders(sym: Symbol): Boolean = - afterPickler { + exitingPickler { !(sym.name.toString contains '$') && sym.hasModuleFlag && !sym.isImplClass && !sym.isNestedClass } @@ -529,9 +500,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with * @author Ross Judson (ross.judson@soletta.com) */ def genBeanInfoClass(c: IClass) { - val description = c.symbol getAnnotation BeanDescriptionAttr - // informProgress(description.toString) - val beanInfoClass = fjbgContext.JClass(javaFlags(c.symbol), javaName(c.symbol) + "BeanInfo", "scala/beans/ScalaBeanInfo", @@ -736,13 +704,13 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with ) def addGenericSignature(jmember: JMember, sym: Symbol, owner: Symbol) { if (needsGenericSignature(sym)) { - val memberTpe = beforeErasure(owner.thisType.memberInfo(sym)) + val memberTpe = enteringErasure(owner.thisType.memberInfo(sym)) erasure.javaSig(sym, memberTpe) foreach { sig => // This seems useful enough in the general case. log(sig) if (checkSignatures) { - val normalizedTpe = beforeErasure(erasure.prepareSigMap(memberTpe)) + val normalizedTpe = enteringErasure(erasure.prepareSigMap(memberTpe)) val bytecodeTpe = owner.thisType.memberInfo(sym) if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym)(normalizedTpe) =:= bytecodeTpe)) { clasz.cunit.warning(sym.pos, @@ -757,8 +725,8 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with } } val index = jmember.getConstantPool.addUtf8(sig).toShort - if (opt.verboseDebug) - beforeErasure(println("add generic sig "+sym+":"+sym.info+" ==> "+sig+" @ "+index)) + if (settings.verbose.value && settings.debug.value) + enteringErasure(println("add generic sig "+sym+":"+sym.info+" ==> "+sig+" @ "+index)) val buf = ByteBuffer.allocate(2) buf putShort index @@ -834,7 +802,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with innerSym.rawname + innerSym.moduleSuffix // add inner classes which might not have been referenced yet - afterErasure { + exitingErasure { for (sym <- List(clasz.symbol, clasz.symbol.linkedClassOfClass); m <- sym.info.decls.map(innerClassSymbolFor) if m.isClass) innerClassBuffer += m } @@ -1078,7 +1046,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with var i = 0 var index = 0 - var argTypes = mirrorMethod.getArgumentTypes() + val argTypes = mirrorMethod.getArgumentTypes() while (i < argTypes.length) { mirrorCode.emitLOAD(index, argTypes(i)) index += argTypes(i).getSize() @@ -1110,7 +1078,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with val className = jclass.getName val linkedClass = moduleClass.companionClass - val linkedModule = linkedClass.companionSymbol lazy val conflictingNames: Set[Name] = { linkedClass.info.members collect { case sym if sym.name.isTermName => sym.name } toSet } @@ -1176,9 +1143,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with var linearization: List[BasicBlock] = Nil var isModuleInitialized = false - /** - * @param m ... - */ def genCode(m: IMethod) { val jcode = jmethod.getCode.asInstanceOf[JExtendedCode] @@ -1354,9 +1318,9 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with case LOAD_LOCAL(local) => jcode.emitLOAD(indexOf(local), javaType(local.kind)) case lf @ LOAD_FIELD(field, isStatic) => - var owner = javaName(lf.hostClass) + val owner = javaName(lf.hostClass) debuglog("LOAD_FIELD with owner: " + owner + - " flags: " + Flags.flagsToString(field.owner.flags)) + " flags: " + field.owner.flagString) val fieldJName = javaName(field) val fieldJType = javaType(field) if (isStatic) jcode.emitGETSTATIC(owner, fieldJName, fieldJType) @@ -1364,7 +1328,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with case LOAD_MODULE(module) => // assert(module.isModule, "Expected module: " + module) - debuglog("generating LOAD_MODULE for: " + module + " flags: " + Flags.flagsToString(module.flags)); + debuglog("generating LOAD_MODULE for: " + module + " flags: " + module.flagString); if (clasz.symbol == module.moduleClass && jmethod.getName() != nme.readResolve.toString) jcode.emitALOAD_0() else @@ -1628,11 +1592,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with } } - - /** - * @param primitive ... - * @param pos ... - */ def genPrimitive(primitive: Primitive, pos: Position) { primitive match { case Negation(kind) => @@ -1812,7 +1771,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with * Synthetic locals are skipped. All variables are method-scoped. */ private def genLocalVariableTable(m: IMethod, jcode: JCode) { - val vars = m.locals filterNot (_.sym.isSynthetic) + val vars = m.locals filterNot (_.sym.isArtifact) if (vars.isEmpty) return val pool = jclass.getConstantPool @@ -1866,15 +1825,8 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with ////////////////////// local vars /////////////////////// - def sizeOf(sym: Symbol): Int = sizeOf(toTypeKind(sym.tpe)) - def sizeOf(k: TypeKind): Int = if(k.isWideType) 2 else 1 - def indexOf(m: IMethod, sym: Symbol): Int = { - val Some(local) = m lookupLocal sym - indexOf(local) - } - def indexOf(local: Local): Int = { assert(local.index >= 0, "Invalid index for: " + local + "{" + local.## + "}: ") local.index @@ -1989,7 +1941,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with ) def isTopLevelModule(sym: Symbol): Boolean = - afterPickler { sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass } + exitingPickler { sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass } def isStaticModule(sym: Symbol): Boolean = { sym.isModuleClass && !sym.isImplClass && !sym.isLifted diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala index e002a614bd..613f8f893e 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala @@ -14,7 +14,6 @@ trait GenJVMUtil { import global._ import icodes._ - import icodes.opcodes._ import definitions._ /** Map from type kinds to the Java reference types. It is used for diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala index aaffaa84d8..2fb6550239 100644 --- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala +++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala @@ -8,7 +8,6 @@ package scala.tools.nsc package backend.msil import java.io.{File, IOException} -import java.nio.{ByteBuffer, ByteOrder} import scala.collection.{ mutable, immutable } import scala.tools.nsc.symtab._ @@ -24,8 +23,6 @@ abstract class GenMSIL extends SubComponent { import icodes._ import icodes.opcodes._ - val x = loaders - /** Create a new phase */ override def newPhase(p: Phase) = new MsilPhase(p) @@ -45,8 +42,8 @@ abstract class GenMSIL extends SubComponent { //classes is ICodes.classes, a HashMap[Symbol, IClass] classes.values foreach codeGenerator.findEntryPoint - if( opt.showClass.isDefined && (codeGenerator.entryPoint == null) ) { // TODO introduce dedicated setting instead - val entryclass = opt.showClass.get.toString + if( settings.Xshowcls.isSetByUser && (codeGenerator.entryPoint == null) ) { // TODO introduce dedicated setting instead + val entryclass = settings.Xshowcls.value.toString warning("Couldn't find entry class " + entryclass) } @@ -84,9 +81,6 @@ abstract class GenMSIL extends SubComponent { SYMTAB_DEFAULT_CONSTR => SYMTAB_ATTRIBUTE_EMPTY_CONSTRUCTOR} val EXCEPTION = clrTypes.getType("System.Exception") - val MBYTE_ARRAY = clrTypes.mkArrayType(MBYTE) - - val ICLONEABLE = clrTypes.getType("System.ICloneable") val MEMBERWISE_CLONE = MOBJECT.GetMethod("MemberwiseClone", MsilType.EmptyTypes) val MMONITOR = clrTypes.getType("System.Threading.Monitor") @@ -103,9 +97,6 @@ abstract class GenMSIL extends SubComponent { val INT_PTR = clrTypes.getType("System.IntPtr") - val JOBJECT = definitions.ObjectClass - val JSTRING = definitions.StringClass - val SystemConvert = clrTypes.getType("System.Convert") val objParam = Array(MOBJECT) @@ -124,7 +115,6 @@ abstract class GenMSIL extends SubComponent { // Scala attributes // symtab.Definitions -> object (singleton..) - val SerializableAttr = definitions.SerializableAttr.tpe val CloneableAttr = definitions.CloneableAttr.tpe val TransientAtt = definitions.TransientAttr.tpe // remoting: the architectures are too different, no mapping (no portable code @@ -259,9 +249,9 @@ abstract class GenMSIL extends SubComponent { * and thus shouldn't be added by this method. */ def addAttributes(member: ICustomAttributeSetter, annotations: List[AnnotationInfo]) { - val attributes = annotations.map(_.atp.typeSymbol).collect { - case definitions.TransientAttr => null // TODO this is just an example - } + // val attributes = annotations.map(_.atp.typeSymbol).collect { + // case definitions.TransientAttr => null // TODO this is just an example + // } return // TODO: implement at some point } @@ -313,7 +303,7 @@ abstract class GenMSIL extends SubComponent { /* def getAttributeArgs(consts: List[Constant], nvPairs: List[(Name, Constant)]): Array[Byte] = { val buf = ByteBuffer.allocate(2048) // FIXME: this may be not enough! - buf.order(ByteOrder.LITTLE_ENDIAN) + buf.order(java.nio.ByteOrder.LITTLE_ENDIAN) buf.putShort(1.toShort) // signature def emitSerString(str: String) = { @@ -466,7 +456,7 @@ abstract class GenMSIL extends SubComponent { private[GenMSIL] def genClass(iclass: IClass) { val sym = iclass.symbol - debuglog("Generating class " + sym + " flags: " + Flags.flagsToString(sym.flags)) + debuglog("Generating class " + sym + " flags: " + sym.flagString) clasz = iclass val tBuilder = getType(sym).asInstanceOf[TypeBuilder] @@ -511,7 +501,7 @@ abstract class GenMSIL extends SubComponent { private def genMethod(m: IMethod) { - debuglog("Generating method " + m.symbol + " flags: " + Flags.flagsToString(m.symbol.flags) + + debuglog("Generating method " + m.symbol + " flags: " + m.symbol.flagString + " owner: " + m.symbol.owner) method = m localBuilders.clear @@ -526,8 +516,8 @@ abstract class GenMSIL extends SubComponent { mcode = mBuilder.GetILGenerator() } catch { case e: Exception => - java.lang.System.out.println("m.symbol = " + Flags.flagsToString(m.symbol.flags) + " " + m.symbol) - java.lang.System.out.println("m.symbol.owner = " + Flags.flagsToString(m.symbol.owner.flags) + " " + m.symbol.owner) + java.lang.System.out.println("m.symbol = " + m.symbol.flagString + " " + m.symbol) + java.lang.System.out.println("m.symbol.owner = " + m.symbol.owner.flagString + " " + m.symbol.owner) java.lang.System.out.println("mBuilder = " + mBuilder) java.lang.System.out.println("mBuilder.DeclaringType = " + TypeAttributes.toString(mBuilder.DeclaringType.Attributes) + @@ -624,7 +614,7 @@ abstract class GenMSIL extends SubComponent { * - emit `Leave handlerReturnLabel` instead of the Return * - emit code at the end: load the local and return its value */ - var currentHandlers = new mutable.Stack[ExceptionHandler] + val currentHandlers = new mutable.Stack[ExceptionHandler] // The IMethod the Local/Label/Kind below belong to var handlerReturnMethod: IMethod = _ // Stores the result when returning inside an exception block @@ -823,8 +813,8 @@ abstract class GenMSIL extends SubComponent { def loadFieldOrAddress(field: Symbol, isStatic: Boolean, msg: String, loadAddr : Boolean) { debuglog(msg + " with owner: " + field.owner + - " flags: " + Flags.flagsToString(field.owner.flags)) - var fieldInfo = fields.get(field) match { + " flags: " + field.owner.flagString) + val fieldInfo = fields.get(field) match { case Some(fInfo) => fInfo case None => val fInfo = getType(field.owner).GetField(msilName(field)) @@ -1126,7 +1116,7 @@ abstract class GenMSIL extends SubComponent { } // method: implicit view(FunctionX[PType0, PType1, ...,PTypeN, ResType]):DelegateType - val (isDelegateView, paramType, resType) = beforeTyper { + val (isDelegateView, paramType, resType) = enteringTyper { msym.tpe match { case MethodType(params, resultType) if (params.length == 1 && msym.name == nme.view_) => @@ -1255,7 +1245,7 @@ abstract class GenMSIL extends SubComponent { mcode.Emit(OpCodes.Stloc, switchLocal) var i = 0 for (l <- tags) { - var targetLabel = labels(branches(i)) + val targetLabel = labels(branches(i)) for (i <- l) { mcode.Emit(OpCodes.Ldloc, switchLocal) loadI4(i, mcode) @@ -1633,18 +1623,6 @@ abstract class GenMSIL extends SubComponent { mf = mf | (if (sym hasFlag Flags.ABSTRACT) TypeAttributes.Abstract else 0) mf = mf | (if (sym.isTrait && !sym.isImplClass) TypeAttributes.Interface else TypeAttributes.Class) mf = mf | (if (sym isFinal) TypeAttributes.Sealed else 0) - - sym.annotations foreach { a => a match { - case AnnotationInfo(SerializableAttr, _, _) => - // TODO: add the Serializable TypeAttribute also if the annotation - // System.SerializableAttribute is present (.net annotation, not scala) - // Best way to do it: compare with - // definitions.getClass("System.SerializableAttribute").tpe - // when frontend available - mf = mf | TypeAttributes.Serializable - case _ => () - }} - mf // static: not possible (or?) } @@ -1731,8 +1709,8 @@ abstract class GenMSIL extends SubComponent { false } - if((entryPoint == null) && opt.showClass.isDefined) { // TODO introduce dedicated setting instead - val entryclass = opt.showClass.get.toString + if((entryPoint == null) && settings.Xshowcls.isSetByUser) { // TODO introduce dedicated setting instead + val entryclass = settings.Xshowcls.value.toString val cfn = cls.symbol.fullName if(cfn == entryclass) { for (m <- cls.methods; if isEntryPoint(m.symbol)) { entryPoint = m.symbol } @@ -1884,7 +1862,7 @@ abstract class GenMSIL extends SubComponent { val sym = ifield.symbol debuglog("Adding field: " + sym.fullName) - var attributes = msilFieldFlags(sym) + val attributes = msilFieldFlags(sym) val fieldTypeWithCustomMods = new PECustomMod(msilType(sym.tpe), customModifiers(sym.annotations)) @@ -1913,12 +1891,12 @@ abstract class GenMSIL extends SubComponent { if (iclass.symbol != definitions.ArrayClass) { for (m: IMethod <- iclass.methods) { val sym = m.symbol - debuglog("Creating MethodBuilder for " + Flags.flagsToString(sym.flags) + " " + + debuglog("Creating MethodBuilder for " + sym.flagString + " " + sym.owner.fullName + "::" + sym.name) val ownerType = getType(sym.enclClass).asInstanceOf[TypeBuilder] assert(mtype == ownerType, "mtype = " + mtype + "; ownerType = " + ownerType) - var paramTypes = msilParamTypes(sym) + val paramTypes = msilParamTypes(sym) val attr = msilMethodFlags(sym) if (m.symbol.isClassConstructor) { @@ -1930,7 +1908,7 @@ abstract class GenMSIL extends SubComponent { mapConstructor(sym, constr) addAttributes(constr, sym.annotations) } else { - var resType = msilType(m.returnType) + val resType = msilType(m.returnType) val method = ownerType.DefineMethod(msilName(sym), attr, resType, paramTypes) for (i <- 0.until(paramTypes.length)) { @@ -1955,7 +1933,7 @@ abstract class GenMSIL extends SubComponent { } // createClassMembers0 private def isTopLevelModule(sym: Symbol): Boolean = - beforeRefchecks { + enteringRefchecks { sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass } @@ -2050,7 +2028,6 @@ abstract class GenMSIL extends SubComponent { } private def generateMirrorClass(sym: Symbol) { - val tBuilder = getType(sym) assert(sym.isModuleClass, "Can't generate Mirror-Class for the Non-Module class " + sym) debuglog("Dumping mirror class for object: " + sym) val moduleName = msilName(sym) @@ -2257,100 +2234,9 @@ abstract class GenMSIL extends SubComponent { methods(sym) = mInfo } - /* - * add mapping between sym and method with newName, paramTypes of newClass - */ - private def mapMethod(sym: Symbol, newClass: MsilType, newName: String, paramTypes: Array[MsilType]) { - val methodInfo = newClass.GetMethod(newName, paramTypes) - assert(methodInfo != null, "Can't find mapping for " + sym + " -> " + - newName + "(" + paramTypes + ")") - mapMethod(sym, methodInfo) - if (methodInfo.IsStatic) - dynToStatMapped += sym - } - - /* - * add mapping between method with name and paramTypes of clazz to - * method with newName and newParamTypes of newClass (used for instance - * for "wait") - */ - private def mapMethod( - clazz: Symbol, name: Name, paramTypes: Array[Type], - newClass: MsilType, newName: String, newParamTypes: Array[MsilType]) { - val methodSym = lookupMethod(clazz, name, paramTypes) - assert(methodSym != null, "cannot find method " + name + "(" + - paramTypes + ")" + " in class " + clazz) - mapMethod(methodSym, newClass, newName, newParamTypes) - } - - /* - * add mapping for member with name and paramTypes to member - * newName of newClass (same parameters) - */ - private def mapMethod( - clazz: Symbol, name: Name, paramTypes: Array[Type], - newClass: MsilType, newName: String) { - mapMethod(clazz, name, paramTypes, newClass, newName, paramTypes map msilType) - } - - /* - * add mapping for all methods with name of clazz to the corresponding - * method (same parameters) with newName of newClass - */ - private def mapMethod( - clazz: Symbol, name: Name, - newClass: MsilType, newName: String) { - val memberSym: Symbol = clazz.tpe.member(name) - memberSym.tpe match { - // alternatives: List[Symbol] - case OverloadedType(_, alternatives) => - alternatives.foreach(s => mapMethod(s, newClass, newName, msilParamTypes(s))) - - // paramTypes: List[Type], resType: Type - case MethodType(params, resType) => - mapMethod(memberSym, newClass, newName, msilParamTypes(memberSym)) - - case _ => - abort("member not found: " + clazz + ", " + name) - } - } - - - /* - * find the method in clazz with name and paramTypes - */ - private def lookupMethod(clazz: Symbol, name: Name, paramTypes: Array[Type]): Symbol = { - val memberSym = clazz.tpe.member(name) - memberSym.tpe match { - case OverloadedType(_, alternatives) => - alternatives.find(s => { - var i: Int = 0 - var typesOK: Boolean = true - if (paramTypes.length == s.tpe.paramTypes.length) { - while(i < paramTypes.length) { - if (paramTypes(i) != s.tpe.paramTypes(i)) - typesOK = false - i += 1 - } - } else { - typesOK = false - } - typesOK - }) match { - case Some(sym) => sym - case None => abort("member of " + clazz + ", " + name + "(" + - paramTypes + ") not found") - } - - case MethodType(_, _) => memberSym - - case _ => abort("member not found: " + name + " of " + clazz) - } - } - private def showsym(sym: Symbol): String = (sym.toString + - "\n symbol = " + Flags.flagsToString(sym.flags) + " " + sym + - "\n owner = " + Flags.flagsToString(sym.owner.flags) + " " + sym.owner + "\n symbol = " + sym.flagString + " " + sym + + "\n owner = " + sym.owner.flagString + " " + sym.owner ) } // class BytecodeGenerator diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala index bb14c3dce0..650775b259 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala @@ -7,7 +7,6 @@ package scala.tools.nsc package backend.opt import scala.tools.nsc.backend.icode.analysis.LubException -import scala.tools.nsc.symtab._ /** * @author Iulian Dragos @@ -120,7 +119,7 @@ abstract class ClosureElimination extends SubComponent { case LOAD_FIELD(f, false) /* if accessible(f, m.symbol) */ => def replaceFieldAccess(r: Record) { - val Record(cls, bindings) = r + val Record(cls, _) = r info.getFieldNonRecordValue(r, f) foreach { v => bb.replaceInstruction(i, DROP(REFERENCE(cls)) :: valueToInstruction(v) :: Nil) debuglog(s"replaced $i with $v") @@ -188,25 +187,17 @@ abstract class ClosureElimination extends SubComponent { case Boxed(LocalVar(v)) => LOAD_LOCAL(v) } - - /** is field 'f' accessible from method 'm'? */ - def accessible(f: Symbol, m: Symbol): Boolean = - f.isPublic || (f.isProtected && (f.enclosingPackageClass == m.enclosingPackageClass)) } /* class ClosureElim */ /** Peephole optimization. */ abstract class PeepholeOpt { - - private var method: IMethod = NoIMethod - /** Concrete implementations will perform their optimizations here */ def peep(bb: BasicBlock, i1: Instruction, i2: Instruction): Option[List[Instruction]] var liveness: global.icodes.liveness.LivenessAnalysis = null def apply(m: IMethod): Unit = if (m.hasCode) { - method = m liveness = new global.icodes.liveness.LivenessAnalysis liveness.init(m) liveness.run diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala index fee683ce3a..f7e743a6f1 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala @@ -8,7 +8,6 @@ package scala.tools.nsc package backend.opt import scala.collection.{ mutable, immutable } -import symtab._ /** */ @@ -280,13 +279,6 @@ abstract class DeadCodeElimination extends SubComponent { compensations } - private def withClosed[a](bb: BasicBlock)(f: => a): a = { - if (bb.nonEmpty) bb.close - val res = f - if (bb.nonEmpty) bb.open - res - } - private def findInstruction(bb: BasicBlock, i: Instruction): (BasicBlock, Int) = { for (b <- linearizer.linearizeAt(method, bb)) { val idx = b.toList indexWhere (_ eq i) diff --git a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala index ab238af239..c534c2230c 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala @@ -4,7 +4,6 @@ package scala.tools.nsc package backend.opt -import scala.util.control.Breaks._ /** * This optimization phase inlines the exception handlers so that further phases can optimize the code better diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index 521b6cc132..ca1cfc8929 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -50,6 +50,7 @@ abstract class Inliners extends SubComponent { val phaseName = "inliner" /** Debug - for timing the inliner. */ + /**** private def timed[T](s: String, body: => T): T = { val t1 = System.currentTimeMillis() val res = body @@ -60,6 +61,7 @@ abstract class Inliners extends SubComponent { res } + ****/ /** Look up implementation of method 'sym in 'clazz'. */ @@ -193,7 +195,7 @@ abstract class Inliners extends SubComponent { private var currentIClazz: IClass = _ private def warn(pos: Position, msg: String) = currentIClazz.cunit.inlinerWarning(pos, msg) - private def ownedName(sym: Symbol): String = afterUncurry { + private def ownedName(sym: Symbol): String = exitingUncurry { val count = ( if (!sym.isMethod) 1 else if (sym.owner.isAnonymousFunction) 3 @@ -279,7 +281,7 @@ abstract class Inliners extends SubComponent { } val tfa = new analysis.MTFAGrowable() - tfa.stat = global.opt.printStats + tfa.stat = global.settings.Ystatistics.value val staleOut = new mutable.ListBuffer[BasicBlock] val splicedBlocks = mutable.Set.empty[BasicBlock] val staleIn = mutable.Set.empty[BasicBlock] @@ -320,8 +322,8 @@ abstract class Inliners extends SubComponent { if (settings.debug.value) inlineLog("caller", ownedName(m.symbol), "in " + m.symbol.owner.fullName) - var sizeBeforeInlining = m.code.blockCount - var instrBeforeInlining = m.code.instructionCount + val sizeBeforeInlining = m.code.blockCount + val instrBeforeInlining = m.code.instructionCount var retry = false var count = 0 @@ -477,7 +479,7 @@ abstract class Inliners extends SubComponent { * As a whole, both `preInline()` invocations amount to priming the inlining process, * so that the first TFA that is run afterwards is able to gain more information as compared to a cold-start. */ - val totalPreInlines = { + /*val totalPreInlines = */ { // Val name commented out to emphasize it is never used val firstRound = preInline(true) if(firstRound == 0) 0 else (firstRound + preInline(false)) } @@ -569,7 +571,6 @@ abstract class Inliners extends SubComponent { m.normalize if (sizeBeforeInlining > 0) { val instrAfterInlining = m.code.instructionCount - val prefix = if ((instrAfterInlining > 2 * instrBeforeInlining) && (instrAfterInlining > 200)) "!!" else "" val inlinings = caller.inlinedCalls if (inlinings > 0) { val s1 = s"instructions $instrBeforeInlining -> $instrAfterInlining" @@ -584,7 +585,7 @@ abstract class Inliners extends SubComponent { private def isHigherOrderMethod(sym: Symbol) = ( sym.isMethod - && beforeExplicitOuter(sym.info.paramTypes exists isFunctionType) // was "at erasurePhase.prev" + && enteringExplicitOuter(sym.info.paramTypes exists isFunctionType) // was "at erasurePhase.prev" ) /** Should method 'sym' being called in 'receiver' be loaded from disk? */ @@ -601,7 +602,6 @@ abstract class Inliners extends SubComponent { override def toString = m.toString val sym = m.symbol - val name = sym.name def owner = sym.owner def paramTypes = sym.info.paramTypes def minimumStack = paramTypes.length + 1 @@ -617,13 +617,11 @@ abstract class Inliners extends SubComponent { def length = blocks.length def openBlocks = blocks filterNot (_.closed) def instructions = m.code.instructions - // def linearized = linearizer linearize m def isSmall = (length <= SMALL_METHOD_SIZE) && blocks(0).length < 10 def isLarge = length > MAX_INLINE_SIZE def isRecursive = m.recursive def hasHandlers = handlers.nonEmpty || m.bytecodeHasEHs - def hasClosureParam = paramTypes exists (tp => isByNameParamType(tp) || isFunctionType(tp)) def isSynchronized = sym.hasFlag(Flags.SYNCHRONIZED) def hasNonFinalizerHandler = handlers exists { @@ -731,7 +729,6 @@ abstract class Inliners extends SubComponent { */ sealed abstract class InlineSafetyInfo { def isSafe = false - def isUnsafe = !isSafe } case object NeverSafeToInline extends InlineSafetyInfo case object InlineableAtThisCaller extends InlineSafetyInfo { override def isSafe = true } @@ -1031,7 +1028,6 @@ abstract class Inliners extends SubComponent { case Public => true } private def sameSymbols = caller.sym == inc.sym - private def sameOwner = caller.owner == inc.owner /** Gives green light for inlining (which may still be vetoed later). Heuristics: * - it's bad to make the caller larger (> SMALL_METHOD_SIZE) if it was small @@ -1058,8 +1054,8 @@ abstract class Inliners extends SubComponent { if (inc.isMonadic) score += 3 else if (inc.isHigherOrder) score += 1 - if (inc.isInClosure) score += 2 - if (inlinedMethodCount(inc.sym) > 2) score -= 2 + if (inc.isInClosure) score += 2; + if (inlinedMethodCount(inc.sym) > 2) score -= 2; score } } diff --git a/src/compiler/scala/tools/nsc/dependencies/Changes.scala b/src/compiler/scala/tools/nsc/dependencies/Changes.scala index 7f5f412a20..b3cacee20a 100644 --- a/src/compiler/scala/tools/nsc/dependencies/Changes.scala +++ b/src/compiler/scala/tools/nsc/dependencies/Changes.scala @@ -61,12 +61,7 @@ abstract class Changes { annotationsChecked.forall(a => (sym1.hasAnnotation(a) == sym2.hasAnnotation(a))) - private def sameType(tp1: Type, tp2: Type)(implicit strict: Boolean) = { - def typeOf(tp: Type): String = tp.toString + "[" + tp.getClass + "]" - val res = sameType0(tp1, tp2) - //if (!res) println("\t different types: " + typeOf(tp1) + " : " + typeOf(tp2)) - res - } + private def sameType(tp1: Type, tp2: Type)(implicit strict: Boolean) = sameType0(tp1, tp2) private def sameType0(tp1: Type, tp2: Type)(implicit strict: Boolean): Boolean = ((tp1, tp2) match { /*case (ErrorType, _) => false @@ -170,7 +165,6 @@ abstract class Changes { /** Return the list of changes between 'from' and 'toSym.info'. */ def changeSet(from: Type, toSym: Symbol): List[Change] = { - implicit val defaultReason = "types" implicit val defaultStrictTypeRefTest = true val to = toSym.info diff --git a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala b/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala index cdde768274..4d4b6589a0 100644 --- a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala +++ b/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala @@ -3,7 +3,6 @@ package dependencies import io.Path import scala.collection._ -import symtab.Flags import scala.tools.nsc.io.AbstractFile import scala.reflect.internal.util.SourceFile @@ -145,7 +144,7 @@ trait DependencyAnalysis extends SubComponent with Files { val name = d.toString d.symbol match { case s : ModuleClassSymbol => - val isTopLevelModule = afterPickler { !s.isImplClass && !s.isNestedClass } + val isTopLevelModule = exitingPickler { !s.isImplClass && !s.isNestedClass } if (isTopLevelModule && (s.companionModule != NoSymbol)) { dependencies.emits(source, nameToFile(unit.source.file, name)) @@ -183,7 +182,7 @@ trait DependencyAnalysis extends SubComponent with Files { // was "at uncurryPhase.prev", which is actually non-deterministic // because the continuations plugin may or may not supply uncurry's // immediately preceding phase. - beforeRefchecks(checkType(tree.symbol.tpe)) + enteringRefchecks(checkType(tree.symbol.tpe)) } tree match { @@ -191,7 +190,7 @@ trait DependencyAnalysis extends SubComponent with Files { !cdef.symbol.isAnonymousFunction => if (cdef.symbol != NoSymbol) buf += cdef.symbol // was "at erasurePhase.prev" - beforeExplicitOuter { + enteringExplicitOuter { for (s <- cdef.symbol.info.decls) s match { case ts: TypeSymbol if !ts.isClass => @@ -203,7 +202,7 @@ trait DependencyAnalysis extends SubComponent with Files { case ddef: DefDef => // was "at typer.prev" - beforeTyper { checkType(ddef.symbol.tpe) } + enteringTyper { checkType(ddef.symbol.tpe) } super.traverse(tree) case a @ Select(q, n) if ((a.symbol != NoSymbol) && (q.symbol != null)) => // #2556 if (!a.symbol.isConstructor && diff --git a/src/compiler/scala/tools/nsc/doc/DocFactory.scala b/src/compiler/scala/tools/nsc/doc/DocFactory.scala index 642e330a57..a091bc3e62 100644 --- a/src/compiler/scala/tools/nsc/doc/DocFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/DocFactory.scala @@ -8,9 +8,7 @@ package doc import scala.util.control.ControlThrowable import reporters.Reporter -import scala.reflect.internal.util.{ NoPosition, BatchSourceFile} -import io.{ File, Directory } -import DocParser.Parsed +import scala.reflect.internal.util.BatchSourceFile /** A documentation processor controls the process of generating Scala * documentation, which is as follows. diff --git a/src/compiler/scala/tools/nsc/doc/Settings.scala b/src/compiler/scala/tools/nsc/doc/Settings.scala index 10a0d8d879..16f3c3776b 100644 --- a/src/compiler/scala/tools/nsc/doc/Settings.scala +++ b/src/compiler/scala/tools/nsc/doc/Settings.scala @@ -6,9 +6,7 @@ package scala.tools.nsc package doc -import java.io.File import java.net.URI -import java.lang.System import scala.language.postfixOps /** An extended version of compiler settings, with additional Scaladoc-specific options. diff --git a/src/compiler/scala/tools/nsc/doc/Uncompilable.scala b/src/compiler/scala/tools/nsc/doc/Uncompilable.scala index d3e5c869e0..9447e36610 100644 --- a/src/compiler/scala/tools/nsc/doc/Uncompilable.scala +++ b/src/compiler/scala/tools/nsc/doc/Uncompilable.scala @@ -15,7 +15,7 @@ trait Uncompilable { val global: Global val settings: Settings - import global.{ reporter, inform, warning, newTypeName, newTermName, Symbol, Name, DocComment, NoSymbol } + import global.{ reporter, inform, warning, newTypeName, newTermName, Symbol, DocComment, NoSymbol } import global.definitions.AnyRefClass import global.rootMirror.RootClass diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala index e8131e242b..c898348526 100644 --- a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala +++ b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala @@ -10,7 +10,7 @@ package html import model._ import comment._ -import scala.xml.{XML, NodeSeq} +import scala.xml.NodeSeq import scala.xml.dtd.{DocType, PublicID} import scala.collection._ import java.io.Writer diff --git a/src/compiler/scala/tools/nsc/doc/html/Page.scala b/src/compiler/scala/tools/nsc/doc/html/Page.scala index 62166f7def..ef9beb1dce 100644 --- a/src/compiler/scala/tools/nsc/doc/html/Page.scala +++ b/src/compiler/scala/tools/nsc/doc/html/Page.scala @@ -88,12 +88,6 @@ abstract class Page { def relativeLinkTo(destClass: TemplateEntity): String = relativeLinkTo(templateToPath(destClass)) - /** A relative link from this page to some destination page in the Scaladoc site. - * @param destPage The page that the link will point to. */ - def relativeLinkTo(destPage: HtmlPage): String = { - relativeLinkTo(destPage.path) - } - /** A relative link from this page to some destination path. * @param destPath The path that the link will point to. */ def relativeLinkTo(destPath: List[String]): String = { diff --git a/src/compiler/scala/tools/nsc/doc/html/SyntaxHigh.scala b/src/compiler/scala/tools/nsc/doc/html/SyntaxHigh.scala index ee78f4ea7a..2783a27811 100644 --- a/src/compiler/scala/tools/nsc/doc/html/SyntaxHigh.scala +++ b/src/compiler/scala/tools/nsc/doc/html/SyntaxHigh.scala @@ -40,7 +40,7 @@ private[html] object SyntaxHigh { /** Standard library classes/objects, sorted alphabetically */ val standards = Array ( - "WeakTypeTag", "Any", "AnyRef", "AnyVal", "App", "Application", "Array", + "WeakTypeTag", "Any", "AnyRef", "AnyVal", "App", "Array", "Boolean", "Byte", "Char", "Class", "ClassTag", "ClassManifest", "Console", "Double", "Enumeration", "Float", "Function", "Int", "List", "Long", "Manifest", "Map", diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Index.scala b/src/compiler/scala/tools/nsc/doc/html/page/Index.scala index 86407fb9a3..daa9df690c 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Index.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Index.scala @@ -9,10 +9,8 @@ package html package page import model._ - import scala.collection._ import scala.xml._ -import scala.util.parsing.json.{JSONObject, JSONArray} class Index(universe: doc.Universe, val index: doc.Index) extends HtmlPage { diff --git a/src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala b/src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala index a205e02533..e3c94505ab 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala @@ -8,7 +8,6 @@ package scala.tools.nsc.doc.html.page import scala.tools.nsc.doc import scala.tools.nsc.doc.model.{Package, DocTemplateEntity} import scala.tools.nsc.doc.html.{Page, HtmlFactory} -import java.nio.channels.Channels import scala.util.parsing.json.{JSONObject, JSONArray} class IndexScript(universe: doc.Universe, index: doc.Index) extends Page { diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Source.scala b/src/compiler/scala/tools/nsc/doc/html/page/Source.scala index 807a1bc11a..37145756d9 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Source.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Source.scala @@ -8,9 +8,7 @@ package doc package html package page -import model._ -import comment._ -import scala.xml.{NodeSeq, Unparsed} +import scala.xml.NodeSeq import java.io.File class Source(sourceFile: File) extends HtmlPage { diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala index 008999e09f..3f40e2cd0a 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -8,10 +8,6 @@ package doc package html package page -import model._ -import model.diagram._ -import diagram._ - import scala.xml.{ NodeSeq, Text, UnprefixedAttribute } import scala.language.postfixOps @@ -527,7 +523,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp val sourceLink: Seq[scala.xml.Node] = mbr match { case dtpl: DocTemplateEntity if (isSelf && dtpl.sourceUrl.isDefined && dtpl.inSource.isDefined && !isReduced) => - val (absFile, line) = dtpl.inSource.get + val (absFile, _) = dtpl.inSource.get <dt>Source</dt> <dd>{ <a href={ dtpl.sourceUrl.get.toString } target="_blank">{ Text(absFile.file.getName) }</a> }</dd> case _ => NodeSeq.Empty @@ -651,7 +647,6 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp case dtpl: DocTemplateEntity if isSelf && !isReduced => val diagram = f(dtpl) if (diagram.isDefined) { - val s = universe.settings val diagramSvg = generator.generate(diagram.get, tpl, this) if (diagramSvg != NodeSeq.Empty) { <div class="toggleContainer block diagram-container" id={ id + "-container"}> diff --git a/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala b/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala index 304c534bdc..df7c7d3dcd 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala @@ -10,7 +10,6 @@ package diagram import scala.xml.{NodeSeq, XML, PrefixedAttribute, Elem, MetaData, Null, UnprefixedAttribute} import scala.collection.immutable._ -import javax.xml.parsers.SAXParser import model._ import model.diagram._ @@ -22,8 +21,6 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator { private var pathToLib: String = null // maps nodes to unique indices private var node2Index: Map[Node, Int] = null - // maps an index to its corresponding node - private var index2Node: Map[Int, Node] = null // true if the current diagram is a class diagram private var isInheritanceDiagram = false // incoming implicit nodes (needed for determining the CSS class of a node) @@ -42,7 +39,6 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator { // clean things up a bit, so we don't leave garbage on the heap this.page = null node2Index = null - index2Node = null incomingImplicitNodes = List() result } @@ -116,7 +112,6 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator { node2Index = d.nodes.zipWithIndex.toMap incomingImplicitNodes = List() } - index2Node = node2Index map {_.swap} val implicitsDot = { if (!isInheritanceDiagram) "" @@ -215,7 +210,7 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator { def escape(name: String) = name.replace("&", "&").replace("<", "<").replace(">", ">"); // assemble node attribues in a map - var attr = scala.collection.mutable.Map[String, String]() + val attr = scala.collection.mutable.Map[String, String]() // link node.doctpl match { diff --git a/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotRunner.scala b/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotRunner.scala index 5cdd5c74a4..2fa1bf62f3 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotRunner.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotRunner.scala @@ -10,12 +10,10 @@ import java.io.InputStreamReader import java.io.OutputStreamWriter import java.io.BufferedWriter import java.io.BufferedReader -import java.io.IOException import scala.sys.process._ import scala.concurrent.SyncVar import model._ -import model.diagram._ /** This class takes care of running the graphviz dot utility */ class DotRunner(settings: doc.Settings) { @@ -183,7 +181,7 @@ class DotProcess(settings: doc.Settings) { private[this] def outputFn(stdOut: InputStream): Unit = { val reader = new BufferedReader(new InputStreamReader(stdOut)) - var buffer: StringBuilder = new StringBuilder() + val buffer: StringBuilder = new StringBuilder() try { var line = reader.readLine while (!error && line != null) { @@ -209,7 +207,6 @@ class DotProcess(settings: doc.Settings) { private[this] def errorFn(stdErr: InputStream): Unit = { val reader = new BufferedReader(new InputStreamReader(stdErr)) - var buffer: StringBuilder = new StringBuilder() try { var line = reader.readLine while (line != null) { @@ -225,4 +222,4 @@ class DotProcess(settings: doc.Settings) { errorBuffer.append(" Error thread in " + templateName + ": Exception: " + exc + "\n") } } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/doc/model/Entity.scala b/src/compiler/scala/tools/nsc/doc/model/Entity.scala index c3f9101f17..04046accc4 100644 --- a/src/compiler/scala/tools/nsc/doc/model/Entity.scala +++ b/src/compiler/scala/tools/nsc/doc/model/Entity.scala @@ -23,10 +23,6 @@ import diagram._ * - type and value parameters; * - annotations. */ trait Entity { - - /** Similar to symbols, so we can track entities */ - def id: Int - /** The name of the entity. Note that the name does not qualify this entity uniquely; use its `qualifiedName` * instead. */ def name : String @@ -59,9 +55,6 @@ trait Entity { /** Indicates whether this entity lives in the types namespace (classes, traits, abstract/alias types) */ def isType: Boolean - - /** Indicates whether this entity lives in the terms namespace (objects, packages, methods, values) */ - def isTerm: Boolean } object Entity { @@ -97,9 +90,6 @@ trait TemplateEntity extends Entity { /** Whether documentation is available for this template. */ def isDocTemplate: Boolean - /** Whether documentation is available for this template. */ - def isNoDocMemberTemplate: Boolean - /** Whether this template is a case class. */ def isCaseClass: Boolean @@ -149,9 +139,6 @@ trait MemberEntity extends Entity { /** Some migration warning if this member has a migration annotation, or none otherwise. */ def migration: Option[Body] - @deprecated("Use `inDefinitionTemplates` instead", "2.9.0") - def inheritedFrom: List[TemplateEntity] - /** For members representing values: the type of the value returned by this member; for members * representing types: the type itself. */ def resultType: TypeEntity @@ -177,12 +164,6 @@ trait MemberEntity extends Entity { /** Whether this member is an abstract type. */ def isAbstractType: Boolean - /** Whether this member is a template. */ - def isTemplate: Boolean - - /** Whether this member is implicit. */ - def isImplicit: Boolean - /** Whether this member is abstract. */ def isAbstract: Boolean @@ -384,14 +365,9 @@ trait RootPackage extends Package /** A non-template member (method, value, lazy value, variable, constructor, alias type, and abstract type). */ trait NonTemplateMemberEntity extends MemberEntity { - /** Whether this member is a use case. A use case is a member which does not exist in the documented code. * It corresponds to a real member, and provides a simplified, yet compatible signature for that member. */ def isUseCase: Boolean - - /** Whether this member is a bridge member. A bridge member does only exist for binary compatibility reasons - * and should not appear in ScalaDoc. */ - def isBridge: Boolean } @@ -506,12 +482,6 @@ trait ImplicitConversion { /** The result type after the conversion */ def targetType: TypeEntity - /** The result type after the conversion - * Note: not all targetTypes have a corresponding template. Examples include conversions resulting in refinement - * types. Need to check it's not option! - */ - def targetTemplate: Option[TemplateEntity] - /** The components of the implicit conversion type parents */ def targetTypeComponents: List[(TemplateEntity, TypeEntity)] diff --git a/src/compiler/scala/tools/nsc/doc/model/IndexModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/IndexModelFactory.scala index 10e2f23142..1d6063255d 100755 --- a/src/compiler/scala/tools/nsc/doc/model/IndexModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/IndexModelFactory.scala @@ -17,8 +17,6 @@ object IndexModelFactory { object result extends mutable.HashMap[Char,SymbolMap] { - /* Owner template ordering */ - implicit def orderingSet = math.Ordering.String.on { x: MemberEntity => x.name.toLowerCase } /* symbol name ordering */ implicit def orderingMap = math.Ordering.String.on { x: String => x.toLowerCase } diff --git a/src/compiler/scala/tools/nsc/doc/model/LinkTo.scala b/src/compiler/scala/tools/nsc/doc/model/LinkTo.scala index 6c13d5a6d3..361837b743 100644 --- a/src/compiler/scala/tools/nsc/doc/model/LinkTo.scala +++ b/src/compiler/scala/tools/nsc/doc/model/LinkTo.scala @@ -6,8 +6,6 @@ package scala.tools.nsc package doc package model -import scala.collection._ - abstract sealed class LinkTo final case class LinkToTpl(tpl: DocTemplateEntity) extends LinkTo final case class LinkToMember(mbr: MemberEntity, inTpl: DocTemplateEntity) extends LinkTo diff --git a/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala b/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala index 5257db1610..4793716b9f 100644 --- a/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala +++ b/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala @@ -4,8 +4,6 @@ package model import comment._ -import scala.reflect.internal.util.FakePos //Position - /** This trait extracts all required information for documentation from compilation units */ trait MemberLookup { thisFactory: ModelFactory => @@ -19,7 +17,7 @@ trait MemberLookup { def memberLookup(pos: Position, query: String, inTplOpt: Option[DocTemplateImpl]): LinkTo = { assert(modelFinished) - var members = breakMembers(query) + val members = breakMembers(query) //println(query + " => " + members) // (1) First look in the root package, as most of the links are qualified diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 3ae1210ebf..acdc3e6797 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -43,20 +43,6 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { def modelFinished: Boolean = _modelFinished private var universe: Universe = null - private def dbg(msg: String) = if (sys.props contains "scala.scaladoc.debug") println(msg) - protected def closestPackage(sym: Symbol) = { - if (sym.isPackage || sym.isPackageClass) sym - else sym.enclosingPackage - } - - private def printWithoutPrefix(memberSym: Symbol, templateSym: Symbol) = { - dbg( - "memberSym " + memberSym + " templateSym " + templateSym + " encls = " + - closestPackage(memberSym) + ", " + closestPackage(templateSym) - ) - memberSym.isOmittablePrefix || (closestPackage(memberSym) == closestPackage(templateSym)) - } - def makeModel: Option[Universe] = { val universe = new Universe { thisUniverse => thisFactory.universe = thisUniverse @@ -86,7 +72,6 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { /* ============== IMPLEMENTATION PROVIDING ENTITY TYPES ============== */ abstract class EntityImpl(val sym: Symbol, val inTpl: TemplateImpl) extends Entity { - val id = { ids += 1; ids } val name = optimize(sym.nameString) val universe = thisFactory.universe @@ -100,7 +85,6 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { def annotations = sym.annotations.map(makeAnnotation) def inPackageObject: Boolean = sym.owner.isModuleClass && sym.owner.sourceModule.isPackageObject def isType = sym.name.isTypeName - def isTerm = sym.name.isTermName } trait TemplateImpl extends EntityImpl with TemplateEntity { @@ -112,7 +96,6 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { def isObject = sym.isModule && !sym.isPackage def isCaseClass = sym.isCaseClass def isRootPackage = false - def isNoDocMemberTemplate = false def selfType = if (sym.thisSym eq sym) None else Some(makeType(sym.thisSym.typeOfThis, this)) } @@ -127,18 +110,14 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { } if (inTpl != null) thisFactory.comment(sym, thisTpl, inTpl) else None } - def group = if (comment.isDefined) comment.get.group.getOrElse(defaultGroup) else defaultGroup + def group = comment flatMap (_.group) getOrElse defaultGroup override def inTemplate = inTpl override def toRoot: List[MemberImpl] = this :: inTpl.toRoot - def inDefinitionTemplates = this match { - case mb: NonTemplateMemberEntity if (mb.useCaseOf.isDefined) => - mb.useCaseOf.get.inDefinitionTemplates - case _ => - if (inTpl == null) - List(makeRootPackage) - else - makeTemplate(sym.owner)::(sym.allOverriddenSymbols map { inhSym => makeTemplate(inhSym.owner) }) - } + def inDefinitionTemplates = + if (inTpl == null) + List(makeRootPackage) + else + makeTemplate(sym.owner)::(sym.allOverriddenSymbols map { inhSym => makeTemplate(inhSym.owner) }) def visibility = { if (sym.isPrivateLocal) PrivateInInstance() else if (sym.isProtectedLocal) ProtectedInInstance() @@ -149,8 +128,10 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { else None if (sym.isPrivate) PrivateInTemplate(inTpl) else if (sym.isProtected) ProtectedInTemplate(qual getOrElse inTpl) - else if (qual.isDefined) PrivateInTemplate(qual.get) - else Public() + else qual match { + case Some(q) => PrivateInTemplate(q) + case None => Public() + } } } def flags = { @@ -189,9 +170,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { }) else None - def inheritedFrom = - if (inTemplate.sym == this.sym.owner || inTemplate.sym.isPackage) Nil else - makeTemplate(this.sym.owner) :: (sym.allOverriddenSymbols map { os => makeTemplate(os.owner) }) + def resultType = { def resultTpe(tpe: Type): Type = tpe match { // similar to finalResultType, except that it leaves singleton types alone case PolyType(_, res) => resultTpe(res) @@ -199,14 +178,13 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { case NullaryMethodType(res) => resultTpe(res) case _ => tpe } - val tpe = if (!isImplicitlyInherited) sym.tpe else byConversion.get.toType memberInfo sym + val tpe = byConversion.fold(sym.tpe) (_.toType memberInfo sym) makeTypeInTemplateContext(resultTpe(tpe), inTemplate, sym) } def isDef = false def isVal = false def isLazyVal = false def isVar = false - def isImplicit = sym.isImplicit def isConstructor = false def isAliasType = false def isAbstractType = false @@ -214,7 +192,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { // for the explanation of conversion == null see comment on flags ((!sym.isTrait && ((sym hasFlag Flags.ABSTRACT) || (sym hasFlag Flags.DEFERRED)) && (!isImplicitlyInherited)) || sym.isAbstractClass || sym.isAbstractType) && !sym.isSynthetic - def isTemplate = false + def signature = externalSignature(sym) lazy val signatureCompat = { @@ -255,8 +233,8 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { * exists, but should not be documented (either it's not included in the source or it's not visible) */ class NoDocTemplateImpl(sym: Symbol, inTpl: TemplateImpl) extends EntityImpl(sym, inTpl) with TemplateImpl with HigherKindedImpl with NoDocTemplate { - assert(modelFinished) - assert(!(noDocTemplatesCache isDefinedAt sym)) + assert(modelFinished, this) + assert(!(noDocTemplatesCache isDefinedAt sym), (sym, noDocTemplatesCache(sym))) noDocTemplatesCache += (sym -> this) def isDocTemplate = false } @@ -268,25 +246,10 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { */ abstract class MemberTemplateImpl(sym: Symbol, inTpl: DocTemplateImpl) extends MemberImpl(sym, inTpl) with TemplateImpl with HigherKindedImpl with MemberTemplateEntity { // no templates cache for this class, each owner gets its own instance - override def isTemplate = true def isDocTemplate = false - override def isNoDocMemberTemplate = true lazy val definitionName = optimize(inDefinitionTemplates.head.qualifiedName + "." + name) def valueParams: List[List[ValueParam]] = Nil /** TODO, these are now only computed for DocTemplates */ - // Seems unused - // def parentTemplates = - // if (sym.isPackage || sym == AnyClass) - // List() - // else - // sym.tpe.parents.flatMap { tpe: Type => - // val tSym = tpe.typeSymbol - // if (tSym != NoSymbol) - // List(makeTemplate(tSym)) - // else - // List() - // } filter (_.isInstanceOf[DocTemplateEntity]) - def parentTypes = if (sym.isPackage || sym == AnyClass) List() else { val tps = (this match { @@ -306,7 +269,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { * All ancestors of the template and all non-package members. */ abstract class DocTemplateImpl(sym: Symbol, inTpl: DocTemplateImpl) extends MemberTemplateImpl(sym, inTpl) with DocTemplateEntity { - assert(!modelFinished) + assert(!modelFinished, (sym, inTpl)) assert(!(docTemplatesCache isDefinedAt sym), sym) docTemplatesCache += (sym -> this) @@ -391,9 +354,9 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { lazy val memberSyms = sym.info.members.filter(s => membersShouldDocument(s, this)).toList // the inherited templates (classes, traits or objects) - var memberSymsLazy = memberSyms.filter(t => templateShouldDocument(t, this) && !inOriginalOwner(t, this)) + val memberSymsLazy = memberSyms.filter(t => templateShouldDocument(t, this) && !inOriginalOwner(t, this)) // the direct members (methods, values, vars, types and directly contained templates) - var memberSymsEager = memberSyms.filter(!memberSymsLazy.contains(_)) + val memberSymsEager = memberSyms.filter(!memberSymsLazy.contains(_)) // the members generated by the symbols in memberSymsEager val ownMembers = (memberSymsEager.flatMap(makeMember(_, None, this))) @@ -439,17 +402,16 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { conversions flatMap (conv => if (!implicitExcluded(conv.conversionQualifiedName)) conv.targetTypeComponents map { - case pair@(template, tpe) => + case (template, tpe) => template match { case d: DocTemplateImpl if (d != this) => d.registerImplicitlyConvertibleClass(this, conv) case _ => // nothing } - (pair._1, pair._2, conv) + (template, tpe, conv) } else List() ) - override def isTemplate = true override def isDocTemplate = true private[this] lazy val companionSymbol = if (sym.isAliasType || sym.isAbstractType) { @@ -524,31 +486,26 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extends MemberImpl(sym, inTpl) with NonTemplateMemberEntity { override lazy val comment = { val inRealTpl = - /* Variable precendence order for implicitly added members: Take the variable defifinitions from ... - * 1. the target of the implicit conversion - * 2. the definition template (owner) - * 3. the current template - */ - if (conversion.isDefined) findTemplateMaybe(conversion.get.toType.typeSymbol) match { - case Some(d) if d != makeRootPackage => d //in case of NoSymbol, it will give us the root package - case _ => findTemplateMaybe(sym.owner) match { - case Some(d) if d != makeRootPackage => d //in case of NoSymbol, it will give us the root package - case _ => inTpl - } - } else inTpl - if (inRealTpl != null) thisFactory.comment(sym, None, inRealTpl) else None + conversion.fold(Option(inTpl)) { conv => + /* Variable precendence order for implicitly added members: Take the variable defifinitions from ... + * 1. the target of the implicit conversion + * 2. the definition template (owner) + * 3. the current template + */ + findTemplateMaybe(conv.toType.typeSymbol) filterNot (_ == makeRootPackage) orElse ( + findTemplateMaybe(sym.owner) filterNot (_ == makeRootPackage) orElse Option(inTpl) + ) + } + inRealTpl flatMap (thisFactory.comment(sym, None, _)) } + override def inDefinitionTemplates = useCaseOf.fold(super.inDefinitionTemplates)(_.inDefinitionTemplates) + override def qualifiedName = optimize(inTemplate.qualifiedName + "#" + name) lazy val definitionName = { - // this contrived name is here just to satisfy some older tests -- if you decide to remove it, be my guest, and - // also remove property("package object") from test/scaladoc/scalacheck/HtmlFactoryTest.scala so you don't break - // the test suite... - val packageObject = if (inPackageObject) ".package" else "" - if (!conversion.isDefined) optimize(inDefinitionTemplates.head.qualifiedName + packageObject + "#" + name) - else optimize(conversion.get.conversionQualifiedName + packageObject + "#" + name) + val qualifiedName = conversion.fold(inDefinitionTemplates.head.qualifiedName)(_.conversionQualifiedName) + optimize(qualifiedName + "#" + name) } - def isBridge = sym.isBridge def isUseCase = useCaseOf.isDefined override def byConversion: Option[ImplicitConversionImpl] = conversion override def isImplicitlyInherited = { assert(modelFinished); conversion.isDefined } @@ -561,7 +518,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { useCaseOf: Option[MemberEntity], inTpl: DocTemplateImpl) extends NonTemplateMemberImpl(sym, conversion, useCaseOf, inTpl) { def valueParams = { - val info = if (!isImplicitlyInherited) sym.info else conversion.get.toType memberInfo sym + val info = conversion.fold(sym.info)(_.toType memberInfo sym) info.paramss map { ps => (ps.zipWithIndex) map { case (p, i) => if (p.nameString contains "$") makeValueParam(p, inTpl, optimize("arg" + i)) else makeValueParam(p, inTpl) }} @@ -663,7 +620,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { */ def createTemplate(aSym: Symbol, inTpl: DocTemplateImpl): Option[MemberImpl] = { // don't call this after the model finished! - assert(!modelFinished) + assert(!modelFinished, (aSym, inTpl)) def createRootPackageComment: Option[Comment] = if(settings.docRootContent.isDefault) None @@ -679,7 +636,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { } def createDocTemplate(bSym: Symbol, inTpl: DocTemplateImpl): DocTemplateImpl = { - assert(!modelFinished) // only created BEFORE the model is finished + assert(!modelFinished, (bSym, inTpl)) // only created BEFORE the model is finished if (bSym.isAliasType && bSym != AnyRefClass) new DocTemplateImpl(bSym, inTpl) with AliasImpl with AliasType { override def isAliasType = true } else if (bSym.isAbstractType) @@ -710,7 +667,6 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { override def inTemplate = this override def toRoot = this :: Nil override def qualifiedName = "_root_" - override def inheritedFrom = Nil override def isRootPackage = true override lazy val memberSyms = (bSym.info.members ++ EmptyPackage.info.members).toList filter { s => @@ -780,7 +736,6 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { } } - /** Get the root package */ def makeRootPackage: PackageImpl = docTemplatesCache(RootPackage).asInstanceOf[PackageImpl] // TODO: Should be able to override the type @@ -857,16 +812,10 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { } def findMember(aSym: Symbol, inTpl: DocTemplateImpl): Option[MemberImpl] = { - val tplSym = normalizeTemplate(aSym.owner) + normalizeTemplate(aSym.owner) inTpl.members.find(_.sym == aSym) } - @deprecated("Use `findLinkTarget` instead.", "2.10.0") - def findTemplate(query: String): Option[DocTemplateImpl] = { - assert(modelFinished) - docTemplatesCache.values find { (tpl: DocTemplateImpl) => tpl.qualifiedName == query && !packageDropped(tpl) && !tpl.isObject } - } - def findTemplateMaybe(aSym: Symbol): Option[DocTemplateImpl] = { assert(modelFinished) docTemplatesCache.get(normalizeTemplate(aSym)).filterNot(packageDropped(_)) @@ -877,20 +826,12 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { def makeTemplate(aSym: Symbol, inTpl: Option[TemplateImpl]): TemplateImpl = { assert(modelFinished) - def makeNoDocTemplate(aSym: Symbol, inTpl: TemplateImpl): NoDocTemplateImpl = { - val bSym = normalizeTemplate(aSym) - noDocTemplatesCache.get(bSym) match { - case Some(noDocTpl) => noDocTpl - case None => new NoDocTemplateImpl(bSym, inTpl) - } - } + def makeNoDocTemplate(aSym: Symbol, inTpl: TemplateImpl): NoDocTemplateImpl = + noDocTemplatesCache getOrElse (aSym, new NoDocTemplateImpl(aSym, inTpl)) - findTemplateMaybe(aSym) match { - case Some(dtpl) => - dtpl - case None => - val bSym = normalizeTemplate(aSym) - makeNoDocTemplate(bSym, if (inTpl.isDefined) inTpl.get else makeTemplate(bSym.owner)) + findTemplateMaybe(aSym) getOrElse { + val bSym = normalizeTemplate(aSym) + makeNoDocTemplate(bSym, inTpl getOrElse makeTemplate(bSym.owner)) } } @@ -901,24 +842,28 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { lazy val annotationClass = makeTemplate(annot.symbol) val arguments = { // lazy - def noParams = annot.args map { _ => None } + def annotArgs = annot.args match { + case Nil => annot.assocs collect { case (_, LiteralAnnotArg(const)) => Literal(const) } + case xs => xs + } + def noParams = annotArgs map (_ => None) + val params: List[Option[ValueParam]] = annotationClass match { case aClass: DocTemplateEntity with Class => (aClass.primaryConstructor map { _.valueParams.head }) match { case Some(vps) => vps map { Some(_) } - case None => noParams + case _ => noParams } case _ => noParams } - assert(params.length == annot.args.length) - (params zip annot.args) flatMap { case (param, arg) => - makeTree(arg) match { - case Some(tree) => - Some(new ValueArgument { - def parameter = param - def value = tree - }) - case None => None + assert(params.length == annotArgs.length, (params, annotArgs)) + + params zip annotArgs flatMap { case (param, arg) => + makeTree(arg) map { tree => + new ValueArgument { + def parameter = param + def value = tree + } } } } @@ -983,10 +928,10 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { val ignoreParents = Set[Symbol](AnyClass, AnyRefClass, ObjectClass) val filtParents = // we don't want to expose too many links to AnyRef, that will just be redundant information - if (tpl.isDefined && { val sym = tpl.get.sym; (!sym.isModule && parents.length < 2) || (sym == AnyValClass) || (sym == AnyRefClass) || (sym == AnyClass) }) - parents - else - parents.filterNot((p: Type) => ignoreParents(p.typeSymbol)) + tpl match { + case Some(tpl) if (!tpl.sym.isModule && parents.length < 2) || (tpl.sym == AnyValClass) || (tpl.sym == AnyRefClass) || (tpl.sym == AnyClass) => parents + case _ => parents.filterNot((p: Type) => ignoreParents(p.typeSymbol)) + } /** Returns: * - a DocTemplate if the type's symbol is documented @@ -1017,9 +962,9 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { } def makeQualifiedName(sym: Symbol, relativeTo: Option[Symbol] = None): String = { - val stop = if (relativeTo.isDefined) relativeTo.get.ownerChain.toSet else Set[Symbol]() + val stop = relativeTo map (_.ownerChain.toSet) getOrElse Set[Symbol]() var sym1 = sym - var path = new StringBuilder() + val path = new StringBuilder() // var path = List[Symbol]() while ((sym1 != NoSymbol) && (path.isEmpty || !stop(sym1))) { @@ -1088,7 +1033,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { def findExternalLink(sym: Symbol, name: String): Option[LinkTo] = { val sym1 = if (sym == AnyClass || sym == AnyRefClass || sym == AnyValClass || sym == NothingClass) ListClass - else if (sym.isPackage) + else if (sym.isPackage) /* Get package object which has associatedFile ne null */ sym.info.member(newTermName("package")) else sym diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala index 5334de3797..015fce294e 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala @@ -13,12 +13,7 @@ package model import comment._ import scala.collection._ -import scala.util.matching.Regex - import symtab.Flags -import io._ - -import model.{ RootPackage => RootPackageEntity } /** * This trait finds implicit conversions for a class in the default scope and creates scaladoc entries for each of them. @@ -58,7 +53,6 @@ trait ModelFactoryImplicitSupport { import global._ import global.analyzer._ import global.definitions._ - import rootMirror.{RootPackage, RootClass, EmptyPackage, EmptyPackageClass} import settings.hardcoded // debugging: @@ -96,9 +90,9 @@ trait ModelFactoryImplicitSupport { // But we don't want that, so we'll simply refuse to find implicit conversions on for Nothing and Null if (!(sym.isClass || sym.isTrait || sym == AnyRefClass) || sym == NothingClass || sym == NullClass) Nil else { - var context: global.analyzer.Context = global.analyzer.rootContext(NoCompilationUnit) + val context: global.analyzer.Context = global.analyzer.rootContext(NoCompilationUnit) - val results = global.analyzer.allViewsFrom(sym.tpe, context, sym.typeParams) + val results = global.analyzer.allViewsFrom(sym.tpe_*, context, sym.typeParams) var conversions = results.flatMap(result => makeImplicitConversion(sym, result._1, result._2, context, inTpl)) // also keep empty conversions, so they appear in diagrams // conversions = conversions.filter(!_.members.isEmpty) @@ -109,7 +103,7 @@ trait ModelFactoryImplicitSupport { hardcoded.arraySkipConversions.contains(conv.conversionQualifiedName)) // Filter out non-sensical conversions from value types - if (isPrimitiveValueType(sym.tpe)) + if (isPrimitiveValueType(sym.tpe_*)) conversions = conversions.filter((ic: ImplicitConversionImpl) => hardcoded.valueClassFilter(sym.nameString, ic.conversionQualifiedName)) @@ -351,15 +345,6 @@ trait ModelFactoryImplicitSupport { makeRootPackage } - def targetTemplate: Option[TemplateEntity] = toType match { - // @Vlad: I'm being extra conservative in template creation -- I don't want to create templates for complex types - // such as refinement types because the template can't represent the type corectly (a template corresponds to a - // package, class, trait or object) - case t: TypeRef => Some(makeTemplate(t.sym)) - case RefinedType(parents, decls) => None - case _ => error("Scaladoc implicits: Could not create template for: " + toType + " of type " + toType.getClass); None - } - def targetTypeComponents: List[(TemplateEntity, TypeEntity)] = makeParentTypes(toType, None, inTpl) def convertorMethod: Either[MemberEntity, String] = { @@ -387,7 +372,6 @@ trait ModelFactoryImplicitSupport { lazy val memberImpls: List[MemberImpl] = { // Obtain the members inherited by the implicit conversion val memberSyms = toType.members.filter(implicitShouldDocument(_)).toList - val existingSyms = sym.info.members // Debugging part :) debug(sym.nameString + "\n" + "=" * sym.nameString.length()) @@ -424,66 +408,52 @@ trait ModelFactoryImplicitSupport { /* ========================= HELPER METHODS ========================== */ /** * Computes the shadowing table for all the members in the implicit conversions - * @param mbrs All template's members, including usecases and full signature members + * @param members All template's members, including usecases and full signature members * @param convs All the conversions the template takes part in - * @param inTpl the ususal :) + * @param inTpl the usual :) */ - def makeShadowingTable(mbrs: List[MemberImpl], + def makeShadowingTable(members: List[MemberImpl], convs: List[ImplicitConversionImpl], inTpl: DocTemplateImpl): Map[MemberEntity, ImplicitMemberShadowing] = { assert(modelFinished) - var shadowingTable = Map[MemberEntity, ImplicitMemberShadowing]() + val shadowingTable = mutable.Map[MemberEntity, ImplicitMemberShadowing]() + val membersByName: Map[Name, List[MemberImpl]] = members.groupBy(_.sym.name) + val convsByMember = (Map.empty[MemberImpl, ImplicitConversionImpl] /: convs) { + case (map, conv) => map ++ conv.memberImpls.map (_ -> conv) + } for (conv <- convs) { - val otherConvs = convs.filterNot(_ == conv) + val otherConvMembers: Map[Name, List[MemberImpl]] = convs filterNot (_ == conv) flatMap (_.memberImpls) groupBy (_.sym.name) for (member <- conv.memberImpls) { - // for each member in our list val sym1 = member.sym val tpe1 = conv.toType.memberInfo(sym1) - // check if it's shadowed by a member in the original class - var shadowedBySyms: List[Symbol] = List() - for (mbr <- mbrs) { - val sym2 = mbr.sym - if (sym1.name == sym2.name) { - val shadowed = !settings.docImplicitsSoundShadowing.value || { - val tpe2 = inTpl.sym.info.memberInfo(sym2) - !isDistinguishableFrom(tpe1, tpe2) - } - if (shadowed) - shadowedBySyms ::= sym2 - } + // check if it's shadowed by a member in the original class. + val shadowed = membersByName.get(sym1.name).toList.flatten filter { other => + !settings.docImplicitsSoundShadowing.value || !isDistinguishableFrom(tpe1, inTpl.sym.info.memberInfo(other.sym)) } - val shadowedByMembers = mbrs.filter((mb: MemberImpl) => shadowedBySyms.contains(mb.sym)) - - // check if it's shadowed by another member - var ambiguousByMembers: List[MemberEntity] = List() - for (conv <- otherConvs) - for (member2 <- conv.memberImpls) { - val sym2 = member2.sym - if (sym1.name == sym2.name) { - val tpe2 = conv.toType.memberInfo(sym2) - // Ambiguity should be an equivalence relation - val ambiguated = !isDistinguishableFrom(tpe1, tpe2) || !isDistinguishableFrom(tpe2, tpe1) - if (ambiguated) - ambiguousByMembers ::= member2 - } - } + // check if it's shadowed by another conversion. + val ambiguous = otherConvMembers.get(sym1.name).toList.flatten filter { other => + val tpe2 = convsByMember(other).toType.memberInfo(other.sym) + !isDistinguishableFrom(tpe1, tpe2) || !isDistinguishableFrom(tpe2, tpe1) + } // we finally have the shadowing info - val shadowing = new ImplicitMemberShadowing { - def shadowingMembers: List[MemberEntity] = shadowedByMembers - def ambiguatingMembers: List[MemberEntity] = ambiguousByMembers - } + if (!shadowed.isEmpty || !ambiguous.isEmpty) { + val shadowing = new ImplicitMemberShadowing { + def shadowingMembers: List[MemberEntity] = shadowed + def ambiguatingMembers: List[MemberEntity] = ambiguous + } - shadowingTable += (member -> shadowing) + shadowingTable += (member -> shadowing) + } } } - shadowingTable + shadowingTable.toMap } @@ -513,14 +483,14 @@ trait ModelFactoryImplicitSupport { /** * Make implicits explicit - Not used curently */ - object implicitToExplicit extends TypeMap { - def apply(tp: Type): Type = mapOver(tp) match { - case MethodType(params, resultType) => - MethodType(params.map(param => if (param.isImplicit) param.cloneSymbol.resetFlag(Flags.IMPLICIT) else param), resultType) - case other => - other - } - } + // object implicitToExplicit extends TypeMap { + // def apply(tp: Type): Type = mapOver(tp) match { + // case MethodType(params, resultType) => + // MethodType(params.map(param => if (param.isImplicit) param.cloneSymbol.resetFlag(Flags.IMPLICIT) else param), resultType) + // case other => + // other + // } + // } /** * removeImplicitParameters transforms implicit parameters from the view result type into constraints and @@ -608,4 +578,4 @@ trait ModelFactoryImplicitSupport { false } else true // the member structure is different foo(3, 5) vs foo(3)(5) } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala index 942ccaf1ba..1876415f2a 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala @@ -9,13 +9,6 @@ import comment._ import diagram._ import scala.collection._ -import scala.util.matching.Regex - -import symtab.Flags - -import io._ - -import model.{ RootPackage => RootPackageEntity } /** This trait extracts all required information for documentation from compilation units */ trait ModelFactoryTypeSupport { @@ -28,14 +21,11 @@ trait ModelFactoryTypeSupport { import global._ import definitions.{ ObjectClass, NothingClass, AnyClass, AnyValClass, AnyRefClass } - import rootMirror.{ RootPackage, RootClass, EmptyPackage } protected val typeCache = new mutable.LinkedHashMap[Type, TypeEntity] /** */ def makeType(aType: Type, inTpl: TemplateImpl): TypeEntity = { - def templatePackage = closestPackage(inTpl.sym) - def createTypeEntity = new TypeEntity { private var nameBuffer = new StringBuilder private var refBuffer = new immutable.TreeMap[Int, (LinkTo, Int)] @@ -231,7 +221,6 @@ trait ModelFactoryTypeSupport { def appendClauses = { nameBuffer append " forSome {" var first = true - val qset = quantified.toSet for (sym <- quantified) { if (!first) { nameBuffer append ", " } else first = false if (sym.isSingletonExistential) { diff --git a/src/compiler/scala/tools/nsc/doc/model/TreeFactory.scala b/src/compiler/scala/tools/nsc/doc/model/TreeFactory.scala index bd7534ded4..b972649194 100755 --- a/src/compiler/scala/tools/nsc/doc/model/TreeFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/TreeFactory.scala @@ -21,7 +21,7 @@ trait TreeFactory { thisTreeFactory: ModelFactory with TreeFactory => def makeTree(rhs: Tree): Option[TreeEntity] = { - var expr = new StringBuilder + val expr = new StringBuilder var refs = new immutable.TreeMap[Int, (Entity, Int)] // start, (Entity to be linked to , end) rhs.pos match { @@ -39,7 +39,7 @@ trait TreeFactory { thisTreeFactory: ModelFactory with TreeFactory => * stores it in tree.refs with its position */ def makeLink(rhs: Tree){ - var start = pos.startOrPoint - firstIndex + val start = pos.startOrPoint - firstIndex val end = pos.endOrPoint - firstIndex if(start != end) { var asym = rhs.symbol diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala b/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala index 3e5e634e18..8848af95eb 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala @@ -10,8 +10,6 @@ package comment import scala.collection._ -import java.net.URL - /** A body of text. A comment has a single body, which is composed of * at least one block. Inside every body is exactly one summary (see * [[scala.tools.nsc.doc.model.comment.Summary]]). */ diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala b/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala index 3e172544dd..736727fc1a 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala @@ -102,9 +102,6 @@ abstract class Comment { /** A usage example related to the entity. */ def example: List[Body] - /** The comment as it appears in the source text. */ - def source: Option[String] - /** A description for the primary constructor */ def constructor: Option[Body] diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala index 40057bbb52..c798def4cb 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala @@ -8,11 +8,9 @@ package doc package model package comment -import reporters.Reporter import scala.collection._ import scala.util.matching.Regex -import scala.annotation.switch -import scala.reflect.internal.util.{NoPosition, Position} +import scala.reflect.internal.util.Position import scala.language.postfixOps /** The comment parser transforms raw comment strings into `Comment` objects. @@ -30,11 +28,6 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member protected val commentCache = mutable.HashMap.empty[(global.Symbol, TemplateImpl), Comment] - def addCommentBody(sym: global.Symbol, inTpl: TemplateImpl, docStr: String, docPos: global.Position): global.Symbol = { - commentCache += (sym, inTpl) -> parse(docStr, docStr, docPos, None) - sym - } - def comment(sym: global.Symbol, currentTpl: Option[DocTemplateImpl], inTpl: DocTemplateImpl): Option[Comment] = { val key = (sym, inTpl) if (commentCache isDefinedAt key) @@ -134,7 +127,6 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member val note = note0 val example = example0 val constructor = constructor0 - val source = source0 val inheritDiagram = inheritDiagram0 val contentDiagram = contentDiagram0 val groupDesc = groupDesc0 @@ -477,7 +469,6 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member var summaryParsed = false def document(): Body = { - nextChar() val blocks = new mutable.ListBuffer[Block] while (char != endOfText) blocks += block() @@ -559,21 +550,21 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member def code(): Block = { jumpWhitespace() jump("{{{") - readUntil("}}}") + val str = readUntil("}}}") if (char == endOfText) reportError(pos, "unclosed code block") else jump("}}}") blockEnded("code block") - Code(normalizeIndentation(getRead)) + Code(normalizeIndentation(str)) } /** {{{ title ::= ('=' inline '=' | "==" inline "==" | ...) '\n' }}} */ def title(): Block = { jumpWhitespace() - val inLevel = repeatJump("=") + val inLevel = repeatJump('=') val text = inline(check("=" * inLevel)) - val outLevel = repeatJump("=", inLevel) + val outLevel = repeatJump('=', inLevel) if (inLevel != outLevel) reportError(pos, "unbalanced or unclosed heading") blockEnded("heading") @@ -583,7 +574,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member /** {{{ hrule ::= "----" { '-' } '\n' }}} */ def hrule(): Block = { jumpWhitespace() - repeatJump("-") + repeatJump('-') blockEnded("horizontal rule") HorizontalRule() } @@ -621,8 +612,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member } do { - readUntil { char == safeTagMarker || char == endOfText } - val str = getRead() + val str = readUntil { char == safeTagMarker || char == endOfText } nextChar() list += str @@ -660,8 +650,8 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member else if (check(",,")) subscript() else if (check("[[")) link() else { - readUntil { char == safeTagMarker || check("''") || char == '`' || check("__") || char == '^' || check(",,") || check("[[") || isInlineEnd || checkParaEnded || char == endOfLine } - Text(getRead()) + val str = readUntil { char == safeTagMarker || check("''") || char == '`' || check("__") || char == '^' || check(",,") || check("[[") || isInlineEnd || checkParaEnded || char == endOfLine } + Text(str) } } @@ -698,9 +688,8 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member def htmlTag(): HtmlTag = { jump(safeTagMarker) - readUntil(safeTagMarker) + val read = readUntil(safeTagMarker) if (char != endOfText) jump(safeTagMarker) - var read = getRead HtmlTag(read) } @@ -762,14 +751,10 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member def link(): Inline = { val SchemeUri = """([a-z]+:.*)""".r jump("[[") - var parens = 1 - readUntil { parens += 1; !check("[") } - getRead // clear the buffer - val start = "[" * parens + val parens = 2 + repeatJump('[') val stop = "]" * parens //println("link with " + parens + " matching parens") - readUntil { check(stop) || check(" ") } - val target = getRead() + val target = readUntil { check(stop) || check(" ") } val title = if (!check(stop)) Some({ jump(" ") @@ -811,7 +796,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member */ def normalizeIndentation(_code: String): String = { - var code = _code.trim + val code = _code.trim var maxSkip = Integer.MAX_VALUE var crtSkip = 0 var wsArea = true @@ -860,7 +845,6 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member (char == endOfText) || ((char == endOfLine) && { val poff = offset - val pc = char nextChar() // read EOL val ok = { checkSkipInitWhitespace(endOfLine) || @@ -870,7 +854,6 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member checkSkipInitWhitespace('\u003D') } offset = poff - char = pc ok }) } @@ -882,40 +865,31 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member protected sealed class CharReader(buffer: String) { reader => - var char: Char = _ var offset: Int = 0 + def char: Char = + if (offset >= buffer.length) endOfText else buffer charAt offset final def nextChar() { - if (offset >= buffer.length) - char = endOfText - else { - char = buffer charAt offset - offset += 1 - } + offset += 1 } final def check(chars: String): Boolean = { val poff = offset - val pc = char val ok = jump(chars) offset = poff - char = pc ok } def checkSkipInitWhitespace(c: Char): Boolean = { val poff = offset - val pc = char jumpWhitespace() val ok = jump(c) offset = poff - char = pc ok } def checkSkipInitWhitespace(chars: String): Boolean = { val poff = offset - val pc = char jumpWhitespace() val (ok0, chars0) = if (chars.charAt(0) == ' ') @@ -924,20 +898,17 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member (true, chars) val ok = ok0 && jump(chars0) offset = poff - char = pc ok } def countWhitespace: Int = { var count = 0 val poff = offset - val pc = char while (isWhitespace(char) && char != endOfText) { nextChar() count += 1 } offset = poff - char = pc count } @@ -964,38 +935,10 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member index == chars.length } - final def checkedJump(chars: String): Boolean = { - val poff = offset - val pc = char - val ok = jump(chars) - if (!ok) { - offset = poff - char = pc - } - ok - } - - final def repeatJump(chars: String, max: Int): Int = { + final def repeatJump(c: Char, max: Int = Int.MaxValue): Int = { var count = 0 - var more = true - while (more && count < max) { - if (!checkedJump(chars)) - more = false - else - count += 1 - } - count - } - - final def repeatJump(chars: String): Int = { - var count = 0 - var more = true - while (more) { - if (!checkedJump(chars)) - more = false - else - count += 1 - } + while (jump(c) && count < max) + count += 1 count } @@ -1008,20 +951,6 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member count } - final def jumpUntil(chars: String): Int = { - assert(chars.length > 0) - var count = 0 - val c = chars.charAt(0) - while (!check(chars) && char != endOfText) { - nextChar() - while (char != c && char != endOfText) { - nextChar() - count += 1 - } - } - count - } - final def jumpUntil(pred: => Boolean): Int = { var count = 0 while (!pred && char != endOfText) { @@ -1035,47 +964,41 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member /* READERS */ - private val readBuilder = new mutable.StringBuilder - - final def getRead(): String = { - val bld = readBuilder.toString - readBuilder.clear() - if (bld.length < 6) bld.intern else bld - } - - final def readUntil(ch: Char): Int = { - var count = 0 - while (char != ch && char != endOfText) { - readBuilder += char - nextChar() + final def readUntil(c: Char): String = { + withRead { + while (char != c && char != endOfText) { + nextChar() + } } - count } - final def readUntil(chars: String): Int = { + final def readUntil(chars: String): String = { assert(chars.length > 0) - var count = 0 - val c = chars.charAt(0) - while (!check(chars) && char != endOfText) { - readBuilder += char - nextChar() - while (char != c && char != endOfText) { - readBuilder += char + withRead { + val c = chars.charAt(0) + while (!check(chars) && char != endOfText) { nextChar() + while (char != c && char != endOfText) + nextChar() } } - count } - final def readUntil(pred: => Boolean): Int = { - var count = 0 - while (!pred && char != endOfText) { - readBuilder += char - nextChar() + final def readUntil(pred: => Boolean): String = { + withRead { + while (char != endOfText && !pred) { + nextChar() + } } - count } + private def withRead(read: => Unit): String = { + val start = offset + read + buffer.substring(start, offset) + } + + /* CHARS CLASSES */ def isWhitespace(c: Char) = c == ' ' || c == '\t' diff --git a/src/compiler/scala/tools/nsc/doc/model/diagram/Diagram.scala b/src/compiler/scala/tools/nsc/doc/model/diagram/Diagram.scala index c2aa1f17f3..150b293b81 100644 --- a/src/compiler/scala/tools/nsc/doc/model/diagram/Diagram.scala +++ b/src/compiler/scala/tools/nsc/doc/model/diagram/Diagram.scala @@ -36,20 +36,12 @@ case class InheritanceDiagram(thisNode: ThisNode, override def isInheritanceDiagram = true lazy val depthInfo = new DepthInfo { def maxDepth = 3 - def nodeDepth(node: Node) = - if (node == thisNode) 1 - else if (superClasses.contains(node)) 0 - else if (subClasses.contains(node)) 2 - else if (incomingImplicits.contains(node) || outgoingImplicits.contains(node)) 1 - else -1 } } trait DepthInfo { /** Gives the maximum depth */ def maxDepth: Int - /** Gives the depth of any node in the diagram or -1 if the node is not in the diagram */ - def nodeDepth(node: Node): Int } abstract class Node { @@ -142,5 +134,4 @@ class ContentDiagramDepth(pack: ContentDiagram) extends DepthInfo { } val maxDepth = _maxDepth - def nodeDepth(node: Node) = _nodeDepth.getOrElse(node, -1) -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala index 49cfaffc2e..fbf6e3386b 100644 --- a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala +++ b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala @@ -7,9 +7,6 @@ import comment.CommentFactory import java.util.regex.{Pattern, Matcher} import scala.util.matching.Regex -// statistics -import html.page.diagram.DiagramStats - /** * This trait takes care of parsing @{inheritance, content}Diagram annotations * @@ -154,7 +151,6 @@ trait DiagramDirectiveParser { private val NodeSpecRegex = "\\\"[A-Za-z\\*][A-Za-z\\.\\*]*\\\"" private val NodeSpecPattern = Pattern.compile(NodeSpecRegex) private val EdgeSpecRegex = "\\(" + NodeSpecRegex + "\\s*\\->\\s*" + NodeSpecRegex + "\\)" - private val EdgeSpecPattern = Pattern.compile(NodeSpecRegex) // And the composed regexes: private val HideNodesRegex = new Regex("^hideNodes(\\s*" + NodeSpecRegex + ")+$") private val HideEdgesRegex = new Regex("^hideEdges(\\s*" + EdgeSpecRegex + ")+$") @@ -183,7 +179,7 @@ trait DiagramDirectiveParser { def warning(message: String) = { // we need the position from the package object (well, ideally its comment, but yeah ...) val sym = if (template.sym.isPackage) template.sym.info.member(global.nme.PACKAGE) else template.sym - assert((sym != global.NoSymbol) || (sym == global.definitions.RootPackage)) + assert((sym != global.NoSymbol) || (sym == global.rootMirror.RootPackage)) global.reporter.warning(sym.pos, message) } @@ -259,4 +255,4 @@ trait DiagramDirectiveParser { result } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala index db2d0c0175..849a2ac4b3 100644 --- a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala @@ -4,7 +4,6 @@ package diagram import model._ import comment.CommentFactory -import scala.collection.mutable // statistics import html.page.diagram.DiagramStats @@ -48,7 +47,7 @@ trait DiagramFactory extends DiagramDirectiveParser { val thisNode = ThisNode(tpl.resultType, Some(tpl))(Some(tpl.qualifiedName + " (this " + tpl.kind + ")")) // superclasses - var superclasses: List[Node] = + val superclasses: List[Node] = tpl.parentTypes.collect { case p: (TemplateEntity, TypeEntity) if !classExcluded(p._1) => NormalNode(p._2, Some(p._1))() }.reverse diff --git a/src/compiler/scala/tools/nsc/interactive/BuildManager.scala b/src/compiler/scala/tools/nsc/interactive/BuildManager.scala index 3e7ac573e9..6b72eb12f8 100644 --- a/src/compiler/scala/tools/nsc/interactive/BuildManager.scala +++ b/src/compiler/scala/tools/nsc/interactive/BuildManager.scala @@ -7,11 +7,6 @@ package scala.tools.nsc package interactive import scala.collection._ - -import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} -import scala.reflect.internal.util.FakePos - -import dependencies._ import io.AbstractFile import scala.language.implicitConversions @@ -20,9 +15,6 @@ trait BuildManager { /** Add the given source files to the managed build process. */ def addSourceFiles(files: Set[AbstractFile]) - /** Remove the given files from the managed build process. */ - def removeFiles(files: Set[AbstractFile]) - /** The given files have been modified by the user. Recompile * them and their dependent files. */ @@ -76,8 +68,6 @@ object BuildManagerTest extends EvalLoop { val settings = new Settings(buildError) settings.Ybuildmanagerdebug.value = true val command = new CompilerCommand(args.toList, settings) -// settings.make.value = "off" -// val buildManager: BuildManager = new SimpleBuildManager(settings) val buildManager: BuildManager = new RefinedBuildManager(settings) buildManager.addSourceFiles(command.files) diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index b4af8f00d6..f3cd41f32f 100644 --- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala @@ -7,8 +7,6 @@ package interactive import scala.util.control.ControlThrowable import scala.tools.nsc.io.AbstractFile -import scala.tools.nsc.symtab._ -import scala.tools.nsc.ast._ import scala.tools.nsc.util.FailedInterrupt import scala.tools.nsc.util.EmptyAction import scala.tools.nsc.util.WorkScheduler diff --git a/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala b/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala index b2568e34bd..93ef4c4d6c 100644 --- a/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala +++ b/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala @@ -6,7 +6,6 @@ package scala.tools.nsc package interactive import scala.collection.mutable.ArrayBuffer -import scala.reflect.internal.util.Position trait ContextTrees { self: Global => diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index 2ab389445f..e4bff1e192 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -8,17 +8,13 @@ package interactive import java.io.{ PrintWriter, StringWriter, FileReader, FileWriter } import scala.collection.mutable import mutable.{LinkedHashMap, SynchronizedMap, HashSet, SynchronizedSet} -import scala.concurrent.SyncVar import scala.util.control.ControlThrowable import scala.tools.nsc.io.{ AbstractFile, LogReplay, Logger, NullLogger, Replayer } -import scala.tools.nsc.util.{ WorkScheduler, MultiHashMap } +import scala.tools.nsc.util.MultiHashMap import scala.reflect.internal.util.{ SourceFile, BatchSourceFile, Position, RangePosition, NoPosition } import scala.tools.nsc.reporters._ import scala.tools.nsc.symtab._ -import scala.tools.nsc.ast._ -import scala.tools.nsc.io.Pickler._ import scala.tools.nsc.typechecker.DivergentImplicit -import scala.annotation.tailrec import symtab.Flags.{ACCESSOR, PARAMACCESSOR} import scala.annotation.elidable import scala.language.implicitConversions @@ -361,7 +357,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") } // don't forget to service interrupt requests - val iqs = scheduler.dequeueAllInterrupts(_.execute()) + scheduler.dequeueAllInterrupts(_.execute()) debugLog("ShutdownReq: cleaning work queue (%d items)".format(units.size)) debugLog("Cleanup up responses (%d loadedType pending, %d parsedEntered pending)" @@ -399,41 +395,6 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") if (typerRun != currentTyperRun) demandNewCompilerRun() } - def debugInfo(source : SourceFile, start : Int, length : Int): String = { - println("DEBUG INFO "+source+"/"+start+"/"+length) - val end = start+length - val pos = rangePos(source, start, start, end) - - val tree = locateTree(pos) - val sw = new StringWriter - val pw = new PrintWriter(sw) - newTreePrinter(pw).print(tree) - pw.flush - - val typed = new Response[Tree] - askTypeAt(pos, typed) - val typ = typed.get.left.toOption match { - case Some(tree) => - val sw = new StringWriter - val pw = new PrintWriter(sw) - newTreePrinter(pw).print(tree) - pw.flush - sw.toString - case None => "<None>" - } - - val completionResponse = new Response[List[Member]] - askTypeCompletion(pos, completionResponse) - val completion = completionResponse.get.left.toOption match { - case Some(members) => - members mkString "\n" - case None => "<None>" - } - - source.content.view.drop(start).take(length).mkString+" : "+source.path+" ("+start+", "+end+ - ")\n\nlocateTree:\n"+sw.toString+"\n\naskTypeAt:\n"+typ+"\n\ncompletion:\n"+completion - } - // ----------------- The Background Runner Thread ----------------------- private var threadId = 0 @@ -1059,7 +1020,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") } @deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0") - def getInstrumented(source: SourceFile, line: Int, response: Response[(String, Array[Char])]) = + def getInstrumented(source: SourceFile, line: Int, response: Response[(String, Array[Char])]) { try { interruptsEnabled = false respond(response) { @@ -1068,6 +1029,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") } finally { interruptsEnabled = true } + } // ---------------- Helper classes --------------------------- @@ -1099,7 +1061,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") * @return true iff typechecked correctly */ private def applyPhase(phase: Phase, unit: CompilationUnit) { - atPhase(phase) { phase.asInstanceOf[GlobalPhase] applyPhase unit } + enteringPhase(phase) { phase.asInstanceOf[GlobalPhase] applyPhase unit } } } diff --git a/src/compiler/scala/tools/nsc/interactive/Picklers.scala b/src/compiler/scala/tools/nsc/interactive/Picklers.scala index ffad19fbaa..1dc891b984 100644 --- a/src/compiler/scala/tools/nsc/interactive/Picklers.scala +++ b/src/compiler/scala/tools/nsc/interactive/Picklers.scala @@ -6,12 +6,10 @@ package scala.tools.nsc package interactive import util.InterruptReq -import scala.reflect.internal.util.{SourceFile, BatchSourceFile} -import io.{AbstractFile, PlainFile} - +import scala.reflect.internal.util.{ SourceFile, BatchSourceFile } +import io.{ AbstractFile, PlainFile, Pickler, CondPickler } import util.EmptyAction -import scala.reflect.internal.util.{Position, RangePosition, NoPosition, OffsetPosition, TransparentPosition} -import io.{Pickler, CondPickler} +import scala.reflect.internal.util.{ RangePosition, OffsetPosition, TransparentPosition } import io.Pickler._ import scala.collection.mutable import mutable.ListBuffer diff --git a/src/compiler/scala/tools/nsc/interactive/REPL.scala b/src/compiler/scala/tools/nsc/interactive/REPL.scala index dacfa679dd..d1a29aeb07 100644 --- a/src/compiler/scala/tools/nsc/interactive/REPL.scala +++ b/src/compiler/scala/tools/nsc/interactive/REPL.scala @@ -5,15 +5,11 @@ package scala.tools.nsc package interactive -import scala.concurrent.SyncVar import scala.reflect.internal.util._ -import scala.tools.nsc.symtab._ -import scala.tools.nsc.ast._ import scala.tools.nsc.reporters._ import scala.tools.nsc.io._ import scala.tools.nsc.scratchpad.SourceInserter -import scala.tools.nsc.interpreter.AbstractFileClassLoader -import java.io.{File, FileWriter} +import java.io.FileWriter /** Interface of interactive compiler to a client such as an IDE */ diff --git a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala index b95f1fa7ca..ecaa793da7 100644 --- a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala +++ b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala @@ -8,7 +8,6 @@ package interactive import ast.Trees import ast.Positions import scala.reflect.internal.util.{SourceFile, Position, RangePosition, NoPosition} -import scala.tools.nsc.util.WorkScheduler import scala.collection.mutable.ListBuffer /** Handling range positions @@ -60,7 +59,7 @@ self: scala.tools.nsc.Global => } // -------------- ensuring no overlaps ------------------------------- - + /** Ensure that given tree has no positions that overlap with * any of the positions of `others`. This is done by * shortening the range, assigning TransparentPositions diff --git a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala index b2ef45a7d8..9873276f05 100644 --- a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala +++ b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala @@ -12,7 +12,6 @@ import scala.util.control.Breaks._ import scala.tools.nsc.symtab.Flags import dependencies._ -import scala.reflect.internal.util.FakePos import util.ClassPath import io.AbstractFile import scala.tools.util.PathResolver @@ -49,7 +48,7 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana protected def newCompiler(settings: Settings) = new BuilderGlobal(settings) val compiler = newCompiler(settings) - import compiler.{ Symbol, Type, beforeErasure } + import compiler.{ Symbol, Type, enteringErasure } import compiler.dependencyAnalysis.Inherited private case class SymWithHistory(sym: Symbol, befErasure: Type) @@ -69,7 +68,7 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana private var inherited: mutable.Map[AbstractFile, immutable.Set[Inherited]] = _ /** Reverse of definitions, used for caching */ - private var classes: mutable.Map[String, AbstractFile] = + private val classes: mutable.Map[String, AbstractFile] = new mutable.HashMap[String, AbstractFile] { override def default(key: String) = null } @@ -161,7 +160,7 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana isCorrespondingSym(s.sym, sym)) match { case Some(SymWithHistory(oldSym, info)) => val changes = changeSet(oldSym.info, sym) - val changesErasure = beforeErasure(changeSet(info, sym)) + val changesErasure = enteringErasure(changeSet(info, sym)) changesOf(oldSym) = (changes ++ changesErasure).distinct case _ => @@ -332,7 +331,7 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana for (src <- files; localDefs = compiler.dependencyAnalysis.definitions(src)) { definitions(src) = (localDefs map (s => { this.classes += s.fullName -> src - SymWithHistory(s.cloneSymbol, beforeErasure(s.info.cloneInfo(s))) + SymWithHistory(s.cloneSymbol, enteringErasure(s.info.cloneInfo(s))) })) } this.references = compiler.dependencyAnalysis.references diff --git a/src/compiler/scala/tools/nsc/interactive/SimpleBuildManager.scala b/src/compiler/scala/tools/nsc/interactive/SimpleBuildManager.scala index 465dcaaf1c..ff25dac7ac 100644 --- a/src/compiler/scala/tools/nsc/interactive/SimpleBuildManager.scala +++ b/src/compiler/scala/tools/nsc/interactive/SimpleBuildManager.scala @@ -8,9 +8,6 @@ package interactive import scala.collection._ import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} -import dependencies._ - -import scala.reflect.internal.util.FakePos import io.AbstractFile /** A simple build manager, using the default scalac dependency tracker. diff --git a/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTest.scala b/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTest.scala index 62d274bc70..f2614bcc42 100644 --- a/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTest.scala +++ b/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTest.scala @@ -7,14 +7,6 @@ package interactive package tests import core._ - -import java.io.File.pathSeparatorChar -import java.io.File.separatorChar - -import scala.annotation.migration -import scala.reflect.internal.util.Position -import scala.reflect.internal.util.SourceFile - import scala.collection.mutable.ListBuffer /** A base class for writing interactive compiler tests. @@ -110,6 +102,7 @@ abstract class InteractiveTest } /** Perform n random tests with random changes. */ + /**** private def randomTests(n: Int, files: Array[SourceFile]) { val tester = new Tester(n, files, settings) { override val compiler = self.compiler @@ -117,6 +110,7 @@ abstract class InteractiveTest } tester.run() } + ****/ /** shutdown the presentation compiler. */ protected def shutdown() { diff --git a/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTestSettings.scala b/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTestSettings.scala index 4d85ab9d88..ad5c61b2b0 100644 --- a/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTestSettings.scala +++ b/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTestSettings.scala @@ -25,7 +25,6 @@ trait InteractiveTestSettings extends TestSettings with PresentationCompilerInst * test. */ override protected def prepareSettings(settings: Settings) { - import java.io.File._ def adjustPaths(paths: settings.PathSetting*) { for (p <- paths if argsString.contains(p.name)) p.value = p.value.map { case '/' => separatorChar @@ -45,10 +44,10 @@ trait InteractiveTestSettings extends TestSettings with PresentationCompilerInst case _ => () } - // Make the --sourcepath path provided in the .flags file (if any) relative to the test's base directory + // Make the --sourcepath path provided in the .flags file (if any) relative to the test's base directory if(settings.sourcepath.isSetByUser) settings.sourcepath.value = (baseDir / Path(settings.sourcepath.value)).path - + adjustPaths(settings.bootclasspath, settings.classpath, settings.javabootclasspath, settings.sourcepath) } @@ -67,4 +66,4 @@ trait InteractiveTestSettings extends TestSettings with PresentationCompilerInst reporter.println("\targsString: %s".format(argsString)) super.printClassPath(reporter) } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala b/src/compiler/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala index c8e6b6ccce..9085eb56e6 100644 --- a/src/compiler/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala +++ b/src/compiler/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala @@ -3,7 +3,6 @@ package interactive package tests.core import scala.reflect.internal.util.Position -import scala.tools.nsc.interactive.tests.core._ /** Set of core test definitions that are executed for each test run. */ private[tests] trait CoreTestDefs @@ -77,7 +76,8 @@ private[tests] trait CoreTestDefs // askHyperlinkPos for `Int` at (73,19) pi.scala --> class Int in package scala has null sourceFile! val treePath = if (tree.symbol.sourceFile ne null) tree.symbol.sourceFile.path else null val treeName = if (tree.symbol.sourceFile ne null) tree.symbol.sourceFile.name else null - val sourceFile = sourceFiles.find(_.path == treePath) match { + + sourceFiles.find(_.path == treePath) match { case Some(source) => compiler.askLinkPos(tree.symbol, source, r) r.get match { @@ -97,4 +97,4 @@ private[tests] trait CoreTestDefs } } } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala b/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala index 5c1837b3bf..b3f80168ff 100644 --- a/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala +++ b/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala @@ -3,7 +3,6 @@ package interactive package tests.core import reporters.{Reporter => CompilerReporter} -import scala.reflect.internal.util.Position /** Trait encapsulating the creation of a presentation compiler's instance.*/ private[tests] trait PresentationCompilerInstance extends TestSettings { @@ -28,4 +27,4 @@ private[tests] trait PresentationCompilerInstance extends TestSettings { reporter.println("\tbootClassPath: %s".format(settings.bootclasspath.value)) reporter.println("\tverbose: %b".format(settings.verbose.value)) } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerTestDef.scala b/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerTestDef.scala index 9cf2aa4fe4..4d5b4e1129 100644 --- a/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerTestDef.scala +++ b/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerTestDef.scala @@ -1,6 +1,5 @@ package scala.tools.nsc.interactive.tests.core -import scala.tools.nsc.interactive.Global import scala.reflect.internal.util.Position trait PresentationCompilerTestDef { @@ -16,4 +15,4 @@ trait PresentationCompilerTestDef { protected def format(pos: Position): String = (if(pos.isDefined) "(%d,%d)".format(pos.line, pos.column) else "<no position>") -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/interactive/tests/core/SourcesCollector.scala b/src/compiler/scala/tools/nsc/interactive/tests/core/SourcesCollector.scala index e80b741a8d..676feeba8a 100644 --- a/src/compiler/scala/tools/nsc/interactive/tests/core/SourcesCollector.scala +++ b/src/compiler/scala/tools/nsc/interactive/tests/core/SourcesCollector.scala @@ -4,7 +4,6 @@ import scala.reflect.internal.util.{SourceFile,BatchSourceFile} import scala.tools.nsc.io.{AbstractFile,Path} private[tests] object SourcesCollector { - import Path._ type SourceFilter = Path => Boolean /** @@ -17,6 +16,5 @@ private[tests] object SourcesCollector { } private def source(file: Path): SourceFile = source(AbstractFile.getFile(file.toFile)) - private def source(filename: String): SourceFile = source(AbstractFile.getFile(filename)) private def source(file: AbstractFile): SourceFile = new BatchSourceFile(file) -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala index 638bca8a72..fcb485defd 100644 --- a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala +++ b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala @@ -5,7 +5,7 @@ package scala.tools.nsc package interpreter -import scala.tools.nsc.io.{ File, AbstractFile } +import scala.tools.nsc.io.AbstractFile import util.ScalaClassLoader import java.net.URL import scala.collection.{ mutable, immutable } diff --git a/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala b/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala index 40e9d3d600..48890a21c6 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala @@ -7,7 +7,6 @@ package scala.tools.nsc package interpreter import java.lang.reflect -import java.util.concurrent.ConcurrentHashMap import util.ScalaClassLoader import ScalaClassLoader.appLoader import scala.reflect.NameTransformer._ @@ -39,25 +38,5 @@ object ByteCode { } yield names - /** Attempts to retrieve case parameter names for given class name. - */ - def caseParamNamesForPath(path: String) = - for { - module <- DECODER - method <- decoderMethod("caseParamNames", classOf[String]) - names <- method.invoke(module, path).asInstanceOf[Option[List[String]]] - } - yield names - def aliasesForPackage(pkg: String) = aliasMap flatMap (_(pkg)) - - /** Attempts to find type aliases in package objects. - */ - def aliasForType(path: String): Option[String] = { - val (pkg, name) = (path lastIndexOf '.') match { - case -1 => return None - case idx => (path take idx, path drop (idx + 1)) - } - aliasesForPackage(pkg) flatMap (_ get name) - } } diff --git a/src/compiler/scala/tools/nsc/interpreter/CodeHandlers.scala b/src/compiler/scala/tools/nsc/interpreter/CodeHandlers.scala deleted file mode 100644 index 1741a82775..0000000000 --- a/src/compiler/scala/tools/nsc/interpreter/CodeHandlers.scala +++ /dev/null @@ -1,50 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package interpreter - -import CodeHandlers.NoSuccess -import scala.util.control.ControlThrowable - -/** - * The start of a simpler interface for utilizing the compiler with piecemeal - * code strings. The "T" here could potentially be a Tree, a Type, a Symbol, - * a Boolean, or something even more exotic. - */ -trait CodeHandlers[T] { - self => - - // Expressions are composed of operators and operands. - def expr(code: String): T - - // Statements occur as parts of blocks and templates. - // A statement can be an import, a definition or an expression, or it can be empty. - // Statements used in the template of a class definition can also be declarations. - def stmt(code: String): T - def stmts(code: String): Seq[T] - - object opt extends CodeHandlers[Option[T]] { - val handler: PartialFunction[Throwable, Option[T]] = { - case _: NoSuccess => None - } - val handlerSeq: PartialFunction[Throwable, Seq[Option[T]]] = { - case _: NoSuccess => Nil - } - - def expr(code: String) = try Some(self.expr(code)) catch handler - def stmt(code: String) = try Some(self.stmt(code)) catch handler - def stmts(code: String) = try (self.stmts(code) map (x => Some(x))) catch handlerSeq - } -} - -object CodeHandlers { - def incomplete() = throw CodeIncomplete - def fail(msg: String) = throw new CodeException(msg) - - trait NoSuccess extends ControlThrowable - class CodeException(msg: String) extends RuntimeException(msg) with NoSuccess { } - object CodeIncomplete extends CodeException("CodeIncomplete") -} diff --git a/src/compiler/scala/tools/nsc/interpreter/CommandLine.scala b/src/compiler/scala/tools/nsc/interpreter/CommandLine.scala index 8042f0aee2..0ab92ab769 100644 --- a/src/compiler/scala/tools/nsc/interpreter/CommandLine.scala +++ b/src/compiler/scala/tools/nsc/interpreter/CommandLine.scala @@ -10,5 +10,4 @@ package interpreter */ class CommandLine(arguments: List[String], error: String => Unit) extends CompilerCommand(arguments, error) { override def cmdName = "scala" - override lazy val fileEndings = List(".scalaint") } diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala index 1dfccbfbf7..84a5cb49ae 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Completion.scala @@ -23,8 +23,6 @@ object NoCompletion extends Completion { } object Completion { - def empty: Completion = NoCompletion - case class Candidates(cursor: Int, candidates: List[String]) { } val NoCandidates = Candidates(-1, Nil) diff --git a/src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala b/src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala index ab96f415db..3dd5d93390 100644 --- a/src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala +++ b/src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala @@ -6,8 +6,6 @@ package scala.tools.nsc package interpreter -import scala.reflect.NameTransformer - /** An interface for objects which are aware of tab completion and * will supply their own candidates and resolve their own paths. */ @@ -53,31 +51,3 @@ trait CompletionAware { results.sorted } } - -object CompletionAware { - val Empty = new CompletionAware { def completions(verbosity: Int) = Nil } - - def unapply(that: Any): Option[CompletionAware] = that match { - case x: CompletionAware => Some((x)) - case _ => None - } - - /** Create a CompletionAware object from the given functions. - * The first should generate the list of completions whenever queried, - * and the second should return Some(CompletionAware) object if - * subcompletions are possible. - */ - def apply(terms: () => List[String], followFunction: String => Option[CompletionAware]): CompletionAware = - new CompletionAware { - def completions = terms() - def completions(verbosity: Int) = completions - override def follow(id: String) = followFunction(id) - } - - /** Convenience factories. - */ - def apply(terms: () => List[String]): CompletionAware = apply(terms, _ => None) - def apply(map: scala.collection.Map[String, CompletionAware]): CompletionAware = - apply(() => map.keys.toList, map.get _) -} - diff --git a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala index 13880bb8af..c647ef6f51 100644 --- a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala +++ b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala @@ -38,7 +38,6 @@ trait CompletionOutput { def relativize(str: String): String = quietString(str stripPrefix (pkg + ".")) def relativize(tp: Type): String = relativize(tp.normalize.toString) - def relativize(sym: Symbol): String = relativize(sym.info) def braceList(tparams: List[String]) = if (tparams.isEmpty) "" else (tparams map relativize).mkString("[", ", ", "]") def parenList(params: List[Any]) = params.mkString("(", ", ", ")") diff --git a/src/compiler/scala/tools/nsc/interpreter/ConsoleReaderHelper.scala b/src/compiler/scala/tools/nsc/interpreter/ConsoleReaderHelper.scala index 07e36f4f27..48af261937 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ConsoleReaderHelper.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ConsoleReaderHelper.scala @@ -7,19 +7,12 @@ package scala.tools.nsc package interpreter import scala.tools.jline.console.{ ConsoleReader, CursorBuffer } -import scala.tools.jline.console.completer.CompletionHandler -import Completion._ trait ConsoleReaderHelper extends ConsoleReader { - def currentLine = "" + getCursorBuffer.buffer - def currentPos = getCursorBuffer.cursor def terminal = getTerminal() def width = terminal.getWidth() def height = terminal.getHeight() - def paginate = isPaginationEnabled() - def paginate_=(value: Boolean) = setPaginationEnabled(value) - def goBack(num: Int): Unit def readOneKey(prompt: String): Int def eraseLine(): Unit diff --git a/src/compiler/scala/tools/nsc/interpreter/Delimited.scala b/src/compiler/scala/tools/nsc/interpreter/Delimited.scala index 80debfacb9..e88a044931 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Delimited.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Delimited.scala @@ -26,7 +26,6 @@ trait Delimited { def delimited: Char => Boolean def escapeChars: List[Char] = List('\\') - def quoteChars: List[(Char, Char)] = List(('\'', '\''), ('"', '"')) /** Break String into args based on delimiting function. */ @@ -39,6 +38,4 @@ trait Delimited { def isDelimiterChar(ch: Char) = delimited(ch) def isEscapeChar(ch: Char): Boolean = escapeChars contains ch - def isQuoteStart(ch: Char): Boolean = quoteChars map (_._1) contains ch - def isQuoteEnd(ch: Char): Boolean = quoteChars map (_._2) contains ch } diff --git a/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala b/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala index c4a672ac37..b087547cf8 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala @@ -6,7 +6,6 @@ package scala.tools.nsc package interpreter -import scala.reflect.internal.util.BatchSourceFile import scala.tools.nsc.ast.parser.Tokens.EOF trait ExprTyper { @@ -15,10 +14,11 @@ trait ExprTyper { import repl._ import global.{ reporter => _, Import => _, _ } import definitions._ - import syntaxAnalyzer.{ UnitParser, UnitScanner, token2name } + import syntaxAnalyzer.UnitParser import naming.freshInternalVarName - object codeParser extends { val global: repl.global.type = repl.global } with CodeHandlers[Tree] { + object codeParser { + val global: repl.global.type = repl.global def applyRule[T](code: String, rule: UnitParser => T): T = { reporter.reset() val scanner = newUnitParser(code) @@ -29,11 +29,7 @@ trait ExprTyper { result } - - def defns(code: String) = stmts(code) collect { case x: DefTree => x } - def expr(code: String) = applyRule(code, _.expr()) def stmts(code: String) = applyRule(code, _.templateStats()) - def stmt(code: String) = stmts(code).last // guaranteed nonempty } /** Parse a line into a sequence of trees. Returns None if the input is incomplete. */ @@ -46,10 +42,6 @@ trait ExprTyper { else Some(trees) } } - // def parsesAsExpr(line: String) = { - // import codeParser._ - // (opt expr line).isDefined - // } def symbolOfLine(code: String): Symbol = { def asExpr(): Symbol = { @@ -63,7 +55,7 @@ trait ExprTyper { case IR.Success => val sym0 = symbolOfTerm(name) // drop NullaryMethodType - val sym = sym0.cloneSymbol setInfo afterTyper(sym0.info.finalResultType) + val sym = sym0.cloneSymbol setInfo exitingTyper(sym0.info.finalResultType) if (sym.info.typeSymbol eq UnitClass) NoSymbol else sym case _ => NoSymbol diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala index b7e07ecdd6..612a90f3ea 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala @@ -8,24 +8,20 @@ package interpreter import Predef.{ println => _, _ } import java.io.{ BufferedReader, FileReader } -import java.util.concurrent.locks.ReentrantLock -import scala.sys.process.Process import session._ -import scala.util.Properties.{ jdkHome, javaVersion } -import scala.tools.util.{ Javap } import scala.annotation.tailrec -import scala.collection.mutable.ListBuffer -import scala.concurrent.ops +import scala.util.Properties.{ jdkHome, javaVersion, versionString, javaVmName } +import scala.tools.util.{ Javap } import util.{ ClassPath, Exceptional, stringFromWriter, stringFromStream } -import interpreter._ import io.{ File, Directory } -import scala.reflect.NameTransformer._ import util.ScalaClassLoader import ScalaClassLoader._ import scala.tools.util._ import scala.language.{implicitConversions, existentials} -import scala.reflect.{ClassTag, classTag} +import scala.reflect.classTag import scala.tools.reflect.StdRuntimeTags._ +import scala.concurrent.{ ExecutionContext, Await, Future, future } +import ExecutionContext.Implicits._ /** The Scala interactive shell. It provides a read-eval-print loop * around the Interpreter class. @@ -42,77 +38,41 @@ import scala.tools.reflect.StdRuntimeTags._ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) extends AnyRef with LoopCommands - with ILoopInit { def this(in0: BufferedReader, out: JPrintWriter) = this(Some(in0), out) def this() = this(None, new JPrintWriter(Console.out, true)) - var in: InteractiveReader = _ // the input stream from which commands come - var settings: Settings = _ - var intp: IMain = _ - @deprecated("Use `intp` instead.", "2.9.0") def interpreter = intp @deprecated("Use `intp` instead.", "2.9.0") def interpreter_= (i: Interpreter): Unit = intp = i - /** Having inherited the difficult "var-ness" of the repl instance, - * I'm trying to work around it by moving operations into a class from - * which it will appear a stable prefix. - */ - private def onIntp[T](f: IMain => T): T = f(intp) - - class IMainOps[T <: IMain](val intp: T) { - import intp._ - import global._ - - def printAfterTyper(msg: => String) = - intp.reporter printUntruncatedMessage afterTyper(msg) - - /** Strip NullaryMethodType artifacts. */ - private def replInfo(sym: Symbol) = { - sym.info match { - case NullaryMethodType(restpe) if sym.isAccessor => restpe - case info => info - } - } - def echoTypeStructure(sym: Symbol) = - printAfterTyper("" + deconstruct.show(replInfo(sym))) + var in: InteractiveReader = _ // the input stream from which commands come + var settings: Settings = _ + var intp: IMain = _ - def echoTypeSignature(sym: Symbol, verbose: Boolean) = { - if (verbose) ILoop.this.echo("// Type signature") - printAfterTyper("" + replInfo(sym)) + private var globalFuture: Future[Boolean] = _ - if (verbose) { - ILoop.this.echo("\n// Internal Type structure") - echoTypeStructure(sym) - } - } + /** Print a welcome message */ + def printWelcome() { + echo(s""" + |Welcome to Scala $versionString ($javaVmName, Java $javaVersion). + |Type in expressions to have them evaluated. + |Type :help for more information.""".trim.stripMargin + ) + replinfo("[info] started at " + new java.util.Date) } - implicit def stabilizeIMain(intp: IMain) = new IMainOps[intp.type](intp) - /** TODO - - * -n normalize - * -l label with case class parameter names - * -c complete - leave nothing out - */ - private def typeCommandInternal(expr: String, verbose: Boolean): Result = { - onIntp { intp => - val sym = intp.symbolOfLine(expr) - if (sym.exists) intp.echoTypeSignature(sym, verbose) - else "" - } + protected def asyncMessage(msg: String) { + if (isReplInfo || isReplPower) + echoAndRefresh(msg) } override def echoCommandMessage(msg: String) { intp.reporter printUntruncatedMessage msg } - def isAsync = !settings.Yreplsync.value lazy val power = new Power(intp, new StdReplVals(this))(tagOfStdReplVals, classTag[StdReplVals]) def history = in.history - /** The context class loader at the time this object was created */ - protected val originalClassLoader = Thread.currentThread.getContextClassLoader - // classpath entries added via :cp var addedClasspath: String = "" @@ -166,20 +126,18 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) def helpCommand(line: String): Result = { if (line == "") helpSummary() else uniqueCommand(line) match { - case Some(lc) => echo("\n" + lc.longHelp) + case Some(lc) => echo("\n" + lc.help) case _ => ambiguousError(line) } } private def helpSummary() = { val usageWidth = commands map (_.usageMsg.length) max - val formatStr = "%-" + usageWidth + "s %s %s" + val formatStr = "%-" + usageWidth + "s %s" echo("All commands can be abbreviated, e.g. :he instead of :help.") - echo("Those marked with a * have more detailed help, e.g. :help imports.\n") commands foreach { cmd => - val star = if (cmd.hasLongHelp) "*" else " " - echo(formatStr.format(cmd.usageMsg, star, cmd.help)) + echo(formatStr.format(cmd.usageMsg, cmd.help)) } } private def ambiguousError(cmd: String): Result = { @@ -229,10 +187,6 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) out println msg out.flush() } - protected def echoNoNL(msg: String) = { - out print msg - out.flush() - } /** Search the history */ def searchHistory(_cmdline: String) { @@ -243,8 +197,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) echo("%d %s".format(index + offset, line)) } - private var currentPrompt = Properties.shellPromptString - def setPrompt(prompt: String) = currentPrompt = prompt + private val currentPrompt = Properties.shellPromptString + /** Prompt to print when awaiting input */ def prompt = currentPrompt @@ -257,7 +211,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) historyCommand, cmd("h?", "<string>", "search the history", searchHistory), cmd("imports", "[name name ...]", "show import history, identifying sources of names", importsCommand), - cmd("implicits", "[-v]", "show the implicits in scope", implicitsCommand), + cmd("implicits", "[-v]", "show the implicits in scope", intp.implicitsCommand), cmd("javap", "<path|class>", "disassemble a file or class name", javapCommand), cmd("load", "<path>", "load and interpret a Scala file", loadCommand), nullary("paste", "enter paste mode: all input up to ctrl-D compiled together", pasteCommand), @@ -276,25 +230,9 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) cmd("phase", "<phase>", "set the implicit phase for power commands", phaseCommand) ) - private def dumpCommand(): Result = { - echo("" + power) - history.asStrings takeRight 30 foreach echo - in.redrawLine() - } - private def valsCommand(): Result = power.valsDescription - - private val typeTransforms = List( - "scala.collection.immutable." -> "immutable.", - "scala.collection.mutable." -> "mutable.", - "scala.collection.generic." -> "generic.", - "java.lang." -> "jl.", - "scala.runtime." -> "runtime." - ) - private def importsCommand(line: String): Result = { val tokens = words(line) val handlers = intp.languageWildcardHandlers ++ intp.importHandlers - val isVerbose = tokens contains "-v" handlers.filterNot(_.importedSymbols.isEmpty).zipWithIndex foreach { case (handler, idx) => @@ -316,63 +254,6 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } } - private def implicitsCommand(line: String): Result = onIntp { intp => - import intp._ - import global._ - - def p(x: Any) = intp.reporter.printMessage("" + x) - - // If an argument is given, only show a source with that - // in its name somewhere. - val args = line split "\\s+" - val filtered = intp.implicitSymbolsBySource filter { - case (source, syms) => - (args contains "-v") || { - if (line == "") (source.fullName.toString != "scala.Predef") - else (args exists (source.name.toString contains _)) - } - } - - if (filtered.isEmpty) - return "No implicits have been imported other than those in Predef." - - filtered foreach { - case (source, syms) => - p("/* " + syms.size + " implicit members imported from " + source.fullName + " */") - - // This groups the members by where the symbol is defined - val byOwner = syms groupBy (_.owner) - val sortedOwners = byOwner.toList sortBy { case (owner, _) => afterTyper(source.info.baseClasses indexOf owner) } - - sortedOwners foreach { - case (owner, members) => - // Within each owner, we cluster results based on the final result type - // if there are more than a couple, and sort each cluster based on name. - // This is really just trying to make the 100 or so implicits imported - // by default into something readable. - val memberGroups: List[List[Symbol]] = { - val groups = members groupBy (_.tpe.finalResultType) toList - val (big, small) = groups partition (_._2.size > 3) - val xss = ( - (big sortBy (_._1.toString) map (_._2)) :+ - (small flatMap (_._2)) - ) - - xss map (xs => xs sortBy (_.name.toString)) - } - - val ownerMessage = if (owner == source) " defined in " else " inherited from " - p(" /* " + members.size + ownerMessage + owner.fullName + " */") - - memberGroups foreach { group => - group foreach (s => p(" " + intp.symbolDefString(s))) - p("") - } - } - p("") - } - } - private def findToolsJar() = { val jdkPath = Directory(jdkHome) val jar = jdkPath / "lib" / "tools.jar" toFile; @@ -398,32 +279,12 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } } - protected def newJavap() = new JavapClass(addToolsJarToLoader(), new IMain.ReplStrippingWriter(intp)) { - override def tryClass(path: String): Array[Byte] = { - val hd :: rest = path split '.' toList; - // If there are dots in the name, the first segment is the - // key to finding it. - if (rest.nonEmpty) { - intp optFlatName hd match { - case Some(flat) => - val clazz = flat :: rest mkString NAME_JOIN_STRING - val bytes = super.tryClass(clazz) - if (bytes.nonEmpty) bytes - else super.tryClass(clazz + MODULE_SUFFIX_STRING) - case _ => super.tryClass(path) - } - } - else { - // Look for Foo first, then Foo$, but if Foo$ is given explicitly, - // we have to drop the $ to find object Foo, then tack it back onto - // the end of the flattened name. - def className = intp flatName path - def moduleName = (intp flatName path.stripSuffix(MODULE_SUFFIX_STRING)) + MODULE_SUFFIX_STRING - - val bytes = super.tryClass(className) - if (bytes.nonEmpty) bytes - else super.tryClass(moduleName) - } + protected def newJavap() = { + val intp = ILoop.this.intp + import intp._ + + new JavapClass(addToolsJarToLoader(), new IMain.ReplStrippingWriter(intp)) { + override def tryClass(path: String) = super.tryClass(translatePath(path) getOrElse path) } } private lazy val javap = substituteAndLog[Javap]("javap", NoJavap)(newJavap()) @@ -432,8 +293,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) private def typeCommand(line0: String): Result = { line0.trim match { case "" => ":type [-v] <expression>" - case s if s startsWith "-v " => typeCommandInternal(s stripPrefix "-v " trim, true) - case s => typeCommandInternal(s, false) + case s if s startsWith "-v " => intp.typeCommandInternal(s stripPrefix "-v " trim, true) + case s => intp.typeCommandInternal(s, false) } } @@ -458,37 +319,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } } - private def wrapCommand(line: String): Result = { - def failMsg = "Argument to :wrap must be the name of a method with signature [T](=> T): T" - onIntp { intp => - import intp._ - import global._ + private def pathToPhaseWrapper = intp.originalPath("$r") + ".phased.atCurrent" - words(line) match { - case Nil => - intp.executionWrapper match { - case "" => "No execution wrapper is set." - case s => "Current execution wrapper: " + s - } - case "clear" :: Nil => - intp.executionWrapper match { - case "" => "No execution wrapper is set." - case s => intp.clearExecutionWrapper() ; "Cleared execution wrapper." - } - case wrapper :: Nil => - intp.typeOfExpression(wrapper) match { - case PolyType(List(targ), MethodType(List(arg), restpe)) => - intp setExecutionWrapper intp.pathToTerm(wrapper) - "Set wrapper to '" + wrapper + "'" - case tp => - failMsg + "\nFound: <unknown>" - } - case _ => failMsg - } - } - } - - private def pathToPhaseWrapper = intp.pathToTerm("$r") + ".phased.atCurrent" private def phaseCommand(name: String): Result = { val phased: Phased = power.phased import phased.NoPhaseName @@ -547,33 +379,30 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) true } + // return false if repl should exit + def processLine(line: String): Boolean = { + import scala.concurrent.duration._ + Await.ready(globalFuture, 60.seconds) + + (line ne null) && (command(line) match { + case Result(false, _) => false + case Result(_, Some(line)) => addReplay(line) ; true + case _ => true + }) + } + + private def readOneLine() = { + out.flush() + in readLine prompt + } + /** The main read-eval-print loop for the repl. It calls * command() for each line of input, and stops when * command() returns false. */ - def loop() { - def readOneLine() = { - out.flush() - in readLine prompt - } - // return false if repl should exit - def processLine(line: String): Boolean = { - if (isAsync) { - if (!awaitInitialized()) return false - runThunks() - } - if (line eq null) false // assume null means EOF - else command(line) match { - case Result(false, _) => false - case Result(_, Some(finalLine)) => addReplay(finalLine) ; true - case _ => true - } - } - def innerLoop() { - if ( try processLine(readOneLine()) catch crashRecovery ) - innerLoop() - } - innerLoop() + @tailrec final def loop() { + if ( try processLine(readOneLine()) catch crashRecovery ) + loop() } /** interpret all lines from a specified file */ @@ -819,48 +648,39 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) SimpleReader() } } - def process(settings: Settings): Boolean = savingContextLoader { - this.settings = settings - createInterpreter() - // sets in to some kind of reader depending on environmental cues - in = in0 match { - case Some(reader) => SimpleReader(reader, out, true) - case None => - // some post-initialization - chooseReader(settings) match { - case x: JLineReader => addThunk(x.consoleReader.postInit) ; x - case x => x - } + private def loopPostInit() { + in match { + case x: JLineReader => x.consoleReader.postInit + case _ => } // Bind intp somewhere out of the regular namespace where // we can get at it in generated code. - addThunk(intp.quietBind(NamedParam[IMain]("$intp", intp)(tagOfIMain, classTag[IMain]))) - addThunk({ - import scala.tools.nsc.io._ - import Properties.userHome - import scala.compat.Platform.EOL - val autorun = replProps.replAutorunCode.option flatMap (f => io.File(f).safeSlurp()) - if (autorun.isDefined) intp.quietRun(autorun.get) - }) - - loadFiles(settings) - // it is broken on startup; go ahead and exit - if (intp.reporter.hasErrors) - return false - - // This is about the illusion of snappiness. We call initialize() - // which spins off a separate thread, then print the prompt and try - // our best to look ready. The interlocking lazy vals tend to - // inter-deadlock, so we break the cycle with a single asynchronous - // message to an actor. - if (isAsync) { - intp initialize initializedCallback() - createAsyncListener() // listens for signal to run postInitialization + intp.quietBind(NamedParam[IMain]("$intp", intp)(tagOfIMain, classTag[IMain])) + // Auto-run code via some setting. + ( replProps.replAutorunCode.option + flatMap (f => io.File(f).safeSlurp()) + foreach (intp quietRun _) + ) + // classloader and power mode setup + intp.setContextClassLoader + if (isReplPower) { + replProps.power setValue true + unleashAndSetPhase() + asyncMessage(power.banner) } - else { + } + def process(settings: Settings): Boolean = savingContextLoader { + this.settings = settings + createInterpreter() + + // sets in to some kind of reader depending on environmental cues + in = in0.fold(chooseReader(settings))(r => SimpleReader(r, out, true)) + globalFuture = future { intp.initializeSynchronous() - postInitialization() + loopPostInit() + loadFiles(settings) + !intp.reporter.hasErrors } printWelcome() @@ -871,27 +691,12 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) true } - /** process command-line arguments and do as they request */ - def process(args: Array[String]): Boolean = { - val command = new CommandLine(args.toList, echo) - def neededHelp(): String = - (if (command.settings.help.value) command.usageMsg + "\n" else "") + - (if (command.settings.Xhelp.value) command.xusageMsg + "\n" else "") - - // if they asked for no help and command is valid, we call the real main - neededHelp() match { - case "" => command.ok && process(command.settings) - case help => echoNoNL(help) ; true - } - } - @deprecated("Use `process` instead", "2.9.0") - def main(settings: Settings): Unit = process(settings) + def main(settings: Settings): Unit = process(settings) //used by sbt } object ILoop { implicit def loopToInterpreter(repl: ILoop): IMain = repl.intp - private def echo(msg: String) = Console println msg // Designed primarily for use by test code: take a String with a // bunch of code, and prints out a transcript of what it would look diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala b/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala deleted file mode 100644 index e3c0494fa3..0000000000 --- a/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala +++ /dev/null @@ -1,125 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package interpreter - -import scala.reflect.internal.util.Position -import scala.util.control.Exception.ignoring -import scala.tools.nsc.util.stackTraceString - -/** - * Machinery for the asynchronous initialization of the repl. - */ -trait ILoopInit { - self: ILoop => - - /** Print a welcome message */ - def printWelcome() { - import Properties._ - val welcomeMsg = - """|Welcome to Scala %s (%s, Java %s). - |Type in expressions to have them evaluated. - |Type :help for more information.""" . - stripMargin.format(versionString, javaVmName, javaVersion) - echo(welcomeMsg) - replinfo("[info] started at " + new java.util.Date) - } - - protected def asyncMessage(msg: String) { - if (isReplInfo || isReplPower) - echoAndRefresh(msg) - } - - private val initLock = new java.util.concurrent.locks.ReentrantLock() - private val initCompilerCondition = initLock.newCondition() // signal the compiler is initialized - private val initLoopCondition = initLock.newCondition() // signal the whole repl is initialized - private val initStart = System.nanoTime - - private def withLock[T](body: => T): T = { - initLock.lock() - try body - finally initLock.unlock() - } - // a condition used to ensure serial access to the compiler. - @volatile private var initIsComplete = false - @volatile private var initError: String = null - private def elapsed() = "%.3f".format((System.nanoTime - initStart).toDouble / 1000000000L) - - // the method to be called when the interpreter is initialized. - // Very important this method does nothing synchronous (i.e. do - // not try to use the interpreter) because until it returns, the - // repl's lazy val `global` is still locked. - protected def initializedCallback() = withLock(initCompilerCondition.signal()) - - // Spins off a thread which awaits a single message once the interpreter - // has been initialized. - protected def createAsyncListener() = { - io.spawn { - withLock(initCompilerCondition.await()) - asyncMessage("[info] compiler init time: " + elapsed() + " s.") - postInitialization() - } - } - - // called from main repl loop - protected def awaitInitialized(): Boolean = { - if (!initIsComplete) - withLock { while (!initIsComplete) initLoopCondition.await() } - if (initError != null) { - println(""" - |Failed to initialize the REPL due to an unexpected error. - |This is a bug, please, report it along with the error diagnostics printed below. - |%s.""".stripMargin.format(initError) - ) - false - } else true - } - // private def warningsThunks = List( - // () => intp.bind("lastWarnings", "" + typeTag[List[(Position, String)]], intp.lastWarnings _), - // ) - - protected def postInitThunks = List[Option[() => Unit]]( - Some(intp.setContextClassLoader _), - if (isReplPower) Some(() => enablePowerMode(true)) else None - ).flatten - // ++ ( - // warningsThunks - // ) - // called once after init condition is signalled - protected def postInitialization() { - try { - postInitThunks foreach (f => addThunk(f())) - runThunks() - } catch { - case ex: Throwable => - initError = stackTraceString(ex) - throw ex - } finally { - initIsComplete = true - - if (isAsync) { - asyncMessage("[info] total init time: " + elapsed() + " s.") - withLock(initLoopCondition.signal()) - } - } - } - // code to be executed only after the interpreter is initialized - // and the lazy val `global` can be accessed without risk of deadlock. - private var pendingThunks: List[() => Unit] = Nil - protected def addThunk(body: => Unit) = synchronized { - pendingThunks :+= (() => body) - } - protected def runThunks(): Unit = synchronized { - if (pendingThunks.nonEmpty) - repldbg("Clearing " + pendingThunks.size + " thunks.") - - while (pendingThunks.nonEmpty) { - val thunk = pendingThunks.head - pendingThunks = pendingThunks.tail - thunk() - } - } -} diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index 2b97f81024..3f49e782b0 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -11,37 +11,19 @@ import util.stringFromWriter import scala.reflect.internal.util._ import java.net.URL import scala.sys.BooleanProp -import io.VirtualDirectory import scala.tools.nsc.io.AbstractFile import reporters._ -import symtab.Flags -import scala.reflect.internal.Names import scala.tools.util.PathResolver import scala.tools.nsc.util.ScalaClassLoader import ScalaClassLoader.URLClassLoader import scala.tools.nsc.util.Exceptional.unwrap import scala.collection.{ mutable, immutable } -import scala.util.control.Exception.{ ultimately } import IMain._ import java.util.concurrent.Future -import typechecker.Analyzer -import scala.language.implicitConversions import scala.reflect.runtime.{ universe => ru } import scala.reflect.{ ClassTag, classTag } import scala.tools.reflect.StdRuntimeTags._ -/** directory to save .class files to */ -private class ReplVirtualDirectory(out: JPrintWriter) extends VirtualDirectory("(memory)", None) { - private def pp(root: AbstractFile, indentLevel: Int) { - val spaces = " " * indentLevel - out.println(spaces + root.name) - if (root.isDirectory) - root.toList sortBy (_.name) foreach (x => pp(x, indentLevel + 1)) - } - // print the contents hierarchically - def show() = pp(this, 0) -} - /** An interpreter for Scala code. * * The main public entry points are compile(), interpret(), and bind(). @@ -77,16 +59,19 @@ private class ReplVirtualDirectory(out: JPrintWriter) extends VirtualDirectory(" class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends Imports { imain => - /** Leading with the eagerly evaluated. - */ - val virtualDirectory: VirtualDirectory = new ReplVirtualDirectory(out) // "directory" for classfiles - private var currentSettings: Settings = initialSettings - private[nsc] var printResults = true // whether to print result lines - private[nsc] var totalSilence = false // whether to print anything - private var _initializeComplete = false // compiler is initialized - private var _isInitialized: Future[Boolean] = null // set up initialization future - private var bindExceptions = true // whether to bind the lastException variable - private var _executionWrapper = "" // code to be wrapped around all lines + object replOutput extends ReplOutput(settings.Yreploutdir) { } + + @deprecated("Use replOutput.dir instead", "2.11.0") + def virtualDirectory = replOutput.dir + // Used in a test case. + def showDirectory() = replOutput.show(out) + + private[nsc] var printResults = true // whether to print result lines + private[nsc] var totalSilence = false // whether to print anything + private var _initializeComplete = false // compiler is initialized + private var _isInitialized: Future[Boolean] = null // set up initialization future + private var bindExceptions = true // whether to bind the lastException variable + private var _executionWrapper = "" // code to be wrapped around all lines /** We're going to go to some trouble to initialize the compiler asynchronously. * It's critical that nothing call into it until it's been initialized or we will @@ -98,20 +83,11 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends private var _classLoader: AbstractFileClassLoader = null // active classloader private val _compiler: Global = newCompiler(settings, reporter) // our private compiler - private val nextReqId = { - var counter = 0 - () => { counter += 1 ; counter } - } - def compilerClasspath: Seq[URL] = ( if (isInitializeComplete) global.classPath.asURLs else new PathResolver(settings).result.asURLs // the compiler's classpath ) - def settings = currentSettings - def mostRecentLine = prevRequestList match { - case Nil => "" - case req :: _ => req.originalLine - } + def settings = initialSettings // Run the code body with the given boolean settings flipped to true. def withoutWarnings[T](body: => T): T = beQuietDuring { val saved = settings.nowarn.value @@ -126,12 +102,6 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends def this(settings: Settings) = this(settings, new NewLinePrintWriter(new ConsoleWriter, true)) def this() = this(new Settings()) - lazy val repllog: Logger = new Logger { - val out: JPrintWriter = imain.out - val isInfo: Boolean = BooleanProp keyExists "scala.repl.info" - val isDebug: Boolean = BooleanProp keyExists "scala.repl.debug" - val isTrace: Boolean = BooleanProp keyExists "scala.repl.trace" - } lazy val formatting: Formatting = new Formatting { val prompt = Properties.shellPromptString } @@ -153,6 +123,8 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends catch AbstractOrMissingHandler() } private def tquoted(s: String) = "\"\"\"" + s + "\"\"\"" + private val logScope = scala.sys.props contains "scala.repl.scope" + private def scopelog(msg: String) = if (logScope) Console.err.println(msg) // argument is a thunk to execute after init is done def initialize(postInitSignal: => Unit) { @@ -187,15 +159,24 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends else null } } - @deprecated("Use `global` for access to the compiler instance.", "2.9.0") - lazy val compiler: global.type = global import global._ - import definitions.{ScalaPackage, JavaLangPackage, termMember, typeMember} - import rootMirror.{RootClass, getClassIfDefined, getModuleIfDefined, getRequiredModule, getRequiredClass} + import definitions.{ ObjectClass, termMember, dropNullaryMethod} + + lazy val runtimeMirror = ru.runtimeMirror(classLoader) + + private def noFatal(body: => Symbol): Symbol = try body catch { case _: FatalError => NoSymbol } + + def getClassIfDefined(path: String) = ( + noFatal(runtimeMirror staticClass path) + orElse noFatal(rootMirror staticClass path) + ) + def getModuleIfDefined(path: String) = ( + noFatal(runtimeMirror staticModule path) + orElse noFatal(rootMirror staticModule path) + ) implicit class ReplTypeOps(tp: Type) { - def orElse(other: => Type): Type = if (tp ne NoType) tp else other def andAlso(fn: Type => Type): Type = if (tp eq NoType) tp else fn(tp) } @@ -208,10 +189,9 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends // make sure we don't overwrite their unwisely named res3 etc. def freshUserTermName(): TermName = { val name = newTermName(freshUserVarName()) - if (definedNameMap contains name) freshUserTermName() + if (replScope containsName name) freshUserTermName() else name } - def isUserTermName(name: Name) = isUserVarName("" + name) def isInternalTermName(name: Name) = isInternalVarName("" + name) } import naming._ @@ -260,9 +240,12 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends /** Instantiate a compiler. Overridable. */ protected def newCompiler(settings: Settings, reporter: Reporter): ReplGlobal = { - settings.outputDirs setSingleOutput virtualDirectory + settings.outputDirs setSingleOutput replOutput.dir settings.exposeEmptyPackage.value = true - new Global(settings, reporter) with ReplGlobal + if (settings.Yrangepos.value) + new Global(settings, reporter) with ReplGlobal with interactive.RangePositions + else + new Global(settings, reporter) with ReplGlobal } /** Parent classloader. Overridable. */ @@ -295,20 +278,51 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends ensureClassLoader() _classLoader } - private class TranslatingClassLoader(parent: ClassLoader) extends AbstractFileClassLoader(virtualDirectory, parent) { + + def backticked(s: String): String = ( + (s split '.').toList map { + case "_" => "_" + case s if nme.keywords(newTermName(s)) => s"`$s`" + case s => s + } mkString "." + ) + + abstract class PhaseDependentOps { + def shift[T](op: => T): T + + def path(name: => Name): String = shift(path(symbolOfName(name))) + def path(sym: Symbol): String = backticked(shift(sym.fullName)) + def sig(sym: Symbol): String = shift(sym.defString) + } + object typerOp extends PhaseDependentOps { + def shift[T](op: => T): T = exitingTyper(op) + } + object flatOp extends PhaseDependentOps { + def shift[T](op: => T): T = exitingFlatten(op) + } + + def originalPath(name: String): String = originalPath(name: TermName) + def originalPath(name: Name): String = typerOp path name + def originalPath(sym: Symbol): String = typerOp path sym + def flatPath(sym: Symbol): String = flatOp shift sym.javaClassName + def translatePath(path: String) = { + val sym = if (path endsWith "$") symbolOfTerm(path.init) else symbolOfIdent(path) + sym match { + case NoSymbol => None + case _ => Some(flatPath(sym)) + } + } + + private class TranslatingClassLoader(parent: ClassLoader) extends AbstractFileClassLoader(replOutput.dir, parent) { /** Overridden here to try translating a simple name to the generated * class name if the original attempt fails. This method is used by * getResourceAsStream as well as findClass. */ - override protected def findAbstractFile(name: String): AbstractFile = { + override protected def findAbstractFile(name: String): AbstractFile = super.findAbstractFile(name) match { - // deadlocks on startup if we try to translate names too early - case null if isInitializeComplete => - generatedName(name) map (x => super.findAbstractFile(x)) orNull - case file => - file + case null => translatePath(name) map (super.findAbstractFile(_)) orNull + case file => file } - } } private def makeClassLoader(): AbstractFileClassLoader = new TranslatingClassLoader(parentClassLoader match { @@ -316,32 +330,11 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends case p => new URLClassLoader(compilerClasspath, p) }) - def getInterpreterClassLoader() = classLoader - // Set the current Java "context" class loader to this interpreter's class loader def setContextClassLoader() = classLoader.setAsContext() - /** Given a simple repl-defined name, returns the real name of - * the class representing it, e.g. for "Bippy" it may return - * {{{ - * $line19.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$Bippy - * }}} - */ - def generatedName(simpleName: String): Option[String] = { - if (simpleName endsWith nme.MODULE_SUFFIX_STRING) optFlatName(simpleName.init) map (_ + nme.MODULE_SUFFIX_STRING) - else optFlatName(simpleName) - } - def flatName(id: String) = optFlatName(id) getOrElse id - def optFlatName(id: String) = requestForIdent(id) map (_ fullFlatName id) - - def allDefinedNames = definedNameMap.keys.toList.sorted - def pathToType(id: String): String = pathToName(newTypeName(id)) - def pathToTerm(id: String): String = pathToName(newTermName(id)) - def pathToName(name: Name): String = { - if (definedNameMap contains name) - definedNameMap(name) fullPath name - else name.toString - } + def allDefinedNames: List[Name] = exitingTyper(replScope.toList.map(_.name).sorted) + def unqualifiedIds: List[String] = allDefinedNames map (_.decode) sorted /** Most recent tree handled which wasn't wholly synthetic. */ private def mostRecentlyHandledTree: Option[Tree] = { @@ -354,50 +347,47 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends None } - /** Stubs for work in progress. */ - def handleTypeRedefinition(name: TypeName, old: Request, req: Request) = { - for (t1 <- old.simpleNameOfType(name) ; t2 <- req.simpleNameOfType(name)) { - repldbg("Redefining type '%s'\n %s -> %s".format(name, t1, t2)) - } - } + private def updateReplScope(sym: Symbol, isDefined: Boolean) { + def log(what: String) { + val mark = if (sym.isType) "t " else "v " + val name = exitingTyper(sym.nameString) + val info = cleanTypeAfterTyper(sym) + val defn = sym defStringSeenAs info - def handleTermRedefinition(name: TermName, old: Request, req: Request) = { - for (t1 <- old.compilerTypeOf get name ; t2 <- req.compilerTypeOf get name) { - // Printing the types here has a tendency to cause assertion errors, like - // assertion failed: fatal: <refinement> has owner value x, but a class owner is required - // so DBG is by-name now to keep it in the family. (It also traps the assertion error, - // but we don't want to unnecessarily risk hosing the compiler's internal state.) - repldbg("Redefining term '%s'\n %s -> %s".format(name, t1, t2)) + scopelog(f"[$mark$what%6s] $name%-25s $defn%s") } + if (ObjectClass isSubClass sym.owner) return + // unlink previous + replScope lookupAll sym.name foreach { sym => + log("unlink") + replScope unlink sym + } + val what = if (isDefined) "define" else "import" + log(what) + replScope enter sym } def recordRequest(req: Request) { - if (req == null || referencedNameMap == null) + if (req == null) return prevRequests += req - req.referencedNames foreach (x => referencedNameMap(x) = req) // warning about serially defining companions. It'd be easy // enough to just redefine them together but that may not always // be what people want so I'm waiting until I can do it better. - for { - name <- req.definedNames filterNot (x => req.definedNames contains x.companionName) - oldReq <- definedNameMap get name.companionName - newSym <- req.definedSymbols get name - oldSym <- oldReq.definedSymbols get name.companionName - } { - afterTyper(replwarn(s"warning: previously defined $oldSym is not a companion to $newSym.")) - replwarn("Companions must be defined together; you may wish to use :paste mode for this.") - } - - // Updating the defined name map - req.definedNames foreach { name => - if (definedNameMap contains name) { - if (name.isTypeName) handleTypeRedefinition(name.toTypeName, definedNameMap(name), req) - else handleTermRedefinition(name.toTermName, definedNameMap(name), req) + exitingTyper { + req.defines filterNot (s => req.defines contains s.companionSymbol) foreach { newSym => + val companion = newSym.name.companionName + replScope lookup companion andAlso { oldSym => + replwarn(s"warning: previously defined $oldSym is not a companion to $newSym.") + replwarn("Companions must be defined together; you may wish to use :paste mode for this.") + } } - definedNameMap(name) = req + } + exitingTyper { + req.imports foreach (sym => updateReplScope(sym, isDefined = false)) + req.defines foreach (sym => updateReplScope(sym, isDefined = true)) } } @@ -406,19 +396,6 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends printMessage(msg) } - def isParseable(line: String): Boolean = { - beSilentDuring { - try parse(line) match { - case Some(xs) => xs.nonEmpty // parses as-is - case None => true // incomplete - } - catch { case x: Exception => // crashed the compiler - replwarn("Exception in isParseable(\"" + line + "\"): " + x) - false - } - } - } - def compileSourcesKeepingRun(sources: SourceFile*) = { val run = new Run() reporter.reset() @@ -445,18 +422,6 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends executingRequest } - // rewriting "5 // foo" to "val x = { 5 // foo }" creates broken code because - // the close brace is commented out. Strip single-line comments. - // ... but for error message output reasons this is not used, and rather than - // enclosing in braces it is constructed like "val x =\n5 // foo". - private def removeComments(line: String): String = { - showCodeIfDebugging(line) // as we're about to lose our // show - line.lines map (s => s indexOf "//" match { - case -1 => s - case idx => s take idx - }) mkString "\n" - } - private def safePos(t: Tree, alt: Int): Int = try t.pos.startOrPoint catch { case _: UnsupportedOperationException => alt } @@ -612,7 +577,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends */ def bind(name: String, boundType: String, value: Any, modifiers: List[String] = Nil): IR.Result = { val bindRep = new ReadEvalPrint() - val run = bindRep.compile(""" + bindRep.compile(""" |object %s { | var value: %s = _ | def set(x: Any) = value = x.asInstanceOf[%s] @@ -642,24 +607,15 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends def rebind(p: NamedParam): IR.Result = { val name = p.name - val oldType = typeOfTerm(name) orElse { return IR.Error } val newType = p.tpe val tempName = freshInternalVarName() quietRun("val %s = %s".format(tempName, name)) quietRun("val %s = %s.asInstanceOf[%s]".format(name, tempName, newType)) } - def quietImport(ids: String*): IR.Result = beQuietDuring(addImports(ids: _*)) - def addImports(ids: String*): IR.Result = - if (ids.isEmpty) IR.Success - else interpret("import " + ids.mkString(", ")) - def quietBind(p: NamedParam): IR.Result = beQuietDuring(bind(p)) def bind(p: NamedParam): IR.Result = bind(p.name, p.tpe, p.value) def bind[T: ru.TypeTag : ClassTag](name: String, value: T): IR.Result = bind((name, value)) - def bindSyntheticValue(x: Any): IR.Result = bindValue(freshInternalVarName(), x) - def bindValue(x: Any): IR.Result = bindValue(freshUserVarName(), x) - def bindValue(name: String, x: Any): IR.Result = bind(name, TypeStrings.fromValue(x), x) /** Reset this interpreter, forgetting all user-specified requests. */ def reset() { @@ -667,9 +623,8 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends resetClassLoader() resetAllCreators() prevRequests.clear() - referencedNameMap.clear() - definedNameMap.clear() - virtualDirectory.clear() + resetReplScope() + replOutput.dir.clear() } /** This instance is no longer needed, so release any resources @@ -690,10 +645,6 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends class ReadEvalPrint(lineId: Int) { def this() = this(freshLineId()) - private var lastRun: Run = _ - private var evalCaught: Option[Throwable] = None - private var conditionalWarnings: List[ConditionalWarning] = Nil - val packageName = sessionNames.line + lineId val readName = sessionNames.read val evalName = sessionNames.eval @@ -720,7 +671,6 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends def readPath = pathTo(readName) def evalPath = pathTo(evalName) - def printPath = pathTo(printName) def call(name: String, args: Any*): AnyRef = { val m = evalMethod(name) @@ -735,10 +685,6 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends try Right(call(name, args: _*)) catch { case ex: Throwable => Left(ex) } - def callOpt(name: String, args: Any*): Option[AnyRef] = - try Some(call(name, args: _*)) - catch { case ex: Throwable => bindError(ex) ; None } - class EvalException(msg: String, cause: Throwable) extends RuntimeException(msg, cause) { } private def evalError(path: String, ex: Throwable) = @@ -750,10 +696,6 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends } lazy val evalClass = load(evalPath) - lazy val evalValue = callEither(resultName) match { - case Left(ex) => evalCaught = Some(ex) ; None - case Right(result) => Some(result) - } def compile(source: String): Boolean = compileAndSaveRun("<console>", source) @@ -761,10 +703,10 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends * following accessPath into the outer one. */ def resolvePathToSymbol(accessPath: String): Symbol = { - val readRoot = getRequiredModule(readPath) // the outermost wrapper + val readRoot = getModuleIfDefined(readPath) // the outermost wrapper (accessPath split '.').foldLeft(readRoot: Symbol) { case (sym, "") => sym - case (sym, name) => afterTyper(termMember(sym, name)) + case (sym, name) => exitingTyper(termMember(sym, name)) } } /** We get a bunch of repeated warnings for reasons I haven't @@ -797,15 +739,16 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends showCodeIfDebugging(code) val (success, run) = compileSourcesKeepingRun(new BatchSourceFile(label, packaged(code))) updateRecentWarnings(run) - lastRun = run success } } /** One line of code submitted by the user for interpretation */ - // private class Request(val line: String, val trees: List[Tree]) { - val reqId = nextReqId() + def defines = defHandlers flatMap (_.definedSymbols) + def imports = importedSymbols + def value = Some(handlers.last) filter (h => h.definesValue) map (h => definedSymbols(h.definesTerm.get)) getOrElse NoSymbol + val lineRep = new ReadEvalPrint() private var _originalLine: String = null @@ -816,50 +759,31 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends val handlers: List[MemberHandler] = trees map (memberHandlers chooseHandler _) def defHandlers = handlers collect { case x: MemberDefHandler => x } - /** all (public) names defined by these statements */ - val definedNames = handlers flatMap (_.definedNames) - /** list of names used by this expression */ val referencedNames: List[Name] = handlers flatMap (_.referencedNames) /** def and val names */ def termNames = handlers flatMap (_.definesTerm) def typeNames = handlers flatMap (_.definesType) - def definedOrImported = handlers flatMap (_.definedOrImported) - def definedSymbolList = defHandlers flatMap (_.definedSymbols) - - def definedTypeSymbol(name: String) = definedSymbols(newTypeName(name)) - def definedTermSymbol(name: String) = definedSymbols(newTermName(name)) + def importedSymbols = handlers flatMap { + case x: ImportHandler => x.importedSymbols + case _ => Nil + } /** Code to import bound names from previous lines - accessPath is code to * append to objectName to access anything bound by request. */ val ComputedImports(importsPreamble, importsTrailer, accessPath) = - importsCode(referencedNames.toSet) - - /** Code to access a variable with the specified name */ - def fullPath(vname: String) = ( - lineRep.readPath + accessPath + ".`%s`".format(vname) - ) - /** Same as fullpath, but after it has been flattened, so: - * $line5.$iw.$iw.$iw.Bippy // fullPath - * $line5.$iw$$iw$$iw$Bippy // fullFlatName - */ - def fullFlatName(name: String) = - lineRep.readPath + accessPath.replace('.', '$') + nme.NAME_JOIN_STRING + name - - /** The unmangled symbol name, but supplemented with line info. */ - def disambiguated(name: Name): String = name + " (in " + lineRep + ")" - - /** Code to access a variable with the specified name */ - def fullPath(vname: Name): String = fullPath(vname.toString) + exitingTyper(importsCode(referencedNames.toSet)) /** the line of code to compute */ def toCompute = line + def fullPath(vname: String) = s"${lineRep.readPath}$accessPath.`$vname`" + /** generate the source code for the object that computes this request */ private object ObjectSourceCode extends CodeAssembler[MemberHandler] { - def path = pathToTerm("$intp") + def path = originalPath("$intp") def envLines = { if (!isReplPower) Nil // power mode only for now // $intp is not bound; punt, but include the line. @@ -869,8 +793,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends ) else List( "def $line = " + tquoted(originalLine), - "def $req = %s.requestForReqId(%s).orNull".format(path, reqId), - "def $trees = if ($req eq null) Nil else $req.trees".format(lineRep.readName, path, reqId) + "def $trees = Nil" ) } @@ -886,13 +809,10 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends /** We only want to generate this code when the result * is a value which can be referred to as-is. */ - val evalResult = - if (!handlers.last.definesValue) "" - else handlers.last.definesTerm match { - case Some(vname) if typeOf contains vname => - "lazy val %s = %s".format(lineRep.resultName, fullPath(vname)) - case _ => "" - } + val evalResult = Request.this.value match { + case NoSymbol => "" + case sym => "lazy val %s = %s".format(lineRep.resultName, originalPath(sym)) + } // first line evaluates object to make sure constructor is run // initial "" so later code can uniformly be: + etc val preamble = """ @@ -914,15 +834,6 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends val generate = (m: MemberHandler) => m resultExtractionCode Request.this } - // get it - def getEvalTyped[T] : Option[T] = getEval map (_.asInstanceOf[T]) - def getEval: Option[AnyRef] = { - // ensure it has been compiled - compile - // try to load it and call the value method - lineRep.evalValue filterNot (_ == null) - } - /** Compile the object file. Returns whether the compilation succeeded. * If all goes well, the "types" map is computed. */ lazy val compile: Boolean = { @@ -941,7 +852,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends val name = dh.member.name definedSymbols get name foreach { sym => dh.member setSymbol sym - repldbg("Set symbol of " + name + " to " + sym.defString) + repldbg("Set symbol of " + name + " to " + symbolDefString(sym)) } } @@ -951,11 +862,10 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends } lazy val resultSymbol = lineRep.resolvePathToSymbol(accessPath) - def applyToResultMember[T](name: Name, f: Symbol => T) = afterTyper(f(resultSymbol.info.nonPrivateDecl(name))) + def applyToResultMember[T](name: Name, f: Symbol => T) = exitingTyper(f(resultSymbol.info.nonPrivateDecl(name))) /* typeOf lookup with encoding */ def lookupTypeOf(name: Name) = typeOf.getOrElse(name, typeOf(global.encode(name.toString))) - def simpleNameOfType(name: TypeName) = (compilerTypeOf get name) map (_.typeSymbol.simpleName) private def typeMap[T](f: Type => T) = mapFrom[Name, Name, T](termNames ++ typeNames)(x => f(cleanMemberDecl(resultSymbol, x))) @@ -963,14 +873,11 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends /** Types of variables defined by this request. */ lazy val compilerTypeOf = typeMap[Type](x => x) withDefaultValue NoType /** String representations of same. */ - lazy val typeOf = typeMap[String](tp => afterTyper(tp.toString)) + lazy val typeOf = typeMap[String](tp => exitingTyper(tp.toString)) - // lazy val definedTypes: Map[Name, Type] = { - // typeNames map (x => x -> afterTyper(resultSymbol.info.nonPrivateDecl(x).tpe)) toMap - // } lazy val definedSymbols = ( termNames.map(x => x -> applyToResultMember(x, x => x)) ++ - typeNames.map(x => x -> compilerTypeOf(x).typeSymbol) + typeNames.map(x => x -> compilerTypeOf(x).typeSymbolDirect) ).toMap[Name, Symbol] withDefaultValue NoSymbol lazy val typesOfDefinedTerms = mapFrom[Name, Name, Type](termNames)(x => applyToResultMember(x, _.tpe)) @@ -1000,45 +907,48 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends private var mostRecentWarnings: List[(global.Position, String)] = Nil def lastWarnings = mostRecentWarnings - def treesForRequestId(id: Int): List[Tree] = - requestForReqId(id).toList flatMap (_.trees) - - def requestForReqId(id: Int): Option[Request] = - if (executingRequest != null && executingRequest.reqId == id) Some(executingRequest) - else prevRequests find (_.reqId == id) + private lazy val importToGlobal = global mkImporter ru + private lazy val importToRuntime = ru mkImporter global + private lazy val javaMirror = ru.rootMirror match { + case x: ru.JavaMirror => x + case _ => null + } + private implicit def importFromRu(sym: ru.Symbol): Symbol = importToGlobal importSymbol sym + private implicit def importToRu(sym: Symbol): ru.Symbol = importToRuntime importSymbol sym - def requestForName(name: Name): Option[Request] = { - assert(definedNameMap != null, "definedNameMap is null") - definedNameMap get name + def classOfTerm(id: String): Option[JClass] = symbolOfTerm(id) match { + case NoSymbol => None + case sym => Some(javaMirror runtimeClass importToRu(sym).asClass) } - def requestForIdent(line: String): Option[Request] = - requestForName(newTermName(line)) orElse requestForName(newTypeName(line)) + def typeOfTerm(id: String): Type = symbolOfTerm(id).tpe - def requestHistoryForName(name: Name): List[Request] = - prevRequests.toList.reverse filter (_.definedNames contains name) + def valueOfTerm(id: String): Option[Any] = exitingTyper { + def value() = { + val sym0 = symbolOfTerm(id) + val sym = (importToRuntime importSymbol sym0).asTerm + val module = runtimeMirror.reflectModule(sym.owner.companionSymbol.asModule).instance + val module1 = runtimeMirror.reflect(module) + val invoker = module1.reflectField(sym) - def definitionForName(name: Name): Option[MemberHandler] = - requestForName(name) flatMap { req => - req.handlers find (_.definedNames contains name) + invoker.get } - def valueOfTerm(id: String): Option[AnyRef] = - requestForName(newTermName(id)) flatMap (_.getEval) - - def classOfTerm(id: String): Option[JClass] = - valueOfTerm(id) map (_.getClass) - - def typeOfTerm(id: String): Type = newTermName(id) match { - case nme.ROOTPKG => RootClass.tpe - case name => requestForName(name).fold(NoType: Type)(_ compilerTypeOf name) + try Some(value()) catch { case _: Exception => None } } - def symbolOfType(id: String): Symbol = - requestForName(newTypeName(id)).fold(NoSymbol: Symbol)(_ definedTypeSymbol id) + /** It's a bit of a shotgun approach, but for now we will gain in + * robustness. Try a symbol-producing operation at phase typer, and + * if that is NoSymbol, try again at phase flatten. I'll be able to + * lose this and run only from exitingTyper as soon as I figure out + * exactly where a flat name is sneaking in when calculating imports. + */ + def tryTwice(op: => Symbol): Symbol = exitingTyper(op) orElse exitingFlatten(op) - def symbolOfTerm(id: String): Symbol = - requestForIdent(newTermName(id)).fold(NoSymbol: Symbol)(_ definedTermSymbol id) + def symbolOfIdent(id: String): Symbol = symbolOfTerm(id) orElse symbolOfType(id) + def symbolOfType(id: String): Symbol = tryTwice(replScope lookup (id: TypeName)) + def symbolOfTerm(id: String): Symbol = tryTwice(replScope lookup (id: TermName)) + def symbolOfName(id: Name): Symbol = replScope lookup id def runtimeClassAndTypeOfTerm(id: String): Option[(JClass, Type)] = { classOfTerm(id) flatMap { clazz => @@ -1059,14 +969,18 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends else NoType } } - def cleanMemberDecl(owner: Symbol, member: Name): Type = afterTyper { - normalizeNonPublic { - owner.info.nonPrivateDecl(member).tpe match { - case NullaryMethodType(tp) => tp - case tp => tp - } - } + + def cleanTypeAfterTyper(sym: => Symbol): Type = { + exitingTyper( + normalizeNonPublic( + dropNullaryMethod( + sym.tpe_* + ) + ) + ) } + def cleanMemberDecl(owner: Symbol, member: Name): Type = + cleanTypeAfterTyper(owner.info nonPrivateDecl member) object exprTyper extends { val repl: IMain.this.type = imain @@ -1080,64 +994,35 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends def typeOfExpression(expr: String, silent: Boolean = true): Type = exprTyper.typeOfExpression(expr, silent) - protected def onlyTerms(xs: List[Name]) = xs collect { case x: TermName => x } - protected def onlyTypes(xs: List[Name]) = xs collect { case x: TypeName => x } + protected def onlyTerms(xs: List[Name]): List[TermName] = xs collect { case x: TermName => x } + protected def onlyTypes(xs: List[Name]): List[TypeName] = xs collect { case x: TypeName => x } def definedTerms = onlyTerms(allDefinedNames) filterNot isInternalTermName def definedTypes = onlyTypes(allDefinedNames) - def definedSymbols = prevRequestList.flatMap(_.definedSymbols.values).toSet[Symbol] - def definedSymbolList = prevRequestList flatMap (_.definedSymbolList) filterNot (s => isInternalTermName(s.name)) + def definedSymbolList = prevRequestList flatMap (_.defines) filterNot (s => isInternalTermName(s.name)) // Terms with user-given names (i.e. not res0 and not synthetic) def namedDefinedTerms = definedTerms filterNot (x => isUserVarName("" + x) || directlyBoundNames(x)) - private def findName(name: Name) = definedSymbols find (_.name == name) getOrElse NoSymbol - - /** Translate a repl-defined identifier into a Symbol. - */ - def apply(name: String): Symbol = - types(name) orElse terms(name) - - def types(name: String): Symbol = { - val tpname = newTypeName(name) - findName(tpname) orElse getClassIfDefined(tpname) - } - def terms(name: String): Symbol = { - val termname = newTypeName(name) - findName(termname) orElse getModuleIfDefined(termname) + private var _replScope: Scope = _ + private def resetReplScope() { + _replScope = newScope } - // [Eugene to Paul] possibly you could make use of TypeTags here - def types[T: ClassTag] : Symbol = types(classTag[T].runtimeClass.getName) - def terms[T: ClassTag] : Symbol = terms(classTag[T].runtimeClass.getName) - def apply[T: ClassTag] : Symbol = apply(classTag[T].runtimeClass.getName) + def replScope = { + if (_replScope eq null) + _replScope = newScope - def classSymbols = allDefSymbols collect { case x: ClassSymbol => x } - def methodSymbols = allDefSymbols collect { case x: MethodSymbol => x } + _replScope + } - /** the previous requests this interpreter has processed */ private var executingRequest: Request = _ private val prevRequests = mutable.ListBuffer[Request]() - private val referencedNameMap = mutable.Map[Name, Request]() - private val definedNameMap = mutable.Map[Name, Request]() private val directlyBoundNames = mutable.Set[Name]() - def allHandlers = prevRequestList flatMap (_.handlers) - def allDefHandlers = allHandlers collect { case x: MemberDefHandler => x } - def allDefSymbols = allDefHandlers map (_.symbol) filter (_ ne NoSymbol) - - def lastRequest = if (prevRequests.isEmpty) null else prevRequests.last - def prevRequestList = prevRequests.toList - def allSeenTypes = prevRequestList flatMap (_.typeOf.values.toList) distinct - def allImplicits = allHandlers filter (_.definesImplicit) flatMap (_.definedNames) - def importHandlers = allHandlers collect { case x: ImportHandler => x } - - def visibleTermNames: List[Name] = definedTerms ++ importedTerms distinct - - /** Another entry point for tab-completion, ids in scope */ - def unqualifiedIds = visibleTermNames map (_.toString) filterNot (_ contains "$") sorted - - /** Parse the ScalaSig to find type aliases */ - def aliasForType(path: String) = ByteCode.aliasForType(path) + def allHandlers = prevRequestList flatMap (_.handlers) + def lastRequest = if (prevRequests.isEmpty) null else prevRequests.last + def prevRequestList = prevRequests.toList + def importHandlers = allHandlers collect { case x: ImportHandler => x } def withoutUnwrapping(op: => Unit): Unit = { val saved = isettings.unwrapStrings @@ -1148,7 +1033,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends def symbolDefString(sym: Symbol) = { TypeStrings.quieter( - afterTyper(sym.defString), + exitingTyper(sym.defString), sym.owner.name + ".this.", sym.owner.fullName + "." ) @@ -1158,13 +1043,12 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends /** Secret bookcase entrance for repl debuggers: end the line * with "// show" and see what's going on. */ - def isShow = code.lines exists (_.trim endsWith "// show") - def isShowRaw = code.lines exists (_.trim endsWith "// raw") - - // old style - beSilentDuring(parse(code)) foreach { ts => - ts foreach { t => - withoutUnwrapping(repldbg(asCompactString(t))) + def isShow = code.lines exists (_.trim endsWith "// show") + if (isReplDebug || isShow) { + beSilentDuring(parse(code)) foreach { ts => + ts foreach { t => + withoutUnwrapping(echo(asCompactString(t))) + } } } } diff --git a/src/compiler/scala/tools/nsc/interpreter/ISettings.scala b/src/compiler/scala/tools/nsc/interpreter/ISettings.scala index a8f77afcdf..d114ca2359 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ISettings.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ISettings.scala @@ -12,13 +12,6 @@ package interpreter * @author Lex Spoon, 2007/3/24 **/ class ISettings(intp: IMain) { - /** A list of paths where :load should look */ - var loadPath = List(".") - - /** Set this to true to see repl machinery under -Yrich-exceptions. - */ - var showInternalStackTraces = false - /** The maximum length of toString to use when printing the result * of an evaluation. 0 means no maximum. If a printout requires * more than this number of characters, then the printout is @@ -44,7 +37,7 @@ class ISettings(intp: IMain) { } def deprecation: Boolean = intp.settings.deprecation.value - def allSettings = Map( + def allSettings = Map[String, Any]( "maxPrintString" -> maxPrintString, "maxAutoprintCompletion" -> maxAutoprintCompletion, "unwrapStrings" -> unwrapStrings, diff --git a/src/compiler/scala/tools/nsc/interpreter/Imports.scala b/src/compiler/scala/tools/nsc/interpreter/Imports.scala index 73d962b5b0..ff7bfd432c 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Imports.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Imports.scala @@ -12,12 +12,9 @@ trait Imports { self: IMain => import global._ - import definitions.{ ScalaPackage, JavaLangPackage, PredefModule } + import definitions.{ ObjectClass, ScalaPackage, JavaLangPackage, PredefModule } import memberHandlers._ - def isNoImports = settings.noimports.value - def isNoPredef = settings.nopredef.value - /** Synthetic import handlers for the language defined imports. */ private def makeWildcardImportHandler(sym: Symbol): ImportHandler = { val hd :: tl = sym.fullName.split('.').toList map newTermName @@ -31,12 +28,9 @@ trait Imports { /** Symbols whose contents are language-defined to be imported. */ def languageWildcardSyms: List[Symbol] = List(JavaLangPackage, ScalaPackage, PredefModule) - def languageWildcards: List[Type] = languageWildcardSyms map (_.tpe) def languageWildcardHandlers = languageWildcardSyms map makeWildcardImportHandler def allImportedNames = importHandlers flatMap (_.importedNames) - def importedTerms = onlyTerms(allImportedNames) - def importedTypes = onlyTypes(allImportedNames) /** Types which have been wildcard imported, such as: * val x = "abc" ; import x._ // type java.lang.String @@ -52,17 +46,11 @@ trait Imports { def sessionWildcards: List[Type] = { importHandlers filter (_.importsWildcard) map (_.targetType) distinct } - def wildcardTypes = languageWildcards ++ sessionWildcards def languageSymbols = languageWildcardSyms flatMap membersAtPickler def sessionImportedSymbols = importHandlers flatMap (_.importedSymbols) def importedSymbols = languageSymbols ++ sessionImportedSymbols def importedTermSymbols = importedSymbols collect { case x: TermSymbol => x } - def importedTypeSymbols = importedSymbols collect { case x: TypeSymbol => x } - def implicitSymbols = importedSymbols filter (_.isImplicit) - - def importedTermNamed(name: String): Symbol = - importedTermSymbols find (_.name.toString == name) getOrElse NoSymbol /** Tuples of (source, imported symbols) in the order they were imported. */ @@ -146,44 +134,42 @@ trait Imports { code append "object %s {\n".format(impname) trailingBraces append "}\n" accessPath append ("." + impname) - - currentImps.clear + currentImps.clear() + } + def maybeWrap(names: Name*) = if (names exists currentImps) addWrapper() + def wrapBeforeAndAfter[T](op: => T): T = { + addWrapper() + try op finally addWrapper() } - - addWrapper() // loop through previous requests, adding imports for each one - for (ReqAndHandler(req, handler) <- reqsToUse) { - handler match { - // If the user entered an import, then just use it; add an import wrapping - // level if the import might conflict with some other import - case x: ImportHandler => - if (x.importsWildcard || currentImps.exists(x.importedNames contains _)) - addWrapper() - - code append (x.member + "\n") - - // give wildcard imports a import wrapper all to their own - if (x.importsWildcard) addWrapper() - else currentImps ++= x.importedNames - - // For other requests, import each defined name. - // import them explicitly instead of with _, so that - // ambiguity errors will not be generated. Also, quote - // the name of the variable, so that we don't need to - // handle quoting keywords separately. - case x => - for (imv <- x.definedNames) { - if (currentImps contains imv) addWrapper() - - code append ("import " + (req fullPath imv) + "\n") - currentImps += imv - } + wrapBeforeAndAfter { + for (ReqAndHandler(req, handler) <- reqsToUse) { + handler match { + // If the user entered an import, then just use it; add an import wrapping + // level if the import might conflict with some other import + case x: ImportHandler if x.importsWildcard => + wrapBeforeAndAfter(code append (x.member + "\n")) + case x: ImportHandler => + maybeWrap(x.importedNames: _*) + code append (x.member + "\n") + currentImps ++= x.importedNames + + // For other requests, import each defined name. + // import them explicitly instead of with _, so that + // ambiguity errors will not be generated. Also, quote + // the name of the variable, so that we don't need to + // handle quoting keywords separately. + case x => + for (sym <- x.definedSymbols) { + maybeWrap(sym.name) + code append s"import ${x.path}\n" + currentImps += sym.name + } + } } } - // add one extra wrapper, to prevent warnings in the common case of - // redefining the value bound in the last interpreter request. - addWrapper() + ComputedImports(code.toString, trailingBraces.toString, accessPath.toString) } @@ -191,5 +177,5 @@ trait Imports { prevRequestList flatMap (req => req.handlers map (req -> _)) private def membersAtPickler(sym: Symbol): List[Symbol] = - beforePickler(sym.info.nonPrivateMembers.toList) + enteringPickler(sym.info.nonPrivateMembers.toList) } diff --git a/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala b/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala index 8331fddca6..28ddf2939c 100644 --- a/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala +++ b/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala @@ -7,8 +7,6 @@ package scala.tools.nsc package interpreter import java.io.IOException -import java.nio.channels.ClosedByInterruptException -import scala.util.control.Exception._ import session.History import InteractiveReader._ import Properties.isMac @@ -17,22 +15,16 @@ import Properties.isMac trait InteractiveReader { val interactive: Boolean - def init(): Unit def reset(): Unit - def history: History def completion: Completion - def eraseLine(): Unit def redrawLine(): Unit - def currentLine: String def readYesOrNo(prompt: String, alt: => Boolean): Boolean = readOneKey(prompt) match { case 'y' => true case 'n' => false case _ => alt } - def readAssumingNo(prompt: String) = readYesOrNo(prompt, false) - def readAssumingYes(prompt: String) = readYesOrNo(prompt, true) protected def readOneLine(prompt: String): String protected def readOneKey(prompt: String): Int @@ -52,6 +44,6 @@ object InteractiveReader { def apply(): InteractiveReader = SimpleReader() @deprecated("Use `apply` instead.", "2.9.0") - def createDefault(): InteractiveReader = apply() + def createDefault(): InteractiveReader = apply() // used by sbt } diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala b/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala index 219cb35242..19fa562234 100644 --- a/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala +++ b/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala @@ -6,10 +6,9 @@ package scala.tools.nsc package interpreter -import scala.tools.jline._ -import scala.tools.jline.console.completer._ import Completion._ import scala.collection.mutable.ListBuffer +import scala.reflect.internal.util.StringOps.longestCommonPrefix // REPL completor - queries supplied interpreter for valid // completions based on current contents of buffer. @@ -29,9 +28,6 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput if (isModule) getModuleIfDefined(name) else getModuleIfDefined(name) ) - def getType(name: String, isModule: Boolean) = getSymbol(name, isModule).tpe - def typeOf(name: String) = getType(name, false) - def moduleOf(name: String) = getType(name, true) trait CompilerCompletion { def tp: Type @@ -47,12 +43,11 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput def anyRefMethodsToShow = Set("isInstanceOf", "asInstanceOf", "toString") def tos(sym: Symbol): String = sym.decodedName - def memberNamed(s: String) = afterTyper(effectiveTp member newTermName(s)) - def hasMethod(s: String) = memberNamed(s).isMethod + def memberNamed(s: String) = exitingTyper(effectiveTp member newTermName(s)) // XXX we'd like to say "filterNot (_.isDeprecated)" but this causes the // compiler to crash for reasons not yet known. - def members = afterTyper((effectiveTp.nonPrivateMembers.toList ++ anyMembers) filter (_.isPublic)) + def members = exitingTyper((effectiveTp.nonPrivateMembers.toList ++ anyMembers) filter (_.isPublic)) def methods = members.toList filter (_.isMethod) def packages = members.toList filter (_.isPackage) def aliases = members.toList filter (_.isAliasType) @@ -111,7 +106,7 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput def excludeNames: List[String] = (anyref.methodNames filterNot anyRefMethodsToShow) :+ "_root_" def methodSignatureString(sym: Symbol) = { - IMain stripString afterTyper(new MethodSymbolOutput(sym).methodString()) + IMain stripString exitingTyper(new MethodSymbolOutput(sym).methodString()) } def exclude(name: String): Boolean = ( @@ -280,10 +275,6 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput if (parsed.isEmpty) xs map ("." + _) else xs } - // generic interface for querying (e.g. interpreter loop, testing) - def completions(buf: String): List[String] = - topLevelFor(Parsed.dotted(buf + ".", buf.length + 1)) - def completer(): ScalaCompleter = new JLineTabCompletion /** This gets a little bit hairy. It's no small feat delegating everything @@ -301,16 +292,6 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput def isConsecutiveTabs(buf: String, cursor: Int) = cursor == lastCursor && buf == lastBuf - // Longest common prefix - def commonPrefix(xs: List[String]): String = { - if (xs.isEmpty || xs.contains("")) "" - else xs.head.head match { - case ch => - if (xs.tail forall (_.head == ch)) "" + ch + commonPrefix(xs map (_.tail)) - else "" - } - } - // This is jline's entry point for completion. override def complete(buf: String, cursor: Int): Candidates = { verbosity = if (isConsecutiveTabs(buf, cursor)) verbosity + 1 else 0 @@ -324,7 +305,7 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput val newCursor = if (winners contains "") p.cursor else { - val advance = commonPrefix(winners) + val advance = longestCommonPrefix(winners) lastCursor = p.position + advance.length lastBuf = (buf take p.position) + advance repldbg("tryCompletion(%s, _) lastBuf = %s, lastCursor = %s, p.position = %s".format( @@ -335,8 +316,7 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput Some(Candidates(newCursor, winners)) } - def mkDotted = Parsed.dotted(buf, cursor) withVerbosity verbosity - def mkUndelimited = Parsed.undelimited(buf, cursor) withVerbosity verbosity + def mkDotted = Parsed.dotted(buf, cursor) withVerbosity verbosity // a single dot is special cased to completion on the previous result def lastResultCompletion = diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala index 10f972452f..a620c7c75a 100644 --- a/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala +++ b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala @@ -9,9 +9,7 @@ package interpreter import scala.tools.jline.console.ConsoleReader import scala.tools.jline.console.completer._ import session._ -import scala.collection.JavaConverters._ import Completion._ -import io.Streamable.slurp /** * Reads from the console using JLine. @@ -25,7 +23,6 @@ class JLineReader(_completion: => Completion) extends InteractiveReader { private def term = consoleReader.getTerminal() def reset() = term.reset() - def init() = term.init() def scalaToJline(tc: ScalaCompleter): Completer = new Completer { def complete(_buf: String, cursor: Int, candidates: JList[CharSequence]): Int = { @@ -37,8 +34,6 @@ class JLineReader(_completion: => Completion) extends InteractiveReader { } class JLineConsoleReader extends ConsoleReader with ConsoleReaderHelper { - // working around protected/trait/java insufficiencies. - def goBack(num: Int): Unit = back(num) def readOneKey(prompt: String) = { this.print(prompt) this.flush() @@ -46,7 +41,6 @@ class JLineReader(_completion: => Completion) extends InteractiveReader { } def eraseLine() = consoleReader.resetPromptLine("", "", 0) def redrawLineAndFlush(): Unit = { flush() ; drawLine() ; flush() } - // override def readLine(prompt: String): String // A hook for running code after the repl is done initializing. lazy val postInit: Unit = { @@ -65,11 +59,7 @@ class JLineReader(_completion: => Completion) extends InteractiveReader { } } - def currentLine = consoleReader.getCursorBuffer.buffer.toString def redrawLine() = consoleReader.redrawLineAndFlush() - def eraseLine() = consoleReader.eraseLine() - // Alternate implementation, not sure if/when I need this. - // def eraseLine() = while (consoleReader.delete()) { } def readOneLine(prompt: String) = consoleReader readLine prompt def readOneKey(prompt: String) = consoleReader readOneKey prompt } diff --git a/src/compiler/scala/tools/nsc/interpreter/Logger.scala b/src/compiler/scala/tools/nsc/interpreter/Logger.scala index aeb25fc688..7407daf8d0 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Logger.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Logger.scala @@ -11,8 +11,4 @@ trait Logger { def isDebug: Boolean def isTrace: Boolean def out: JPrintWriter - - def info(msg: => Any): Unit = if (isInfo) out println msg - def debug(msg: => Any): Unit = if (isDebug) out println msg - def trace(msg: => Any): Unit = if (isTrace) out println msg } diff --git a/src/compiler/scala/tools/nsc/interpreter/LoopCommands.scala b/src/compiler/scala/tools/nsc/interpreter/LoopCommands.scala index 60325ece30..39979c8fbe 100644 --- a/src/compiler/scala/tools/nsc/interpreter/LoopCommands.scala +++ b/src/compiler/scala/tools/nsc/interpreter/LoopCommands.scala @@ -19,13 +19,8 @@ class ProcessResult(val line: String) { val exitCode = builder ! logger def lines = buffer.toList - def show() = lines foreach println override def toString = "`%s` (%d lines, exit %d)".format(line, buffer.size, exitCode) } -object ProcessResult { - implicit def processResultToOutputLines(pr: ProcessResult): List[String] = pr.lines - def apply(line: String): ProcessResult = new ProcessResult(line) -} trait LoopCommands { protected def out: JPrintWriter @@ -35,14 +30,6 @@ trait LoopCommands { // a single interpreter command abstract class LoopCommand(val name: String, val help: String) extends (String => Result) { - private var _longHelp: String = null - final def defaultHelp = usageMsg + " (no extended help available.)" - def hasLongHelp = _longHelp != null || longHelp != defaultHelp - def withLongHelp(text: String): this.type = { _longHelp = text ; this } - def longHelp = _longHelp match { - case null => defaultHelp - case text => text - } def usage: String = "" def usageMsg: String = ":" + name + ( if (usage == "") "" else " " + usage @@ -54,11 +41,6 @@ trait LoopCommands { "usage is " + usageMsg Result(true, None) } - - def onError(msg: String) = { - out.println("error: " + msg) - showUsage() - } } object LoopCommand { def nullary(name: String, help: String, f: () => Result): LoopCommand = @@ -67,9 +49,6 @@ trait LoopCommands { def cmd(name: String, usage: String, help: String, f: String => Result): LoopCommand = if (usage == "") new NullaryCmd(name, help, f) else new LineCmd(name, usage, help, f) - - def varargs(name: String, usage: String, help: String, f: List[String] => Result): LoopCommand = - new VarArgsCmd(name, usage, help, f) } class NullaryCmd(name: String, help: String, f: String => Result) extends LoopCommand(name, help) { diff --git a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala index 12fb8f1507..381dfeb261 100644 --- a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala +++ b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala @@ -7,8 +7,6 @@ package scala.tools.nsc package interpreter import scala.collection.{ mutable, immutable } -import scala.PartialFunction.cond -import scala.reflect.internal.Chars import scala.reflect.internal.Flags._ import scala.language.implicitConversions @@ -21,8 +19,6 @@ trait MemberHandlers { private def codegenln(leadingPlus: Boolean, xs: String*): String = codegen(leadingPlus, (xs ++ Array("\n")): _*) private def codegenln(xs: String*): String = codegenln(true, xs: _*) - - private def codegen(xs: String*): String = codegen(true, xs: _*) private def codegen(leadingPlus: Boolean, xs: String*): String = { val front = if (leadingPlus) "+ " else "" front + (xs map string2codeQuoted mkString " + ") @@ -55,21 +51,20 @@ trait MemberHandlers { def chooseHandler(member: Tree): MemberHandler = member match { case member: DefDef => new DefHandler(member) case member: ValDef => new ValHandler(member) - case member: Assign => new AssignHandler(member) case member: ModuleDef => new ModuleHandler(member) case member: ClassDef => new ClassHandler(member) case member: TypeDef => new TypeAliasHandler(member) + case member: Assign => new AssignHandler(member) case member: Import => new ImportHandler(member) case DocDef(_, documented) => chooseHandler(documented) case member => new GenericHandler(member) } sealed abstract class MemberDefHandler(override val member: MemberDef) extends MemberHandler(member) { - def symbol = if (member.symbol eq null) NoSymbol else member.symbol - def name: Name = member.name - def mods: Modifiers = member.mods - def keyword = member.keyword - def prettyName = name.decode + override def name: Name = member.name + def mods: Modifiers = member.mods + def keyword = member.keyword + def prettyName = name.decode override def definesImplicit = member.mods.isImplicit override def definesTerm: Option[TermName] = Some(name.toTermName) filter (_ => name.isTermName) @@ -81,9 +76,11 @@ trait MemberHandlers { * in a single interpreter request. */ sealed abstract class MemberHandler(val member: Tree) { + def name: Name = nme.NO_NAME + def path = intp.originalPath(symbol) + def symbol = if (member.symbol eq null) NoSymbol else member.symbol def definesImplicit = false def definesValue = false - def isLegalTopLevel = false def definesTerm = Option.empty[TermName] def definesType = Option.empty[TypeName] @@ -91,7 +88,6 @@ trait MemberHandlers { lazy val referencedNames = ImportVarsTraverser(member) def importedNames = List[Name]() def definedNames = definesTerm.toList ++ definesType.toList - def definedOrImported = definedNames ++ importedNames def definedSymbols = List[Symbol]() def extraCodeToEvaluate(req: Request): String = "" @@ -114,10 +110,10 @@ trait MemberHandlers { // if this is a lazy val we avoid evaluating it here val resultString = if (mods.isLazy) codegenln(false, "<lazy>") - else any2stringOf(req fullPath name, maxStringElements) + else any2stringOf(path, maxStringElements) val vidString = - if (replProps.vids) """" + " @ " + "%%8x".format(System.identityHashCode(%s)) + " """.trim.format(req fullPath name) + if (replProps.vids) s"""" + " @ " + "%%8x".format(System.identityHashCode($path)) + " """.trim else "" """ + "%s%s: %s = " + %s""".format(prettyName, vidString, string2code(req typeOf name), resultString) @@ -136,7 +132,7 @@ trait MemberHandlers { class AssignHandler(member: Assign) extends MemberHandler(member) { val Assign(lhs, rhs) = member - val name = newTermName(freshInternalVarName()) + override lazy val name = newTermName(freshInternalVarName()) override def definesTerm = Some(name) override def definesValue = true @@ -155,15 +151,14 @@ trait MemberHandlers { class ModuleHandler(module: ModuleDef) extends MemberDefHandler(module) { override def definesTerm = Some(name) override def definesValue = true - override def isLegalTopLevel = true override def resultExtractionCode(req: Request) = codegenln("defined module ", name) } class ClassHandler(member: ClassDef) extends MemberDefHandler(member) { + override def definedSymbols = List(symbol, symbol.companionSymbol) filterNot (_ == NoSymbol) override def definesType = Some(name.toTypeName) override def definesTerm = Some(name.toTermName) filter (_ => mods.isCase) - override def isLegalTopLevel = true override def resultExtractionCode(req: Request) = codegenln("defined %s %s".format(keyword, name)) @@ -179,21 +174,11 @@ trait MemberHandlers { class ImportHandler(imp: Import) extends MemberHandler(imp) { val Import(expr, selectors) = imp - def targetType: Type = intp.typeOfExpression("" + expr) - override def isLegalTopLevel = true - - def createImportForName(name: Name): String = { - selectors foreach { - case sel @ ImportSelector(old, _, `name`, _) => return "import %s.{ %s }".format(expr, sel) - case _ => () - } - "import %s.%s".format(expr, name) + def targetType = intp.global.rootMirror.getModuleIfDefined("" + expr) match { + case NoSymbol => intp.typeOfExpression("" + expr) + case sym => sym.thisType } - // TODO: Need to track these specially to honor Predef masking attempts, - // because they must be the leading imports in the code generated for each - // line. We can use the same machinery as Contexts now, anyway. - def isPredefImport = isReferenceToPredef(expr) - + private def importableTargetMembers = importableMembers(targetType).toList // wildcard imports, e.g. import foo._ private def selectorWild = selectors filter (_.name == nme.USCOREkw) // renamed imports, e.g. import foo.{ bar => baz } @@ -202,22 +187,16 @@ trait MemberHandlers { /** Whether this import includes a wildcard import */ val importsWildcard = selectorWild.nonEmpty - /** Whether anything imported is implicit .*/ - def importsImplicit = implicitSymbols.nonEmpty - def implicitSymbols = importedSymbols filter (_.isImplicit) def importedSymbols = individualSymbols ++ wildcardSymbols - lazy val individualSymbols: List[Symbol] = - beforePickler(individualNames map (targetType nonPrivateMember _)) - - lazy val wildcardSymbols: List[Symbol] = - if (importsWildcard) beforePickler(targetType.nonPrivateMembers.toList) - else Nil + private val selectorNames = selectorRenames filterNot (_ == nme.USCOREkw) flatMap (_.bothNames) toSet + lazy val individualSymbols: List[Symbol] = exitingTyper(importableTargetMembers filter (m => selectorNames(m.name))) + lazy val wildcardSymbols: List[Symbol] = exitingTyper(if (importsWildcard) importableTargetMembers else Nil) /** Complete list of names imported by a wildcard */ lazy val wildcardNames: List[Name] = wildcardSymbols map (_.name) - lazy val individualNames: List[Name] = selectorRenames filterNot (_ == nme.USCOREkw) flatMap (_.bothNames) + lazy val individualNames: List[Name] = individualSymbols map (_.name) /** The names imported by this statement */ override lazy val importedNames: List[Name] = wildcardNames ++ individualNames diff --git a/src/compiler/scala/tools/nsc/interpreter/NamedParam.scala b/src/compiler/scala/tools/nsc/interpreter/NamedParam.scala index eff0ef59c5..627a881cae 100644 --- a/src/compiler/scala/tools/nsc/interpreter/NamedParam.scala +++ b/src/compiler/scala/tools/nsc/interpreter/NamedParam.scala @@ -14,14 +14,10 @@ import scala.reflect.{ClassTag, classTag} trait NamedParamCreator { protected def freshName: () => String - def apply(name: String, tpe: String, value: Any): NamedParam = NamedParamClass(name, tpe, value) def apply[T: ru.TypeTag : ClassTag](name: String, x: T): NamedParam = new Typed[T](name, x) def apply[T: ru.TypeTag : ClassTag](x: T): NamedParam = apply(freshName(), x) - def clazz(name: String, x: Any): NamedParam = new Untyped(name, x) - def clazz(x: Any): NamedParam = clazz(freshName(), x) - implicit def namedValue[T: ru.TypeTag : ClassTag](name: String, x: T): NamedParam = apply(name, x) implicit def tuple[T: ru.TypeTag : ClassTag](pair: (String, T)): NamedParam = apply(pair._1, pair._2) } diff --git a/src/compiler/scala/tools/nsc/interpreter/Naming.scala b/src/compiler/scala/tools/nsc/interpreter/Naming.scala index 0d03a8669a..41ddf23de4 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Naming.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Naming.scala @@ -78,7 +78,6 @@ trait Naming { private lazy val userVar = new NameCreator(sessionNames.res) // var name, like res0 private lazy val internalVar = new NameCreator(sessionNames.ires) // internal var name, like $ires0 - def isLineName(name: String) = (name startsWith sessionNames.line) && (name stripPrefix sessionNames.line forall (_.isDigit)) def isUserVarName(name: String) = userVar didGenerate name def isInternalVarName(name: String) = internalVar didGenerate name diff --git a/src/compiler/scala/tools/nsc/interpreter/Parsed.scala b/src/compiler/scala/tools/nsc/interpreter/Parsed.scala index b0be956df8..672a6fd28f 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Parsed.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Parsed.scala @@ -6,7 +6,6 @@ package scala.tools.nsc package interpreter -import scala.tools.jline.console.completer.ArgumentCompleter.{ ArgumentDelimiter, ArgumentList } import util.returning /** One instance of a command buffer. @@ -18,7 +17,6 @@ class Parsed private ( ) extends Delimited { def isEmpty = args.isEmpty def isUnqualified = args.size == 1 - def isQualified = args.size > 1 def isAtStart = cursor <= 0 private var _verbosity = 0 @@ -32,7 +30,6 @@ class Parsed private ( def bufferTail = new Parsed(buffer drop headLength, cursor - headLength, delimited) withVerbosity verbosity def prev = new Parsed(buffer, cursor - 1, delimited) withVerbosity verbosity - def next = new Parsed(buffer, cursor + 1, delimited) withVerbosity verbosity def currentChar = buffer(cursor) def currentArg = args.last def position = @@ -42,8 +39,6 @@ class Parsed private ( def isFirstDelimiter = !isEmpty && isDelimiterChar(buffer.head) def isLastDelimiter = !isEmpty && isDelimiterChar(buffer.last) - def firstIfDelimiter = if (isFirstDelimiter) buffer.head.toString else "" - def lastIfDelimiter = if (isLastDelimiter) buffer.last.toString else "" def isQuoted = false // TODO def isEscaped = !isAtStart && isEscapeChar(currentChar) && !isEscapeChar(prev.currentChar) @@ -57,13 +52,9 @@ object Parsed { private def onull(s: String) = if (s == null) "" else s - def apply(s: String): Parsed = apply(onull(s), onull(s).length) def apply(s: String, cursor: Int): Parsed = apply(onull(s), cursor, DefaultDelimiters) def apply(s: String, cursor: Int, delimited: Char => Boolean): Parsed = new Parsed(onull(s), cursor, delimited) - def dotted(s: String): Parsed = dotted(onull(s), onull(s).length) def dotted(s: String, cursor: Int): Parsed = new Parsed(onull(s), cursor, _ == '.') - - def undelimited(s: String, cursor: Int): Parsed = new Parsed(onull(s), cursor, _ => false) } diff --git a/src/compiler/scala/tools/nsc/interpreter/Phased.scala b/src/compiler/scala/tools/nsc/interpreter/Phased.scala index 638944713a..f625124e70 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Phased.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Phased.scala @@ -6,7 +6,7 @@ package scala.tools.nsc package interpreter -import scala.collection.{ mutable, immutable } +import scala.collection.immutable import scala.language.implicitConversions /** Mix this into an object and use it as a phasing @@ -24,7 +24,6 @@ trait Phased { case NoPhaseName => false case name => active = name ; true } - def getMulti = multi def setMulti(phases: Seq[PhaseName]): Boolean = { if (phases contains NoPhaseName) false else { @@ -66,16 +65,8 @@ trait Phased { try parseInternal(str) catch { case _: Exception => NoPhaseName } - def apply[T](body: => T) = immutable.SortedMap[PhaseName, T](atMap(PhaseName.all)(body): _*) - - def atCurrent[T](body: => T): T = atPhase(get)(body) + def atCurrent[T](body: => T): T = enteringPhase(get)(body) def multi[T](body: => T): Seq[T] = multi map (ph => at(ph)(body)) - def all[T](body: => T): Seq[T] = atMulti(PhaseName.all)(body) - def show[T](body: => T): Seq[T] = { - val pairs = atMap(PhaseName.all)(body) - pairs foreach { case (ph, op) => Console.println("%15s -> %s".format(ph, op.toString take 240)) } - pairs map (_._2) - } def at[T](ph: PhaseName)(body: => T): T = { val saved = get @@ -90,11 +81,6 @@ trait Phased { finally setMulti(saved) } - def showAt[T](phs: Seq[PhaseName])(body: => T): Unit = - atMap[T](phs)(body) foreach { - case (ph, op) => Console.println("%15s -> %s".format(ph, op.toString take 240)) - } - def atMap[T](phs: Seq[PhaseName])(body: => T): Seq[(PhaseName, T)] = phs zip atMulti(phs)(body) @@ -112,16 +98,12 @@ trait Phased { def apply(id: Int): PhaseName = all find (_.id == id) getOrElse NoPhaseName implicit def apply(s: String): PhaseName = nameMap(s) - implicit def defaultPhaseName: PhaseName = active } sealed abstract class PhaseName { lazy val id = phase.id lazy val name = toString.toLowerCase def phase = currentRun.phaseNamed(name) def isEmpty = this eq NoPhaseName - - // Execute some code during this phase. - def apply[T](body: => T): T = atPhase(phase)(body) } case object Parser extends PhaseName @@ -158,5 +140,4 @@ trait Phased { } implicit def phaseEnumToPhase(name: PhaseName): Phase = name.phase - implicit def phaseNameToPhase(name: String): Phase = currentRun.phaseNamed(name) } diff --git a/src/compiler/scala/tools/nsc/interpreter/Power.scala b/src/compiler/scala/tools/nsc/interpreter/Power.scala index 5e6bf8824d..e517a16b32 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Power.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Power.scala @@ -8,8 +8,6 @@ package interpreter import scala.collection.{ mutable, immutable } import scala.util.matching.Regex -import scala.reflect.internal.util.{ BatchSourceFile } -import session.{ History } import scala.io.Codec import java.net.{ URL, MalformedURLException } import io.{ Path } @@ -48,7 +46,6 @@ class Power[ReplValsImpl <: ReplVals : ru.TypeTag: ClassTag](val intp: IMain, re import intp.{ beQuietDuring, typeOfExpression, interpret, parse } import intp.global._ import definitions.{ compilerTypeFromTag, compilerSymbolFromTag} - import rootMirror.{ getClassIfDefined, getModuleIfDefined } abstract class SymSlurper { def isKeep(sym: Symbol): Boolean @@ -73,7 +70,7 @@ class Power[ReplValsImpl <: ReplVals : ru.TypeTag: ClassTag](val intp: IMain, re pass += 1 val (repeats, unseen) = todo partition seen unseenHistory += unseen.size - if (opt.verbose) { + if (settings.verbose.value) { println("%3d %s accumulated, %s discarded. This pass: %s unseen, %s repeats".format( pass, keep.size, discarded, unseen.size, repeats.size)) } @@ -148,21 +145,10 @@ class Power[ReplValsImpl <: ReplVals : ru.TypeTag: ClassTag](val intp: IMain, re // First we create the ReplVals instance and bind it to $r intp.bind("$r", replVals) // Then we import everything from $r. - intp interpret ("import " + intp.pathToTerm("$r") + "._") + intp interpret ("import " + intp.originalPath("$r") + "._") // And whatever else there is to do. init.lines foreach (intp interpret _) } - def valsDescription: String = { - def to_str(m: Symbol) = "%12s %s".format( - m.decodedName, "" + elimRefinement(m.accessedOrSelf.tpe) stripPrefix "scala.tools.nsc.") - - ( rutil.info[ReplValsImpl].membersDeclared - filter (m => m.isPublic && !m.hasModuleFlag && !m.isConstructor) - sortBy (_.decodedName) - map to_str - mkString ("Name and type of values imported into the repl in power mode.\n\n", "\n", "") - ) - } trait LowPriorityInternalInfo { implicit def apply[T: ru.TypeTag : ClassTag] : InternalInfo[T] = new InternalInfo[T](None) @@ -175,12 +161,7 @@ class Power[ReplValsImpl <: ReplVals : ru.TypeTag: ClassTag](val intp: IMain, re * symbol, by only implicitly installing one method, "?", and the rest * of the conveniences exist on that wrapper. */ - trait LowPriorityInternalInfoWrapper { - implicit def apply[T: ru.TypeTag : ClassTag] : InternalInfoWrapper[T] = new InternalInfoWrapper[T](None) - } - object InternalInfoWrapper extends LowPriorityInternalInfoWrapper { - - } + trait LowPriorityInternalInfoWrapper { } class InternalInfoWrapper[T: ru.TypeTag : ClassTag](value: Option[T] = None) { def ? : InternalInfo[T] = new InternalInfo[T](value) } @@ -190,7 +171,6 @@ class Power[ReplValsImpl <: ReplVals : ru.TypeTag: ClassTag](val intp: IMain, re * customizable symbol filter (had to hardcode no-spec to reduce noise) */ class InternalInfo[T](value: Option[T] = None)(implicit typeEvidence: ru.TypeTag[T], runtimeClassEvidence: ClassTag[T]) { - private def newInfo[U: ru.TypeTag : ClassTag](value: U): InternalInfo[U] = new InternalInfo[U](Some(value)) private def isSpecialized(s: Symbol) = s.name.toString contains "$mc" private def isImplClass(s: Symbol) = s.name.toString endsWith "$class" @@ -201,47 +181,15 @@ class Power[ReplValsImpl <: ReplVals : ru.TypeTag: ClassTag](val intp: IMain, re || s.isAnonOrRefinementClass || s.isAnonymousFunction ) - def symbol = compilerSymbolFromTag(tag) - def tpe = compilerTypeFromTag(tag) - def name = symbol.name - def companion = symbol.companionSymbol - def info = symbol.info - def moduleClass = symbol.moduleClass - def owner = symbol.owner - def owners = symbol.ownerChain drop 1 - def signature = symbol.defString - - def decls = info.decls - def declsOverride = membersDeclared filter (_.isOverride) - def declsOriginal = membersDeclared filterNot (_.isOverride) - + def symbol = compilerSymbolFromTag(tag) + def tpe = compilerTypeFromTag(tag) def members = membersUnabridged filterNot excludeMember def membersUnabridged = tpe.members.toList - def membersDeclared = members filterNot excludeMember - def membersInherited = members filterNot (membersDeclared contains _) - def memberTypes = members filter (_.name.isTypeName) - def memberMethods = members filter (_.isMethod) - - def pkg = symbol.enclosingPackage - def pkgName = pkg.fullName - def pkgClass = symbol.enclosingPackageClass - def pkgMembers = pkg.info.members filterNot excludeMember - def pkgClasses = pkgMembers filter (s => s.isClass && s.isDefinedInPackage) - def pkgSymbols = new PackageSlurper(pkgClass).slurp() filterNot excludeMember - - def tag = typeEvidence - def runtimeClass = runtimeClassEvidence.runtimeClass - def shortClass = runtimeClass.getName split "[$.]" last - - def baseClasses = tpe.baseClasses - def baseClassDecls = mapFrom(baseClasses)(_.info.decls.toList.sortBy(_.name)) - def ancestors = baseClasses drop 1 - def ancestorDeclares(name: String) = ancestors filter (_.info member newTermName(name) ne NoSymbol) - def baseTypes = tpe.baseTypeSeq.toList - - def <:<[U: ru.TypeTag : ClassTag](other: U) = tpe <:< newInfo(other).tpe - def lub[U: ru.TypeTag : ClassTag](other: U) = intp.global.lub(List(tpe, newInfo(other).tpe)) - def glb[U: ru.TypeTag : ClassTag](other: U) = intp.global.glb(List(tpe, newInfo(other).tpe)) + def pkg = symbol.enclosingPackage + def tag = typeEvidence + def runtimeClass = runtimeClassEvidence.runtimeClass + def shortClass = runtimeClass.getName split "[$.]" last + def baseClasses = tpe.baseClasses override def toString = value match { case Some(x) => "%s (%s)".format(x, shortClass) @@ -267,7 +215,6 @@ class Power[ReplValsImpl <: ReplVals : ru.TypeTag: ClassTag](val intp: IMain, re } object Prettifier extends LowPriorityPrettifier { def stringOf(x: Any): String = scala.runtime.ScalaRunTime.stringOf(x) - def prettify[T](value: T): TraversableOnce[String] = default[T] prettify value def default[T] = new Prettifier[T] { def prettify(x: T): TraversableOnce[String] = AnyPrettifier prettify x def show(x: T): Unit = AnyPrettifier show x @@ -277,45 +224,21 @@ class Power[ReplValsImpl <: ReplVals : ru.TypeTag: ClassTag](val intp: IMain, re def show(x: T): Unit def prettify(x: T): TraversableOnce[String] - def show(xs: TraversableOnce[T]): Unit = prettify(xs) foreach println def prettify(xs: TraversableOnce[T]): TraversableOnce[String] = xs flatMap (x => prettify(x)) } abstract class PrettifierClass[T: Prettifier]() { val pretty = implicitly[Prettifier[T]] - import pretty._ - def value: Seq[T] def pp(f: Seq[T] => Seq[T]): Unit = pretty prettify f(value) foreach (StringPrettifier show _) def freq[U](p: T => U) = (value.toSeq groupBy p mapValues (_.size)).toList sortBy (-_._2) map (_.swap) - def ppfreq[U](p: T => U): Unit = freq(p) foreach { case (count, key) => println("%5d %s".format(count, key)) } - - def |[U](f: Seq[T] => Seq[U]): Seq[U] = f(value) - def ^^[U](f: T => U): Seq[U] = value map f - def ^?[U](pf: PartialFunction[T, U]): Seq[U] = value collect pf - def >>!(implicit ord: Ordering[T]): Unit = pp(_.sorted.distinct) def >>(implicit ord: Ordering[T]): Unit = pp(_.sorted) def >!(): Unit = pp(_.distinct) def >(): Unit = pp(identity) - - def >#(): Unit = this ># (identity[T] _) - def >#[U](p: T => U): Unit = this ppfreq p - - def >?(p: T => Boolean): Unit = pp(_ filter p) - def >?(s: String): Unit = pp(_ filter (_.toString contains s)) - def >?(r: Regex): Unit = pp(_ filter (_.toString matches fixRegex(r))) - - private def fixRegex(r: scala.util.matching.Regex): String = { - val s = r.pattern.toString - val prefix = if (s startsWith "^") "" else """^.*?""" - val suffix = if (s endsWith "$") "" else """.*$""" - - prefix + s + suffix - } } class MultiPrettifierClass[T: Prettifier](val value: Seq[T]) extends PrettifierClass[T]() { } @@ -339,17 +262,11 @@ class Power[ReplValsImpl <: ReplVals : ru.TypeTag: ClassTag](val intp: IMain, re class RichReplURL(url: URL)(implicit codec: Codec) { def slurp(): String = io.Streamable.slurp(url) } - class RichSymbolList(syms: List[Symbol]) { - def sigs = syms map (_.defString) - def infos = syms map (_.info) - } trait Implicits1 { // fallback implicit def replPrinting[T](x: T)(implicit pretty: Prettifier[T] = Prettifier.default[T]) = new SinglePrettifierClass[T](x) - - implicit def liftToTypeName(s: String): TypeName = newTypeName(s) } trait Implicits2 extends Implicits1 { class RichSymbol(sym: Symbol) { @@ -374,26 +291,13 @@ class Power[ReplValsImpl <: ReplVals : ru.TypeTag: ClassTag](val intp: IMain, re implicit def replInputStream(in: InputStream)(implicit codec: Codec) = new RichInputStream(in) implicit def replEnhancedURLs(url: URL)(implicit codec: Codec): RichReplURL = new RichReplURL(url)(codec) - - implicit def liftToTermName(s: String): TermName = newTermName(s) - implicit def replListOfSymbols(xs: List[Symbol]) = new RichSymbolList(xs) } trait ReplUtilities { - // [Eugene to Paul] needs review! - // def module[T: Manifest] = getModuleIfDefined(manifest[T].erasure.getName stripSuffix nme.MODULE_SUFFIX_STRING) - // def clazz[T: Manifest] = getClassIfDefined(manifest[T].erasure.getName) def module[T: ru.TypeTag] = ru.typeOf[T].typeSymbol.suchThat(_.isPackage) def clazz[T: ru.TypeTag] = ru.typeOf[T].typeSymbol.suchThat(_.isClass) def info[T: ru.TypeTag : ClassTag] = InternalInfo[T] def ?[T: ru.TypeTag : ClassTag] = InternalInfo[T] - def url(s: String) = { - try new URL(s) - catch { case _: MalformedURLException => - if (Path(s).exists) Path(s).toURL - else new URL("http://" + s) - } - } def sanitize(s: String): String = sanitize(s.getBytes()) def sanitize(s: Array[Byte]): String = (s map { case x if x.toChar.isControl => '?' @@ -411,20 +315,12 @@ class Power[ReplValsImpl <: ReplVals : ru.TypeTag: ClassTag](val intp: IMain, re lazy val rutil: ReplUtilities = new ReplUtilities { } lazy val phased: Phased = new { val global: intp.global.type = intp.global } with Phased { } - def context(code: String) = analyzer.rootContext(unit(code)) - def source(code: String) = newSourceFile(code) - def unit(code: String) = newCompilationUnit(code) - def trees(code: String) = parse(code) getOrElse Nil - def typeOf(id: String) = intp.typeOfExpression(id) + def unit(code: String) = newCompilationUnit(code) + def trees(code: String) = parse(code) getOrElse Nil - override def toString = """ + override def toString = s""" |** Power mode status ** - |Default phase: %s - |Names: %s - |Identifiers: %s - """.stripMargin.format( - phased.get, - intp.allDefinedNames mkString " ", - intp.unqualifiedIds mkString " " - ) + |Default phase: ${phased.get} + |Names: ${intp.unqualifiedIds mkString " "} + """.stripMargin } diff --git a/src/compiler/scala/tools/nsc/interpreter/ReplConfig.scala b/src/compiler/scala/tools/nsc/interpreter/ReplConfig.scala index 7cd0f436c4..3392ea0b5e 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ReplConfig.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ReplConfig.scala @@ -14,9 +14,7 @@ trait ReplConfig { lazy val replProps = new ReplProps class TapMaker[T](x: T) { - def tapInfo(msg: => String): T = tap(x => replinfo(parens(x))) def tapDebug(msg: => String): T = tap(x => repldbg(parens(x))) - def tapTrace(msg: => String): T = tap(x => repltrace(parens(x))) def tap[U](f: T => U): T = { f(x) x @@ -28,12 +26,6 @@ trait ReplConfig { try Console println msg catch { case x: AssertionError => Console.println("Assertion error printing debugging output: " + x) } - private[nsc] def repldbgex(ex: Throwable): Unit = { - if (isReplDebug) { - echo("Caught/suppressing: " + ex) - ex.printStackTrace - } - } private[nsc] def repldbg(msg: => String) = if (isReplDebug) echo(msg) private[nsc] def repltrace(msg: => String) = if (isReplTrace) echo(msg) private[nsc] def replinfo(msg: => String) = if (isReplInfo) echo(msg) @@ -45,14 +37,10 @@ trait ReplConfig { repltrace(stackTraceString(unwrap(t))) alt } - private[nsc] def substituteAndLog[T](alt: => T)(body: => T): T = - substituteAndLog("" + alt, alt)(body) private[nsc] def substituteAndLog[T](label: String, alt: => T)(body: => T): T = { try body catch logAndDiscard(label, alt) } - private[nsc] def squashAndLog(label: String)(body: => Unit): Unit = - substituteAndLog(label, ())(body) def isReplTrace: Boolean = replProps.trace def isReplDebug: Boolean = replProps.debug || isReplTrace diff --git a/src/compiler/scala/tools/nsc/interpreter/ReplDir.scala b/src/compiler/scala/tools/nsc/interpreter/ReplDir.scala new file mode 100644 index 0000000000..9fbf64acb5 --- /dev/null +++ b/src/compiler/scala/tools/nsc/interpreter/ReplDir.scala @@ -0,0 +1,48 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2012 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools.nsc +package interpreter + +import io.VirtualDirectory +import settings.MutableSettings +import scala.reflect.io.{ AbstractFile, PlainDirectory, Directory } +import scala.collection.generic.Clearable + +/** Directory to save .class files to. */ +trait ReplDir extends AbstractFile with Clearable { } + +private class ReplVirtualDir() extends VirtualDirectory("(memory)", None) with ReplDir { } +private class ReplRealDir(dir: Directory) extends PlainDirectory(dir) with ReplDir { + def clear() = { + dir.deleteRecursively() + dir.createDirectory() + } +} + +class ReplOutput(val dirSetting: MutableSettings#StringSetting) { + // outdir for generated classfiles - may be in-memory (the default), + // a generated temporary directory, or a specified outdir. + val dir: ReplDir = ( + if (dirSetting.isDefault) + new ReplVirtualDir() + else if (dirSetting.value == "") + new ReplRealDir(Directory.makeTemp("repl")) + else + new ReplRealDir(Directory(dirSetting.value)) + ) + + // print the contents hierarchically + def show(out: JPrintWriter) = { + def pp(root: AbstractFile, indentLevel: Int) { + val label = root.name + val spaces = " " * indentLevel + out.println(spaces + label) + if (root.isDirectory) + root.toList sortBy (_.name) foreach (x => pp(x, indentLevel + 1)) + } + pp(dir, 0) + } +} diff --git a/src/compiler/scala/tools/nsc/interpreter/ReplGlobal.scala b/src/compiler/scala/tools/nsc/interpreter/ReplGlobal.scala index 7c698a2f3e..16b22869e7 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ReplGlobal.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ReplGlobal.scala @@ -6,7 +6,6 @@ package scala.tools.nsc package interpreter -import reporters._ import typechecker.Analyzer /** A layer on top of Global so I can guarantee some extra diff --git a/src/compiler/scala/tools/nsc/interpreter/ReplProps.scala b/src/compiler/scala/tools/nsc/interpreter/ReplProps.scala index bc3e7a10d7..2364918494 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ReplProps.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ReplProps.scala @@ -13,15 +13,11 @@ class ReplProps { private def bool(name: String) = BooleanProp.keyExists(name) private def int(name: String) = IntProp(name) - val jlineDebug = bool("scala.tools.jline.internal.Log.debug") - val jlineTrace = bool("scala.tools.jline.internal.Log.trace") - val info = bool("scala.repl.info") val debug = bool("scala.repl.debug") val trace = bool("scala.repl.trace") val power = bool("scala.repl.power") - val replInitCode = Prop[JFile]("scala.repl.initcode") val replAutorunCode = Prop[JFile]("scala.repl.autoruncode") val powerInitCode = Prop[JFile]("scala.repl.power.initcode") val powerBanner = Prop[JFile]("scala.repl.power.banner") diff --git a/src/compiler/scala/tools/nsc/interpreter/ReplStrings.scala b/src/compiler/scala/tools/nsc/interpreter/ReplStrings.scala index f8ecc6c6fe..08472bbc64 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ReplStrings.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ReplStrings.scala @@ -6,8 +6,6 @@ package scala.tools.nsc package interpreter -import scala.collection.{ mutable, immutable } -import scala.PartialFunction.cond import scala.reflect.internal.Chars trait ReplStrings { @@ -31,5 +29,4 @@ trait ReplStrings { "scala.runtime.ScalaRunTime.replStringOf(%s, %s)".format(x, maxlen) def words(s: String) = s.trim split "\\s+" filterNot (_ == "") toList - def isQuoted(s: String) = (s.length >= 2) && (s.head == s.last) && ("\"'" contains s.head) } diff --git a/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala b/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala index 53478bdc5d..ea100b25f2 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala @@ -57,7 +57,6 @@ object ReplVals { */ def mkCompilerTypeFromTag[T <: Global](global: T) = { import global._ - import definitions._ /** We can't use definitions.compilerTypeFromTag directly because we're passing * it to map and the compiler refuses to perform eta expansion on a method diff --git a/src/compiler/scala/tools/nsc/interpreter/RichClass.scala b/src/compiler/scala/tools/nsc/interpreter/RichClass.scala index 4371f7fe05..36cdf65510 100644 --- a/src/compiler/scala/tools/nsc/interpreter/RichClass.scala +++ b/src/compiler/scala/tools/nsc/interpreter/RichClass.scala @@ -10,7 +10,6 @@ import scala.reflect.{ ClassTag, classTag } class RichClass[T](val clazz: Class[T]) { def toTag: ClassTag[T] = ClassTag[T](clazz) - def toTypeString: String = TypeStrings.fromClazz(clazz) // Sadly isAnonymousClass does not return true for scala anonymous // classes because our naming scheme is not doing well against the @@ -20,14 +19,12 @@ class RichClass[T](val clazz: Class[T]) { catch { case _: java.lang.InternalError => false } // good ol' "Malformed class name" ) - /** It's not easy... to be... me... */ - def supermans: List[ClassTag[_]] = supers map (_.toTag) + def supertags: List[ClassTag[_]] = supers map (_.toTag) def superNames: List[String] = supers map (_.getName) def interfaces: List[JClass] = supers filter (_.isInterface) def hasAncestorName(f: String => Boolean) = superNames exists f def hasAncestor(f: JClass => Boolean) = supers exists f - def hasAncestorInPackage(pkg: String) = hasAncestorName(_ startsWith (pkg + ".")) def supers: List[JClass] = { def loop(x: JClass): List[JClass] = x.getSuperclass match { diff --git a/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala b/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala index bccd8158ec..2d0917d91f 100644 --- a/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala +++ b/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala @@ -19,11 +19,8 @@ extends InteractiveReader val history = NoHistory val completion = NoCompletion - def init() = () def reset() = () - def eraseLine() = () def redrawLine() = () - def currentLine = "" def readOneLine(prompt: String): String = { if (interactive) { out.print(prompt) @@ -40,4 +37,4 @@ object SimpleReader { def apply(in: BufferedReader = defaultIn, out: JPrintWriter = defaultOut, interactive: Boolean = true): SimpleReader = new SimpleReader(in, out, interactive) -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala b/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala index 6abb52a649..239dbb8149 100644 --- a/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala +++ b/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala @@ -13,15 +13,12 @@ import NameTransformer._ import scala.reflect.runtime.{universe => ru} import scala.reflect.{ClassTag, classTag} import typechecker.DestructureTypes -import scala.reflect.internal.util.StringOps.ojoin -import scala.language.implicitConversions /** A more principled system for turning types into strings. */ trait StructuredTypeStrings extends DestructureTypes { val global: Global import global._ - import definitions._ case class LabelAndType(label: String, typeName: String) { } object LabelAndType { @@ -36,10 +33,8 @@ trait StructuredTypeStrings extends DestructureTypes { val NoGrouping = Grouping("", "", "", false) val ListGrouping = Grouping("(", ", ", ")", false) val ProductGrouping = Grouping("(", ", ", ")", true) - val ParamGrouping = Grouping("(", ", ", ")", true) val BlockGrouping = Grouping(" { ", "; ", "}", false) - private implicit def lowerName(n: Name): String = "" + n private def str(level: Int)(body: => String): String = " " * level + body private def block(level: Int, grouping: Grouping)(name: String, nodes: List[TypeNode]): String = { val l1 = str(level)(name + grouping.ldelim) @@ -49,7 +44,6 @@ trait StructuredTypeStrings extends DestructureTypes { l1 +: l2 :+ l3 mkString "\n" } private def maybeBlock(level: Int, grouping: Grouping)(name: String, nodes: List[TypeNode]): String = { - import grouping._ val threshold = 70 val try1 = str(level)(name + grouping.join(nodes map (_.show(0, grouping.labels)): _*)) @@ -57,7 +51,7 @@ trait StructuredTypeStrings extends DestructureTypes { else block(level, grouping)(name, nodes) } private def shortClass(x: Any) = { - if (opt.debug) { + if (settings.debug.value) { val name = (x.getClass.getName split '.').last val isAnon = name.reverse takeWhile (_ != '$') forall (_.isDigit) val str = if (isAnon) name else (name split '$').last @@ -194,7 +188,6 @@ trait TypeStrings { else enclClass.getName + "." + (name stripPrefix enclPre) ) } - def scalaName(ct: ClassTag[_]): String = scalaName(ct.runtimeClass) def anyClass(x: Any): JClass = if (x == null) null else x.getClass private def brackets(tps: String*): String = @@ -212,10 +205,8 @@ trait TypeStrings { } private def tparamString[T: ru.TypeTag] : String = { + import ru._ def typeArguments: List[ru.Type] = ru.typeOf[T] match { case ru.TypeRef(_, _, args) => args; case _ => Nil } - // [Eugene to Paul] need to use not the `rootMirror`, but a mirror with the REPL's classloader - // how do I get to it? acquiring context classloader seems unreliable because of multithreading - def typeVariables: List[java.lang.Class[_]] = typeArguments map (targ => ru.rootMirror.runtimeClass(targ)) brackets(typeArguments map (jc => tvarString(List(jc))): _*) } @@ -227,7 +218,6 @@ trait TypeStrings { * practice to rely on toString for correctness) generated the VALID string * representation of the type. */ - def fromTypedValue[T: ru.TypeTag : ClassTag](x: T): String = fromTag[T] def fromValue(value: Any): String = if (value == null) "Null" else fromClazz(anyClass(value)) def fromClazz(clazz: JClass): String = scalaName(clazz) + tparamString(clazz) def fromTag[T: ru.TypeTag : ClassTag] : String = scalaName(classTag[T].runtimeClass) + tparamString[T] @@ -247,13 +237,6 @@ trait TypeStrings { case (res, (k, v)) => res.replaceAll(k, v) } } - - val typeTransforms = List( - "java.lang." -> "", - "scala.collection.immutable." -> "immutable.", - "scala.collection.mutable." -> "mutable.", - "scala.collection.generic." -> "generic." - ) } object TypeStrings extends TypeStrings { } diff --git a/src/compiler/scala/tools/nsc/interpreter/package.scala b/src/compiler/scala/tools/nsc/interpreter/package.scala index e3440c9f8b..52a085080b 100644 --- a/src/compiler/scala/tools/nsc/interpreter/package.scala +++ b/src/compiler/scala/tools/nsc/interpreter/package.scala @@ -6,6 +6,10 @@ package scala.tools.nsc import scala.language.implicitConversions +import scala.reflect.{ classTag, ClassTag } +import scala.reflect.runtime.{ universe => ru } +import scala.reflect.{ClassTag, classTag} +import scala.reflect.api.{Mirror, TypeCreator, Universe => ApiUniverse} /** The main REPL related classes and values are as follows. * In addition to standard compiler classes Global and Settings, there are: @@ -44,6 +48,110 @@ package object interpreter extends ReplConfig with ReplStrings { private[nsc] implicit def enrichClass[T](clazz: Class[T]) = new RichClass[T](clazz) private[nsc] implicit def enrichAnyRefWithTap[T](x: T) = new TapMaker(x) - private[nsc] def tracing[T](msg: String)(x: T): T = x.tapTrace(msg) private[nsc] def debugging[T](msg: String)(x: T) = x.tapDebug(msg) + + private val ourClassloader = getClass.getClassLoader + + def staticTypeTag[T: ClassTag]: ru.TypeTag[T] = ru.TypeTag[T]( + ru.runtimeMirror(ourClassloader), + new TypeCreator { + def apply[U <: ApiUniverse with Singleton](m: Mirror[U]): U # Type = + m.staticClass(classTag[T].runtimeClass.getName).toTypeConstructor.asInstanceOf[U # Type] + }) + + /** This class serves to trick the compiler into treating a var + * (intp, in ILoop) as a stable identifier. + */ + implicit class IMainOps(val intp: IMain) { + import intp._ + import global.{ reporter => _, _ } + import definitions._ + + protected def echo(msg: String) = { + Console.out println msg + Console.out.flush() + } + + def implicitsCommand(line: String): String = { + def p(x: Any) = intp.reporter.printMessage("" + x) + + // If an argument is given, only show a source with that + // in its name somewhere. + val args = line split "\\s+" + val filtered = intp.implicitSymbolsBySource filter { + case (source, syms) => + (args contains "-v") || { + if (line == "") (source.fullName.toString != "scala.Predef") + else (args exists (source.name.toString contains _)) + } + } + + if (filtered.isEmpty) + return "No implicits have been imported other than those in Predef." + + filtered foreach { + case (source, syms) => + p("/* " + syms.size + " implicit members imported from " + source.fullName + " */") + + // This groups the members by where the symbol is defined + val byOwner = syms groupBy (_.owner) + val sortedOwners = byOwner.toList sortBy { case (owner, _) => exitingTyper(source.info.baseClasses indexOf owner) } + + sortedOwners foreach { + case (owner, members) => + // Within each owner, we cluster results based on the final result type + // if there are more than a couple, and sort each cluster based on name. + // This is really just trying to make the 100 or so implicits imported + // by default into something readable. + val memberGroups: List[List[Symbol]] = { + val groups = members groupBy (_.tpe.finalResultType) toList + val (big, small) = groups partition (_._2.size > 3) + val xss = ( + (big sortBy (_._1.toString) map (_._2)) :+ + (small flatMap (_._2)) + ) + + xss map (xs => xs sortBy (_.name.toString)) + } + + val ownerMessage = if (owner == source) " defined in " else " inherited from " + p(" /* " + members.size + ownerMessage + owner.fullName + " */") + + memberGroups foreach { group => + group foreach (s => p(" " + intp.symbolDefString(s))) + p("") + } + } + p("") + } + "" + } + + /** TODO - + * -n normalize + * -l label with case class parameter names + * -c complete - leave nothing out + */ + def typeCommandInternal(expr: String, verbose: Boolean): Unit = + symbolOfLine(expr) andAlso (echoTypeSignature(_, verbose)) + + def printAfterTyper(msg: => String) = + reporter printUntruncatedMessage exitingTyper(msg) + + private def replInfo(sym: Symbol) = + if (sym.isAccessor) dropNullaryMethod(sym.info) else sym.info + + def echoTypeStructure(sym: Symbol) = + printAfterTyper("" + deconstruct.show(replInfo(sym))) + + def echoTypeSignature(sym: Symbol, verbose: Boolean) = { + if (verbose) echo("// Type signature") + printAfterTyper("" + replInfo(sym)) + + if (verbose) { + echo("\n// Internal Type structure") + echoTypeStructure(sym) + } + } + } } diff --git a/src/compiler/scala/tools/nsc/interpreter/session/History.scala b/src/compiler/scala/tools/nsc/interpreter/session/History.scala index daa05b86db..794d41adc7 100644 --- a/src/compiler/scala/tools/nsc/interpreter/session/History.scala +++ b/src/compiler/scala/tools/nsc/interpreter/session/History.scala @@ -14,15 +14,9 @@ trait History { def asStrings: List[String] def index: Int def size: Int - def grep(s: String): List[String] } object NoHistory extends History { def asStrings = Nil - def grep(s: String) = Nil def index = 0 def size = 0 } - -object History { - def empty: History = NoHistory -} diff --git a/src/compiler/scala/tools/nsc/interpreter/session/SimpleHistory.scala b/src/compiler/scala/tools/nsc/interpreter/session/SimpleHistory.scala index 9f4e2b9df3..89998e438a 100644 --- a/src/compiler/scala/tools/nsc/interpreter/session/SimpleHistory.scala +++ b/src/compiler/scala/tools/nsc/interpreter/session/SimpleHistory.scala @@ -54,9 +54,5 @@ class SimpleHistory extends JLineHistory { def moveTo(idx: Int) = (idx > 0) && (idx <= lastIndex) && setTo(idx) def moveToEnd(): Unit = setTo(size) - // scala legacy interface - def asList: List[JEntry] = toEntries().toList - def asJavaList = entries() - def asStrings = buf.toList - def grep(s: String) = buf.toList filter (_ contains s) + def asStrings = buf.toList } diff --git a/src/compiler/scala/tools/nsc/io/Fileish.scala b/src/compiler/scala/tools/nsc/io/Fileish.scala deleted file mode 100644 index 7b4e385dd8..0000000000 --- a/src/compiler/scala/tools/nsc/io/Fileish.scala +++ /dev/null @@ -1,33 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package io - -import java.io.{ InputStream } -import java.util.jar.JarEntry - -/** A common interface for File-based things and Stream-based things. - * (In particular, io.File and JarEntry.) - */ -class Fileish(val path: Path, val input: () => InputStream) extends Streamable.Chars { - def inputStream() = input() - - def parent = path.parent - def name = path.name - def isSourceFile = path.hasExtension("java", "scala") - - private lazy val pkgLines = lines() collect { case x if x startsWith "package " => x stripPrefix "package" trim } - lazy val pkgFromPath = parent.path.replaceAll("""[/\\]""", ".") - lazy val pkgFromSource = pkgLines map (_ stripSuffix ";") mkString "." - - override def toString = path.path -} - -object Fileish { - def apply(f: File): Fileish = new Fileish(f, () => f.inputStream()) - def apply(f: JarEntry, in: () => InputStream): Fileish = new Fileish(Path(f.getName), in) - def apply(path: String, in: () => InputStream): Fileish = new Fileish(Path(path), in) -} diff --git a/src/compiler/scala/tools/nsc/io/Jar.scala b/src/compiler/scala/tools/nsc/io/Jar.scala index e919621338..49a1ff114f 100644 --- a/src/compiler/scala/tools/nsc/io/Jar.scala +++ b/src/compiler/scala/tools/nsc/io/Jar.scala @@ -10,7 +10,6 @@ import java.io.{ InputStream, OutputStream, IOException, FileNotFoundException, import java.util.jar._ import scala.collection.JavaConverters._ import Attributes.Name -import util.ClassPath import scala.language.implicitConversions // Attributes.Name instances: @@ -37,9 +36,6 @@ class Jar(file: File) extends Iterable[JarEntry] { def this(jfile: JFile) = this(File(jfile)) def this(path: String) = this(File(path)) - protected def errorFn(msg: String): Unit = Console println msg - - lazy val jarFile = new JarFile(file.jfile) lazy val manifest = withJarInput(s => Option(s.getManifest)) def mainClass = manifest map (f => f(Name.MAIN_CLASS)) @@ -64,12 +60,6 @@ class Jar(file: File) extends Iterable[JarEntry] { Iterator continually in.getNextJarEntry() takeWhile (_ != null) foreach f } override def iterator: Iterator[JarEntry] = this.toList.iterator - def fileishIterator: Iterator[Fileish] = jarFile.entries.asScala map (x => Fileish(x, () => getEntryStream(x))) - - private def getEntryStream(entry: JarEntry) = jarFile getInputStream entry match { - case null => errorFn("No such entry: " + entry) ; null - case x => x - } override def toString = "" + file } @@ -131,7 +121,6 @@ object Jar { m } def apply(manifest: JManifest): WManifest = new WManifest(manifest) - implicit def unenrichManifest(x: WManifest): JManifest = x.underlying } class WManifest(manifest: JManifest) { for ((k, v) <- initialMainAttrs) @@ -148,12 +137,7 @@ object Jar { } def apply(name: Attributes.Name): String = attrs(name) - def apply(name: String): String = apply(new Attributes.Name(name)) def update(key: Attributes.Name, value: String) = attrs.put(key, value) - def update(key: String, value: String) = attrs.put(new Attributes.Name(key), value) - - def mainClass: String = apply(Name.MAIN_CLASS) - def mainClass_=(value: String) = update(Name.MAIN_CLASS, value) } // See http://download.java.net/jdk7/docs/api/java/nio/file/Path.html diff --git a/src/compiler/scala/tools/nsc/io/Lexer.scala b/src/compiler/scala/tools/nsc/io/Lexer.scala index 5ffb5b4d4f..e843f8d5ce 100644 --- a/src/compiler/scala/tools/nsc/io/Lexer.scala +++ b/src/compiler/scala/tools/nsc/io/Lexer.scala @@ -1,8 +1,6 @@ package scala.tools.nsc.io -import java.io.{Reader, Writer, StringReader, StringWriter} -import scala.collection.mutable.{Buffer, ArrayBuffer} -import scala.math.BigInt +import java.io.Reader /** Companion object of class `Lexer` which defines tokens and some utility concepts * used for tokens and lexers diff --git a/src/compiler/scala/tools/nsc/io/MsilFile.scala b/src/compiler/scala/tools/nsc/io/MsilFile.scala index 2f0a71fc60..bda13a5ed0 100644 --- a/src/compiler/scala/tools/nsc/io/MsilFile.scala +++ b/src/compiler/scala/tools/nsc/io/MsilFile.scala @@ -6,13 +6,10 @@ package scala.tools.nsc package io -import ch.epfl.lamp.compiler.msil.{ Type => MsilType, _ } +import ch.epfl.lamp.compiler.msil.{ Type => MsilType } /** This class wraps an MsilType. It exists only so * ClassPath can treat all of JVM/MSIL/bin/src files * uniformly, as AbstractFiles. */ -class MsilFile(val msilType: MsilType) extends VirtualFile(msilType.FullName, msilType.Namespace) { -} - -object NoMsilFile extends MsilFile(null) { } +class MsilFile(val msilType: MsilType) extends VirtualFile(msilType.FullName, msilType.Namespace) { } diff --git a/src/compiler/scala/tools/nsc/io/Pickler.scala b/src/compiler/scala/tools/nsc/io/Pickler.scala index b03a921e87..5d32c10143 100644 --- a/src/compiler/scala/tools/nsc/io/Pickler.scala +++ b/src/compiler/scala/tools/nsc/io/Pickler.scala @@ -1,6 +1,5 @@ package scala.tools.nsc.io -import scala.annotation.unchecked import Lexer._ import java.io.Writer import scala.language.implicitConversions @@ -71,14 +70,6 @@ abstract class Pickler[T] { */ def wrapped [U] (in: T => U)(out: U => T): Pickler[U] = wrappedPickler(this)(in)(out) - /** A pickler obtained from the current pickler by also admitting `null` as - * a handled value, represented as the token `null`. - * - * @param fromNull an implicit evidence parameter ensuring that the type of values - * handled by this pickler contains `null`. - */ - def orNull(implicit fromNull: Null <:< T): Pickler[T] = nullablePickler(this) - /** A conditional pickler obtained from the current pickler. * @param cond the condition to test to find out whether pickler can handle * some Scala value. @@ -93,9 +84,6 @@ abstract class Pickler[T] { } object Pickler { - - var picklerDebugMode = false - /** A base class representing unpickler result. It has two subclasses: * `UnpickleSucess` for successful unpicklings and `UnpickleFailure` for failures, * where a value of the given type `T` could not be unpickled from input. @@ -175,17 +163,6 @@ object Pickler { def ~ [T](y: T): S ~ T = new ~ (x, y) } - /** A converter from binary functions to functions over `~`-pairs - */ - implicit def fromTilde[T1, T2, R](f: (T1, T2) => R): T1 ~ T2 => R = { case x1 ~ x2 => f(x1, x2) } - - /** An converter from unctions returning Options over pair to functions returning `~`-pairs - * The converted function will raise a `MatchError` where the original function returned - * a `None`. This converter is useful for turning `unapply` methods of case classes - * into wrapper methods that can be passed as second argument to `wrap`. - */ - implicit def toTilde[T1, T2, S](f: S => Option[(T1, T2)]): S => T1 ~ T2 = { x => (f(x): @unchecked) match { case Some((x1, x2)) => x1 ~ x2 } } - /** Same as `p.labelled(label)`. */ def labelledPickler[T](label: String, p: Pickler[T]): Pickler[T] = new Pickler[T] { @@ -249,16 +226,6 @@ object Pickler { def unpickle(rd: Lexer) = p.unpickle(rd) orElse qq.unpickle(rd) } - /** Same as `p.orNull` - */ - def nullablePickler[T](p: Pickler[T])(implicit fromNull: Null <:< T): Pickler[T] = new Pickler[T] { - def pickle(wr: Writer, x: T) = - if (x == null) wr.write("null") else p.pickle(wr, x) - def unpickle(rd: Lexer): Unpickled[T] = - if (rd.token == NullLit) nextSuccess(rd, fromNull(null)) - else p.unpickle(rd) - } - /** A conditional pickler for singleton objects. It represents these * with the object's underlying class as a label. * Example: Object scala.None would be represented as `scala.None$()`. @@ -330,22 +297,9 @@ object Pickler { implicit val longPickler: Pickler[Long] = tokenPickler("integer literal") { case IntLit(s) => s.toLong } - /** A pickler for values of type `Double`, represented as floating point literals */ - implicit val doublePickler: Pickler[Double] = - tokenPickler("floating point literal") { case FloatLit(s) => s.toDouble } - - /** A pickler for values of type `Byte`, represented as integer literals */ - implicit val bytePickler: Pickler[Byte] = longPickler.wrapped { _.toByte } { _.toLong } - - /** A pickler for values of type `Short`, represented as integer literals */ - implicit val shortPickler: Pickler[Short] = longPickler.wrapped { _.toShort } { _.toLong } - /** A pickler for values of type `Int`, represented as integer literals */ implicit val intPickler: Pickler[Int] = longPickler.wrapped { _.toInt } { _.toLong } - /** A pickler for values of type `Float`, represented as floating point literals */ - implicit val floatPickler: Pickler[Float] = doublePickler.wrapped { _.toFloat } { _.toLong } - /** A conditional pickler for the boolean value `true` */ private val truePickler = tokenPickler("boolean literal") { case TrueLit => true } cond { _ == true } @@ -373,52 +327,15 @@ object Pickler { } } - /** A pickler for values of type `Char`, represented as string literals of length 1 */ - implicit val charPickler: Pickler[Char] = - stringPickler - .wrapped { s => require(s.length == 1, "single character string literal expected, but "+quoted(s)+" found"); s(0) } { _.toString } - - /** A pickler for pairs, represented as `~`-pairs */ - implicit def tuple2Pickler[T1: Pickler, T2: Pickler]: Pickler[(T1, T2)] = - (pkl[T1] ~ pkl[T2]) - .wrapped { case x1 ~ x2 => (x1, x2) } { case (x1, x2) => x1 ~ x2 } - .labelled ("tuple2") - /** A pickler for 3-tuples, represented as `~`-tuples */ implicit def tuple3Pickler[T1, T2, T3](implicit p1: Pickler[T1], p2: Pickler[T2], p3: Pickler[T3]): Pickler[(T1, T2, T3)] = (p1 ~ p2 ~ p3) .wrapped { case x1 ~ x2 ~ x3 => (x1, x2, x3) } { case (x1, x2, x3) => x1 ~ x2 ~ x3 } .labelled ("tuple3") - /** A pickler for 4-tuples, represented as `~`-tuples */ - implicit def tuple4Pickler[T1, T2, T3, T4](implicit p1: Pickler[T1], p2: Pickler[T2], p3: Pickler[T3], p4: Pickler[T4]): Pickler[(T1, T2, T3, T4)] = - (p1 ~ p2 ~ p3 ~ p4) - .wrapped { case x1 ~ x2 ~ x3 ~ x4 => (x1, x2, x3, x4) } { case (x1, x2, x3, x4) => x1 ~ x2 ~ x3 ~ x4 } - .labelled ("tuple4") - - /** A conditional pickler for the `scala.None` object */ - implicit val nonePickler = singletonPickler(None) - - /** A conditional pickler for instances of class `scala.Some` */ - implicit def somePickler[T: Pickler]: CondPickler[Some[T]] = - pkl[T] - .wrapped { Some(_) } { _.get } - .asClass (classOf[Some[T]]) - - /** A pickler for optional values */ - implicit def optionPickler[T: Pickler]: Pickler[Option[T]] = nonePickler | somePickler[T] - /** A pickler for list values */ implicit def listPickler[T: Pickler]: Pickler[List[T]] = iterPickler[T] .wrapped { _.toList } { _.iterator } .labelled ("scala.List") - - /** A pickler for vector values */ - implicit def vectorPickler[T: Pickler]: Pickler[Vector[T]] = - iterPickler[T] .wrapped { Vector() ++ _ } { _.iterator } .labelled ("scala.Vector") - - /** A pickler for array values */ - implicit def array[T : ClassTag : Pickler]: Pickler[Array[T]] = - iterPickler[T] .wrapped { _.toArray} { _.iterator } .labelled ("scala.Array") } /** A subclass of Pickler can indicate whether a particular value can be pickled by instances diff --git a/src/compiler/scala/tools/nsc/io/Replayer.scala b/src/compiler/scala/tools/nsc/io/Replayer.scala index 5cb61b6cb1..e3dc8939a3 100644 --- a/src/compiler/scala/tools/nsc/io/Replayer.scala +++ b/src/compiler/scala/tools/nsc/io/Replayer.scala @@ -3,7 +3,7 @@ package scala.tools.nsc.io import java.io.{Reader, Writer} import Pickler._ -import Lexer.{Token, EOF} +import Lexer.EOF abstract class LogReplay { def logreplay(event: String, x: => Boolean): Boolean diff --git a/src/compiler/scala/tools/nsc/io/Socket.scala b/src/compiler/scala/tools/nsc/io/Socket.scala index e766c1b2fd..4925c50d85 100644 --- a/src/compiler/scala/tools/nsc/io/Socket.scala +++ b/src/compiler/scala/tools/nsc/io/Socket.scala @@ -28,13 +28,10 @@ object Socket { private val optHandler = handlerFn[Option[T]](_ => None) private val eitherHandler = handlerFn[Either[Throwable, T]](x => Left(x)) - def getOrElse[T1 >: T](alt: T1): T1 = opt getOrElse alt def either: Either[Throwable, T] = try Right(f()) catch eitherHandler def opt: Option[T] = try Some(f()) catch optHandler } - def newIPv4Server(port: Int = 0) = new Box(() => preferringIPv4(new ServerSocket(0))) - def newServer(port: Int = 0) = new Box(() => new ServerSocket(0)) def localhost(port: Int) = apply(InetAddress.getLocalHost(), port) def apply(host: InetAddress, port: Int) = new Box(() => new Socket(new JSocket(host, port))) def apply(host: String, port: Int) = new Box(() => new Socket(new JSocket(host, port))) @@ -62,4 +59,4 @@ class Socket(jsocket: JSocket) extends Streamable.Bytes with Closeable { out.close() } } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/io/SourceReader.scala b/src/compiler/scala/tools/nsc/io/SourceReader.scala index 569270f530..ece78db2cf 100644 --- a/src/compiler/scala/tools/nsc/io/SourceReader.scala +++ b/src/compiler/scala/tools/nsc/io/SourceReader.scala @@ -9,7 +9,7 @@ package io import java.io.{ FileInputStream, InputStream, IOException } import java.nio.{ByteBuffer, CharBuffer} -import java.nio.channels.{FileChannel, ReadableByteChannel, Channels} +import java.nio.channels.{ ReadableByteChannel, Channels } import java.nio.charset.{CharsetDecoder, CoderResult} import scala.tools.nsc.reporters._ @@ -33,9 +33,6 @@ class SourceReader(decoder: CharsetDecoder, reporter: Reporter) { "Please try specifying another one using the -encoding option") } - /** Reads the file with the specified name. */ - def read(filename: String): Array[Char]= read(new JFile(filename)) - /** Reads the specified file. */ def read(file: JFile): Array[Char] = { val c = new FileInputStream(file).getChannel diff --git a/src/compiler/scala/tools/nsc/io/package.scala b/src/compiler/scala/tools/nsc/io/package.scala index 711696bb6e..0b2db115fb 100644 --- a/src/compiler/scala/tools/nsc/io/package.scala +++ b/src/compiler/scala/tools/nsc/io/package.scala @@ -7,7 +7,6 @@ package scala.tools.nsc import java.util.concurrent.{ Future, Callable } import java.util.{ Timer, TimerTask } -import java.util.jar.{ Attributes } import scala.language.implicitConversions package object io { @@ -21,14 +20,10 @@ package object io { type Path = scala.reflect.io.Path val Path = scala.reflect.io.Path type PlainFile = scala.reflect.io.PlainFile - val PlainFile = scala.reflect.io.PlainFile val Streamable = scala.reflect.io.Streamable type VirtualDirectory = scala.reflect.io.VirtualDirectory type VirtualFile = scala.reflect.io.VirtualFile - val ZipArchive = scala.reflect.io.ZipArchive type ZipArchive = scala.reflect.io.ZipArchive - - implicit def postfixOps = scala.language.postfixOps // make all postfix ops in this package compile without warning type JManifest = java.util.jar.Manifest type JFile = java.io.File @@ -39,23 +34,11 @@ package object io { def runnable(body: => Unit): Runnable = new Runnable { override def run() = body } def callable[T](body: => T): Callable[T] = new Callable[T] { override def call() = body } def spawn[T](body: => T): Future[T] = daemonThreadPool submit callable(body) - def submit(runnable: Runnable) = daemonThreadPool submit runnable - // Create, start, and return a daemon thread - def daemonize(body: => Unit): Thread = newThread(_ setDaemon true)(body) def newThread(f: Thread => Unit)(body: => Unit): Thread = { val thread = new Thread(runnable(body)) f(thread) thread.start thread } - - // Set a timer to execute the given code. - def timer(seconds: Int)(body: => Unit): Timer = { - val alarm = new Timer(true) // daemon - val tt = new TimerTask { def run() = body } - - alarm.schedule(tt, seconds * 1000) - alarm - } } diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 43a8402fc7..73cbeaa6c4 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -35,7 +35,6 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { abstract class JavaParser extends ParserCommon { val in: JavaScanner - protected def posToReport: Int = in.currentPos def freshName(prefix : String): Name protected implicit def i2p(offset : Int) : Position private implicit def p2i(pos : Position): Int = if (pos.isDefined) pos.point else -1 @@ -94,11 +93,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { if (skipIt) skip() } - def warning(msg: String) : Unit = warning(in.currentPos, msg) - def errorTypeTree = TypeTree().setType(ErrorType) setPos in.currentPos - def errorTermTree = Literal(Constant(null)) setPos in.currentPos - def errorPatternTree = blankExpr setPos in.currentPos // --------- tree building ----------------------------- @@ -178,11 +173,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { def accept(token: Int): Int = { val pos = in.currentPos if (in.token != token) { - val posToReport = - //if (in.currentPos.line(unit.source).get(0) > in.lastPos.line(unit.source).get(0)) - // in.lastPos - //else - in.currentPos + val posToReport = in.currentPos val msg = JavaScannerConfiguration.token2string(token) + " expected but " + JavaScannerConfiguration.token2string(in.token) + " found." @@ -348,46 +339,10 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { /** Annotation ::= TypeName [`(` AnnotationArgument {`,` AnnotationArgument} `)`] */ def annotation() { - val pos = in.currentPos - var t = qualId() + qualId() if (in.token == LPAREN) { skipAhead(); accept(RPAREN) } else if (in.token == LBRACE) { skipAhead(); accept(RBRACE) } } -/* - def annotationArg() = { - val pos = in.token - if (in.token == IDENTIFIER && in.lookaheadToken == ASSIGN) { - val name = ident() - accept(ASSIGN) - atPos(pos) { - ValDef(Modifiers(Flags.JAVA), name, TypeTree(), elementValue()) - } - } else { - elementValue() - } - } - - def elementValue(): Tree = - if (in.token == AT) annotation() - else if (in.token == LBRACE) elementValueArrayInitializer() - else expression1() - - def elementValueArrayInitializer() = { - accept(LBRACE) - val buf = new ListBuffer[Tree] - def loop() = - if (in.token != RBRACE) { - buf += elementValue() - if (in.token == COMMA) { - in.nextToken - loop() - } - } - loop() - accept(RBRACE) - buf.toList - } - */ def modifiers(inInterface: Boolean): Modifiers = { var flags: Long = Flags.JAVA diff --git a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala index e230585a8b..84eee36f18 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala @@ -57,23 +57,14 @@ trait JavaScanners extends ast.parser.ScannersCommon { /** ... */ abstract class AbstractJavaScanner extends AbstractJavaTokenData { - implicit def p2g(pos: Position): ScanPosition implicit def g2p(pos: ScanPosition): Position - /** the last error position - */ - var errpos: ScanPosition - var lastPos: ScanPosition - def skipToken: ScanPosition def nextToken(): Unit def next: AbstractJavaTokenData def intVal(negated: Boolean): Long def floatVal(negated: Boolean): Double def intVal: Long = intVal(false) def floatVal: Double = floatVal(false) - //def token2string(token : Int) : String = configuration.token2string(token) - /** return recent scala doc, if any */ - def flushDoc: DocComment def currentPos: Position } @@ -227,17 +218,9 @@ trait JavaScanners extends ast.parser.ScannersCommon { abstract class JavaScanner extends AbstractJavaScanner with JavaTokenData with Cloneable with ScannerCommon { override def intVal = super.intVal// todo: needed? override def floatVal = super.floatVal - override var errpos: Int = NoPos def currentPos: Position = g2p(pos - 1) - var in: JavaCharArrayReader = _ - def dup: JavaScanner = { - val dup = clone().asInstanceOf[JavaScanner] - dup.in = in.dup - dup - } - /** character buffer for literals */ val cbuf = new StringBuilder() @@ -256,12 +239,6 @@ trait JavaScanners extends ast.parser.ScannersCommon { */ var docBuffer: StringBuilder = null - def flushDoc: DocComment = { - val ret = if (docBuffer != null) DocComment(docBuffer.toString, NoPosition) else null - docBuffer = null - ret - } - /** add the given character to the documentation buffer */ protected def putDocChar(c: Char) { @@ -277,13 +254,6 @@ trait JavaScanners extends ast.parser.ScannersCommon { // Get next token ------------------------------------------------------------ - /** read next token and return last position - */ - def skipToken: Int = { - val p = pos; nextToken - p - 1 - } - def nextToken() { if (next.token == EMPTY) { fetchToken() @@ -308,7 +278,6 @@ trait JavaScanners extends ast.parser.ScannersCommon { private def fetchToken() { if (token == EOF) return lastPos = in.cpos - 1 - //var index = bp while (true) { in.ch match { case ' ' | '\t' | CR | LF | FF => @@ -868,7 +837,6 @@ trait JavaScanners extends ast.parser.ScannersCommon { def syntaxError(pos: Int, msg: String) { error(pos, msg) token = ERROR - errpos = pos } /** generate an error at the current token position @@ -879,7 +847,6 @@ trait JavaScanners extends ast.parser.ScannersCommon { def incompleteInputError(msg: String) { incompleteInputError(pos, msg) token = EOF - errpos = pos } override def toString() = token match { @@ -913,16 +880,12 @@ trait JavaScanners extends ast.parser.ScannersCommon { } } - /** ... - */ class JavaUnitScanner(unit: CompilationUnit) extends JavaScanner { in = new JavaCharArrayReader(unit.source.content, !settings.nouescape.value, syntaxError) init - def warning(pos: Int, msg: String) = unit.warning(pos, msg) def error (pos: Int, msg: String) = unit. error(pos, msg) def incompleteInputError(pos: Int, msg: String) = unit.incompleteInputError(pos, msg) def deprecationWarning(pos: Int, msg: String) = unit.deprecationWarning(pos, msg) - implicit def p2g(pos: Position): Int = if (pos.isDefined) pos.point else -1 implicit def g2p(pos: Int): Position = new OffsetPosition(unit.source, pos) } } diff --git a/src/compiler/scala/tools/nsc/javac/JavaTokens.scala b/src/compiler/scala/tools/nsc/javac/JavaTokens.scala index a562de291d..953a3c6d82 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaTokens.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaTokens.scala @@ -68,9 +68,6 @@ object JavaTokens extends ast.parser.Tokens { final val VOLATILE = 68 final val WHILE = 69 - def isKeyword(code : Int) = - code >= ABSTRACT && code <= WHILE - /** special symbols */ final val COMMA = 70 final val SEMI = 71 @@ -115,9 +112,6 @@ object JavaTokens extends ast.parser.Tokens { final val GTGTEQ = 113 final val GTGTGTEQ = 114 - def isSymbol(code : Int) = - code >= COMMA && code <= GTGTGTEQ - /** parenthesis */ final val LPAREN = 115 final val RPAREN = 116 diff --git a/src/compiler/scala/tools/nsc/matching/MatchSupport.scala b/src/compiler/scala/tools/nsc/matching/MatchSupport.scala index 5ca9fd5062..3c26997cfe 100644 --- a/src/compiler/scala/tools/nsc/matching/MatchSupport.scala +++ b/src/compiler/scala/tools/nsc/matching/MatchSupport.scala @@ -6,9 +6,6 @@ package scala.tools.nsc package matching -import transform.ExplicitOuter -import ast.{ Printers, Trees } -import java.io.{ StringWriter, PrintWriter } import scala.annotation.elidable import scala.language.postfixOps @@ -25,9 +22,6 @@ trait MatchSupport extends ast.TreeDSL { self: ParallelMatching => def impossible: Nothing = abort("this never happens") - def treeCollect[T](tree: Tree, pf: PartialFunction[Tree, T]): List[T] = - tree filter (pf isDefinedAt _) map (x => pf(x)) - object Types { import definitions._ @@ -39,24 +33,12 @@ trait MatchSupport extends ast.TreeDSL { self: ParallelMatching => // These tests for final classes can inspect the typeSymbol private def is(s: Symbol) = tpe.typeSymbol eq s - def isByte = is(ByteClass) - def isShort = is(ShortClass) def isInt = is(IntClass) - def isChar = is(CharClass) - def isBoolean = is(BooleanClass) def isNothing = is(NothingClass) - def isArray = is(ArrayClass) } } object Debug { - def typeToString(t: Type): String = t match { - case NoType => "x" - case x => x.toString - } - def symbolToString(s: Symbol): String = s match { - case x => x.toString - } def treeToString(t: Tree): String = treeInfo.unbind(t) match { case EmptyTree => "?" case WILD() => "_" @@ -69,10 +51,6 @@ trait MatchSupport extends ast.TreeDSL { self: ParallelMatching => // Formatting for some error messages private val NPAD = 15 def pad(s: String): String = "%%%ds" format (NPAD-1) format s - def pad(s: Any): String = pad(s match { - case x: Tree => treeToString(x) - case x => x.toString - }) // pretty print for debugging def pp(x: Any): String = pp(x, false) @@ -120,7 +98,6 @@ trait MatchSupport extends ast.TreeDSL { self: ParallelMatching => else x } - def indent(s: Any) = s.toString() split "\n" map (" " + _) mkString "\n" def indentAll(s: Seq[Any]) = s map (" " + _.toString() + "\n") mkString } diff --git a/src/compiler/scala/tools/nsc/matching/Matrix.scala b/src/compiler/scala/tools/nsc/matching/Matrix.scala index daefe4c545..ba966acf34 100644 --- a/src/compiler/scala/tools/nsc/matching/Matrix.scala +++ b/src/compiler/scala/tools/nsc/matching/Matrix.scala @@ -140,7 +140,6 @@ trait Matrix extends MatrixAdditions { cases: List[CaseDef], default: Tree ) { - def tvars = roots map (_.lhs) def valDefs = roots map (_.valDef) override def toString() = "MatrixInit(roots = %s, %d cases)".format(pp(roots), cases.size) } @@ -151,27 +150,12 @@ trait Matrix extends MatrixAdditions { object PatternVarGroup { def apply(xs: PatternVar*) = new PatternVarGroup(xs.toList) def apply(xs: List[PatternVar]) = new PatternVarGroup(xs) - - // XXX - transitional - def fromBindings(vlist: List[Binding], freeVars: List[Symbol] = Nil) = { - def vmap(v: Symbol): Option[Binding] = vlist find (_.pvar eq v) - val info = - if (freeVars.isEmpty) vlist - else (freeVars map vmap).flatten - - val xs = - for (Binding(lhs, rhs) <- info) yield - new PatternVar(lhs, Ident(rhs) setType lhs.tpe, !(rhs hasFlag NO_EXHAUSTIVE)) - - new PatternVarGroup(xs) - } } val emptyPatternVarGroup = PatternVarGroup() class PatternVarGroup(val pvs: List[PatternVar]) { def syms = pvs map (_.sym) def valDefs = pvs map (_.valDef) - def idents = pvs map (_.ident) def extractIndex(index: Int): (PatternVar, PatternVarGroup) = { val (t, ts) = self.extractIndex(pvs, index) @@ -180,16 +164,11 @@ trait Matrix extends MatrixAdditions { def isEmpty = pvs.isEmpty def size = pvs.size - def head = pvs.head - def ::(t: PatternVar) = PatternVarGroup(t :: pvs) def :::(ts: List[PatternVar]) = PatternVarGroup(ts ::: pvs) - def ++(other: PatternVarGroup) = PatternVarGroup(pvs ::: other.pvs) def apply(i: Int) = pvs(i) def zipWithIndex = pvs.zipWithIndex def indices = pvs.indices - def map[T](f: PatternVar => T) = pvs map f - def filter(p: PatternVar => Boolean) = PatternVarGroup(pvs filter p) override def toString() = pp(pvs) } @@ -237,17 +216,11 @@ trait Matrix extends MatrixAdditions { tracing("create")(new PatternVar(lhs, rhs, checked)) } - def createLazy(tpe: Type, f: Symbol => Tree, checked: Boolean) = { - val lhs = newVar(owner.pos, tpe, Flags.LAZY :: flags(checked)) - val rhs = f(lhs) - - tracing("createLazy")(new PatternVar(lhs, rhs, checked)) - } private def newVar( pos: Position, tpe: Type, - flags: List[Long] = Nil, + flags: List[Long], name: TermName = null): Symbol = { val n = if (name == null) cunit.freshTermName("temp") else name diff --git a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala index 7220253003..b1ca6e7b5a 100644 --- a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala +++ b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala @@ -7,7 +7,6 @@ package scala.tools.nsc package matching import transform.ExplicitOuter -import PartialFunction._ /** Traits which are mixed into MatchMatrix, but separated out as * (somewhat) independent components to keep them on the sidelines. @@ -17,7 +16,6 @@ trait MatrixAdditions extends ast.TreeDSL { import global.{ typer => _, _ } import symtab.Flags - import CODE._ import Debug._ import treeInfo._ import definitions.{ isPrimitiveValueClass } @@ -190,4 +188,4 @@ trait MatrixAdditions extends ast.TreeDSL { } } } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 9d01e73063..b5e25f3809 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -9,11 +9,8 @@ package matching import PartialFunction._ import scala.collection.{ mutable } -import scala.reflect.internal.util.Position import transform.ExplicitOuter -import symtab.Flags import mutable.ListBuffer -import scala.annotation.elidable import scala.language.postfixOps trait ParallelMatching extends ast.TreeDSL @@ -26,7 +23,7 @@ trait ParallelMatching extends ast.TreeDSL import global.{ typer => _, _ } import definitions.{ - AnyRefClass, IntClass, BooleanClass, SomeClass, OptionClass, + IntClass, BooleanClass, SomeClass, OptionClass, getProductArgs, productProj, Object_eq, Any_asInstanceOf } import CODE._ @@ -129,7 +126,7 @@ trait ParallelMatching extends ast.TreeDSL // for propagating "unchecked" to synthetic vars def isChecked = !(sym hasFlag NO_EXHAUSTIVE) - def flags: List[Long] = List(NO_EXHAUSTIVE) filter (sym hasFlag _) + // def flags: List[Long] = List(NO_EXHAUSTIVE) filter (sym hasFlag _) // this is probably where this actually belongs def createVar(tpe: Type, f: Symbol => Tree) = context.createVar(tpe, f, isChecked) @@ -173,7 +170,7 @@ trait ParallelMatching extends ast.TreeDSL case class PatternMatch(scrut: Scrutinee, ps: List[Pattern]) { def head = ps.head def tail = ps.tail - def size = ps.length + // def size = ps.length def headType = head.necessaryType private val dummyCount = if (head.isCaseClass) headType.typeSymbol.caseFieldAccessors.length else 0 @@ -579,7 +576,7 @@ trait ParallelMatching extends ast.TreeDSL (_ys.toList, _ns.toList) } - val moreSpecific = yeses map (_.moreSpecific) + // val moreSpecific = yeses map (_.moreSpecific) val subsumed = yeses map (x => (x.bx, x.subsumed)) val remaining = noes map (x => (x.bx, x.remaining)) diff --git a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala index 7b2fcf0e9b..c6fa6f6ba0 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala @@ -7,7 +7,6 @@ package scala.tools.nsc package matching import transform.ExplicitOuter -import PartialFunction._ import scala.language.postfixOps trait PatternBindings extends ast.TreeDSL @@ -17,7 +16,6 @@ trait PatternBindings extends ast.TreeDSL import global.{ typer => _, _ } import definitions.{ EqualsPatternClass } import CODE._ - import Debug._ /** EqualsPattern **/ def isEquals(tpe: Type) = tpe.typeSymbol == EqualsPatternClass @@ -61,10 +59,6 @@ trait PatternBindings extends ast.TreeDSL trait PatternBindingLogic { self: Pattern => - // This is for traversing the pattern tree - pattern types which might have - // bound variables beneath them return a list of said patterns for flatMapping. - def subpatternsForVars: List[Pattern] = Nil - // The outermost Bind(x1, Bind(x2, ...)) surrounding the tree. private var _boundTree: Tree = tree def boundTree = _boundTree @@ -108,8 +102,6 @@ trait PatternBindings extends ast.TreeDSL case b @ Bind(_, pat) => b.symbol :: strip(pat) case _ => Nil } - private def deepstrip(t: Tree): List[Symbol] = - treeCollect(t, { case x: Bind => x.symbol }) } case class Binding(pvar: Symbol, tvar: Symbol) { @@ -117,9 +109,6 @@ trait PatternBindings extends ast.TreeDSL } class Bindings(private val vlist: List[Binding]) { - // if (!vlist.isEmpty) - // traceCategory("Bindings", this.toString) - def get() = vlist def toMap = vlist map (x => (x.pvar, x.tvar)) toMap diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala index 99b72fa26e..df536da108 100644 --- a/src/compiler/scala/tools/nsc/matching/Patterns.scala +++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala @@ -6,7 +6,6 @@ package scala.tools.nsc package matching -import symtab.Flags import PartialFunction._ /** Patterns are wrappers for Trees with enhanced semantics. @@ -33,9 +32,6 @@ trait Patterns extends ast.TreeDSL { // An empty pattern def NoPattern = WildcardPattern() - // The constant null pattern - def NullPattern = LiteralPattern(NULL) - // The Nil pattern def NilPattern = Pattern(gen.mkNil) @@ -61,7 +57,6 @@ trait Patterns extends ast.TreeDSL { override def covers(sym: Symbol) = newMatchesPattern(sym, tpt.tpe) override def sufficientType = tpt.tpe - override def subpatternsForVars: List[Pattern] = List(Pattern(expr)) override def simplify(pv: PatternVar) = Pattern(expr) match { case ExtractorPattern(ua) if pv.sym.tpe <:< tpt.tpe => this rebindTo expr case _ => this @@ -141,10 +136,6 @@ trait Patterns extends ast.TreeDSL { require(fn.isType && this.isCaseClass, "tree: " + tree + " fn: " + fn) def name = tpe.typeSymbol.name def cleanName = tpe.typeSymbol.decodedName - def hasPrefix = tpe.prefix.prefixString != "" - def prefixedName = - if (hasPrefix) "%s.%s".format(tpe.prefix.prefixString, cleanName) - else cleanName private def isColonColon = cleanName == "::" @@ -189,13 +180,6 @@ trait Patterns extends ast.TreeDSL { private lazy val packedType = global.typer.computeType(tpt, tpt.tpe) private lazy val consRef = appliedType(ConsClass, packedType) private lazy val listRef = appliedType(ListClass, packedType) - private lazy val seqRef = appliedType(SeqClass, packedType) - - private def thisSeqRef = { - val tc = (tree.tpe baseType SeqClass).typeConstructor - if (tc.typeParams.size == 1) appliedType(tc, List(packedType)) - else seqRef - } // Fold a list into a well-typed x :: y :: etc :: tree. private def listFolder(hd: Tree, tl: Tree): Tree = unbind(hd) match { @@ -230,15 +214,13 @@ trait Patterns extends ast.TreeDSL { // 8.1.8 (b) (literal ArrayValues) case class SequencePattern(tree: ArrayValue) extends Pattern with SequenceLikePattern { - lazy val ArrayValue(elemtpt, elems) = tree + lazy val ArrayValue(_, elems) = tree - override def subpatternsForVars: List[Pattern] = elemPatterns override def description = "Seq(%s)".format(elemPatterns mkString ", ") } // 8.1.8 (c) case class StarPattern(tree: Star) extends Pattern { - lazy val Star(elem) = tree override def description = "_*" } // XXX temporary? @@ -392,15 +374,7 @@ trait Patterns extends ast.TreeDSL { // Covers if the symbol matches the unapply method's argument type, // and the return type of the unapply is Some. override def covers(sym: Symbol) = newMatchesPattern(sym, arg.tpe) - - // TODO: for alwaysCovers: - // fn.tpe.finalResultType.typeSymbol == SomeClass - override def necessaryType = arg.tpe - override def subpatternsForVars = args match { - case List(ArrayValue(elemtpe, elems)) => toPats(elems) - case _ => toPats(args) - } def resTypes = analyzer.unapplyTypeList(unfn.symbol, unfn.tpe, args.length) def resTypesString = resTypes match { @@ -411,13 +385,7 @@ trait Patterns extends ast.TreeDSL { sealed trait ApplyPattern extends Pattern { lazy val Apply(fn, args) = tree - override def subpatternsForVars: List[Pattern] = toPats(args) - override def dummies = - if (!this.isCaseClass) Nil - else emptyPatterns(sufficientType.typeSymbol.caseFieldAccessors.size) - - def isConstructorPattern = fn.isType override def covers(sym: Symbol) = newMatchesPattern(sym, fn.tpe) } @@ -427,9 +395,6 @@ trait Patterns extends ast.TreeDSL { // returns either a simplification of this pattern or identity. def simplify(pv: PatternVar): Pattern = this - // the right number of dummies for this pattern - def dummies: List[Pattern] = Nil - // Is this a default pattern (untyped "_" or an EmptyTree inserted by the matcher) def isDefault = false @@ -459,14 +424,8 @@ trait Patterns extends ast.TreeDSL { def isModule = sym.isModule || tpe.termSymbol.isModule def isCaseClass = tpe.typeSymbol.isCase def isObject = (sym != null) && (sym != NoSymbol) && tpe.prefix.isStable // XXX not entire logic - def hasStar = false - def setType(tpe: Type): this.type = { - tree setType tpe - this - } - def equalsCheck = tracing("equalsCheck")( if (sym.isValue) singleType(NoPrefix, sym) @@ -483,7 +442,6 @@ trait Patterns extends ast.TreeDSL { final override def toString = description - def toTypeString() = "%s <: x <: %s".format(necessaryType, sufficientType) def kindString = "" } diff --git a/src/compiler/scala/tools/nsc/plugins/Plugin.scala b/src/compiler/scala/tools/nsc/plugins/Plugin.scala index 2050ce7ffd..093f8285e1 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugin.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugin.scala @@ -6,13 +6,10 @@ package scala.tools.nsc package plugins -import io.{ File, Path, Jar } +import io.{ Path, Jar } import java.net.URLClassLoader import java.util.jar.JarFile import java.util.zip.ZipException - -import scala.collection.mutable -import mutable.ListBuffer import scala.xml.XML /** Information about a plugin loaded from a jar file. @@ -74,7 +71,7 @@ object Plugin { } /** Try to load a plugin description from the specified - * file, returning <code>None</code> if it does not work. + * file, returning `None` if it does not work. */ private def loadDescription(jarfile: Path): Option[PluginDescription] = // XXX Return to this once we have some ARM support diff --git a/src/compiler/scala/tools/nsc/plugins/PluginDescription.scala b/src/compiler/scala/tools/nsc/plugins/PluginDescription.scala index bd567400fb..f77123ba11 100644 --- a/src/compiler/scala/tools/nsc/plugins/PluginDescription.scala +++ b/src/compiler/scala/tools/nsc/plugins/PluginDescription.scala @@ -6,7 +6,7 @@ package scala.tools.nsc package plugins -import scala.xml.{Node,NodeSeq} +import scala.xml.Node /** A description of a compiler plugin, suitable for serialization * to XML for inclusion in the plugin's .jar file. @@ -26,7 +26,7 @@ abstract class PluginDescription { val classname: String /** An XML representation of this description. It can be - * read back using <code>PluginDescription.fromXML</code>. + * read back using `PluginDescription.fromXML`. * It should be stored inside the jar archive file. */ def toXML: Node = { diff --git a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala index c7ee11dec0..025fc8e068 100644 --- a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala @@ -29,11 +29,7 @@ abstract class AbstractReporter extends Reporter { private def noWarnings = settings.nowarnings.value private def isPromptSet = settings.prompt.value - protected def info0(pos: Position, msg: String, _severity: Severity, force: Boolean) { - val severity = - if (settings.fatalWarnings.value && _severity == WARNING) ERROR - else _severity - + protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean) { if (severity == INFO) { if (isVerbose || force) { severity.count += 1 diff --git a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala index e847fb5b86..bda195f9d3 100644 --- a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala @@ -34,9 +34,6 @@ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: Pr } /** Returns the number of errors issued totally as a string. - * - * @param severity ... - * @return ... */ private def getCountString(severity: Severity): String = StringOps.countElementsAsString((severity).count, label(severity)) @@ -52,17 +49,12 @@ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: Pr printMessage(pos, clabel(severity) + msg) } - /** - * @param pos ... - */ def printSourceLine(pos: Position) { printMessage(pos.lineContent.stripLineEnd) printColumnMarker(pos) } /** Prints the column marker of the given position. - * - * @param pos ... */ def printColumnMarker(pos: Position) = if (pos.isDefined) { printMessage(" " * (pos.column - 1) + "^") } @@ -94,6 +86,5 @@ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: Pr } } - private def abort(msg: String) = throw new Error(msg) override def flush() { writer.flush() } } diff --git a/src/compiler/scala/tools/nsc/reporters/Reporter.scala b/src/compiler/scala/tools/nsc/reporters/Reporter.scala index 8871ae6555..817ec47ab3 100644 --- a/src/compiler/scala/tools/nsc/reporters/Reporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/Reporter.scala @@ -7,7 +7,6 @@ package scala.tools.nsc package reporters import scala.reflect.internal.util._ -import scala.reflect.internal.util.StringOps._ /** * This interface provides methods to issue information, warning and diff --git a/src/compiler/scala/tools/nsc/scratchpad/Mixer.scala b/src/compiler/scala/tools/nsc/scratchpad/Mixer.scala index 10e9982594..3aecc06b1e 100644 --- a/src/compiler/scala/tools/nsc/scratchpad/Mixer.scala +++ b/src/compiler/scala/tools/nsc/scratchpad/Mixer.scala @@ -2,9 +2,6 @@ package scala.tools.nsc.scratchpad import java.io.{FileInputStream, InputStreamReader, IOException} -import scala.runtime.ScalaRunTime.stringOf -import java.lang.reflect.InvocationTargetException -import scala.reflect.runtime.ReflectionUtils._ import scala.collection.mutable.ArrayBuffer @deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0") diff --git a/src/compiler/scala/tools/nsc/scratchpad/SourceInserter.scala b/src/compiler/scala/tools/nsc/scratchpad/SourceInserter.scala index 01dccd7521..61c1717fea 100644 --- a/src/compiler/scala/tools/nsc/scratchpad/SourceInserter.scala +++ b/src/compiler/scala/tools/nsc/scratchpad/SourceInserter.scala @@ -1,8 +1,6 @@ package scala.tools.nsc package scratchpad -import java.io.Writer -import scala.reflect.internal.util.SourceFile import scala.reflect.internal.Chars._ @deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0") diff --git a/src/compiler/scala/tools/nsc/settings/AbsSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala index adabeb02a3..4727e6d867 100644 --- a/src/compiler/scala/tools/nsc/settings/AbsSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala @@ -47,8 +47,6 @@ trait AbsSettings extends scala.reflect.internal.settings.AbsSettings { } }) - implicit lazy val SettingOrdering: Ordering[Setting] = Ordering.ordered - trait AbsSetting extends Ordered[Setting] with AbsSettingValue { def name: String def helpDescription: String @@ -83,14 +81,6 @@ trait AbsSettings extends scala.reflect.internal.settings.AbsSettings { this } - /** If the appearance of the setting should halt argument processing. */ - private var isTerminatorSetting = false - def shouldStopProcessing = isTerminatorSetting - def stopProcessing(): this.type = { - isTerminatorSetting = true - this - } - /** Issue error and return */ def errorAndValue[T](msg: String, x: T): T = { errorFn(msg) ; x } @@ -110,6 +100,7 @@ trait AbsSettings extends scala.reflect.internal.settings.AbsSettings { /** Attempt to set from a properties file style property value. * Currently used by Eclipse SDT only. + * !!! Needs test. */ def tryToSetFromPropertyValue(s: String): Unit = tryToSet(s :: Nil) @@ -133,7 +124,7 @@ trait AbsSettings extends scala.reflect.internal.settings.AbsSettings { case _ => false } override def hashCode() = name.hashCode + value.hashCode - override def toString() = name + " = " + value + override def toString() = name + " = " + (if (value == "") "\"\"" else value) } trait InternalSetting extends AbsSetting { diff --git a/src/compiler/scala/tools/nsc/settings/AdvancedScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/AdvancedScalaSettings.scala deleted file mode 100644 index 0bec113743..0000000000 --- a/src/compiler/scala/tools/nsc/settings/AdvancedScalaSettings.scala +++ /dev/null @@ -1,77 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package settings - -trait AdvancedScalaSettings { - self: AbsScalaSettings => - - abstract class X extends SettingGroup("-X") { - val assemextdirs: StringSetting - val assemname: StringSetting - val assempath: StringSetting - val checkinit: BooleanSetting - val disableassertions: BooleanSetting - val elidebelow: IntSetting - val experimental: BooleanSetting - val future: BooleanSetting - val generatephasegraph: StringSetting - val logimplicits: BooleanSetting - val mainClass: StringSetting - val migration: BooleanSetting - val noforwarders: BooleanSetting - val nojline: BooleanSetting - val nouescape: BooleanSetting - val plugin: MultiStringSetting - val plugindisable: MultiStringSetting - val pluginlist: BooleanSetting - val pluginrequire: MultiStringSetting - val pluginsdir: StringSetting - val print: PhasesSetting - val printicode: BooleanSetting - val printpos: BooleanSetting - val printtypes: BooleanSetting - val prompt: BooleanSetting - val resident: BooleanSetting - val script: StringSetting - val showclass: StringSetting - val showobject: StringSetting - val showphases: BooleanSetting - val sourcedir: StringSetting - val sourcereader: StringSetting - } - // def Xexperimental = X.experimental - // def Xmigration28 = X.migration - // def Xnojline = X.nojline - // def Xprint = X.print - // def Xprintpos = X.printpos - // def Xshowcls = X.showclass - // def Xshowobj = X.showobject - // def assemextdirs = X.assemextdirs - // def assemname = X.assemname - // def assemrefs = X.assempath - // def checkInit = X.checkinit - // def disable = X.plugindisable - // def elideLevel = X.elidelevel - // def future = X.future - // def genPhaseGraph = X.generatephasegraph - // def logimplicits = X.logimplicits - // def noForwarders = X.noforwarders - // def noassertions = X.disableassertions - // def nouescape = X.nouescape - // def plugin = X.plugin - // def pluginsDir = X.pluginsdir - // def printtypes = X.printtypes - // def prompt = X.prompt - // def require = X.require - // def resident = X.resident - // def script = X.script - // def showPhases = X.showphases - // def showPlugins = X.pluginlist - // def sourceReader = X.sourcereader - // def sourcedir = X.sourcedir - // def writeICode = X.printicode -}
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/settings/AestheticSettings.scala b/src/compiler/scala/tools/nsc/settings/AestheticSettings.scala deleted file mode 100644 index da2c89d707..0000000000 --- a/src/compiler/scala/tools/nsc/settings/AestheticSettings.scala +++ /dev/null @@ -1,39 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package settings - -/** Taking flag checking to a somewhat higher level. */ -trait AestheticSettings { - def settings: Settings - - // Some(value) if setting has been set by user, None otherwise. - def optSetting[T](s: Settings#Setting): Option[T] = - if (s.isDefault) None else Some(s.value.asInstanceOf[T]) - - def script = optSetting[String](settings.script) - def encoding = optSetting[String](settings.encoding) - def sourceReader = optSetting[String](settings.sourceReader) - - def debug = settings.debug.value - def declsOnly = false - def deprecation = settings.deprecation.value - def experimental = settings.Xexperimental.value - def fatalWarnings = settings.fatalWarnings.value - def feature = settings.feature.value - def future = settings.future.value - def logClasspath = settings.Ylogcp.value - def printStats = settings.Ystatistics.value - def target = settings.target.value - def unchecked = settings.unchecked.value - def verbose = settings.verbose.value - def virtPatmat = !settings.XoldPatmat.value - - /** Derived values */ - def jvm = target startsWith "jvm" - def msil = target == "msil" - def verboseDebug = debug && verbose -} diff --git a/src/compiler/scala/tools/nsc/settings/FscSettings.scala b/src/compiler/scala/tools/nsc/settings/FscSettings.scala index 06ebc20d3e..14b398e50a 100644 --- a/src/compiler/scala/tools/nsc/settings/FscSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/FscSettings.scala @@ -8,7 +8,7 @@ package nsc package settings import util.ClassPath -import io.{ Directory, Path, AbstractFile } +import io.{ Path, AbstractFile } class FscSettings(error: String => Unit) extends Settings(error) { outer => diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala index f1f289ed4d..748c6069f0 100644 --- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala @@ -10,7 +10,6 @@ package settings import io.{ AbstractFile, Jar, Path, PlainFile, VirtualDirectory } import scala.reflect.internal.util.StringOps -import scala.collection.mutable.ListBuffer import scala.io.Source import scala.reflect.{ ClassTag, classTag } @@ -63,30 +62,23 @@ class MutableSettings(val errorFn: String => Unit) (checkDependencies, residualArgs) case "--" :: xs => (checkDependencies, xs) + // discard empties, sometimes they appear because of ant or etc. + // but discard carefully, because an empty string is valid as an argument + // to an option, e.g. -cp "" . So we discard them only when they appear + // where an option should be, not where an argument to an option should be. + case "" :: xs => + loop(xs, residualArgs) case x :: xs => - val isOpt = x startsWith "-" - if (isOpt) { - val newArgs = parseParams(args) - if (args eq newArgs) { - errorFn(s"bad option: '$x'") - (false, args) + if (x startsWith "-") { + parseParams(args) match { + case newArgs if newArgs eq args => errorFn(s"bad option: '$x'") ; (false, args) + case newArgs => loop(newArgs, residualArgs) } - // discard empties, sometimes they appear because of ant or etc. - // but discard carefully, because an empty string is valid as an argument - // to an option, e.g. -cp "" . So we discard them only when they appear - // in option position. - else if (x == "") { - loop(xs, residualArgs) - } - else lookupSetting(x) match { - case Some(s) if s.shouldStopProcessing => (checkDependencies, newArgs) - case _ => loop(newArgs, residualArgs) - } - } - else { - if (processAll) loop(xs, residualArgs :+ x) - else (checkDependencies, args) } + else if (processAll) + loop(xs, residualArgs :+ x) + else + (checkDependencies, args) } loop(arguments, Nil) } @@ -184,7 +176,7 @@ class MutableSettings(val errorFn: String => Unit) * The class loader defining `T` should provide resources `app.class.path` * and `boot.class.path`. These resources should contain the application * and boot classpaths in the same form as would be passed on the command line.*/ - def embeddedDefaults[T: ClassTag]: Unit = + def embeddedDefaults[T: ClassTag]: Unit = // called from sbt and repl embeddedDefaults(classTag[T].runtimeClass.getClassLoader) /** Initializes these settings for embedded use by a class from the given class loader. @@ -247,7 +239,7 @@ class MutableSettings(val errorFn: String => Unit) /** Add a destination directory for sources found under srcdir. * Both directories should exits. */ - def add(srcDir: String, outDir: String): Unit = + def add(srcDir: String, outDir: String): Unit = // used in ide? add(checkDir(AbstractFile.getDirectory(srcDir), srcDir), checkDir(AbstractFile.getDirectory(outDir), outDir)) @@ -442,7 +434,7 @@ class MutableSettings(val errorFn: String => Unit) def tryToSet(args: List[String]) = { value = true ; Some(args) } def unparse: List[String] = if (value) List(name) else Nil - override def tryToSetFromPropertyValue(s : String) { + override def tryToSetFromPropertyValue(s : String) { // used from ide value = s.equalsIgnoreCase("true") } } @@ -535,7 +527,7 @@ class MutableSettings(val errorFn: String => Unit) Some(rest) } override def tryToSetColon(args: List[String]) = tryToSet(args) - override def tryToSetFromPropertyValue(s: String) = tryToSet(s.trim.split(',').toList) + override def tryToSetFromPropertyValue(s: String) = tryToSet(s.trim.split(',').toList) // used from ide def unparse: List[String] = value map (name + ":" + _) withHelpSyntax(name + ":<" + arg + ">") @@ -569,7 +561,7 @@ class MutableSettings(val errorFn: String => Unit) } def unparse: List[String] = if (value == default) Nil else List(name + ":" + value) - override def tryToSetFromPropertyValue(s: String) = tryToSetColon(s::Nil) + override def tryToSetFromPropertyValue(s: String) = tryToSetColon(s::Nil) // used from ide withHelpSyntax(name + ":<" + helpArg + ">") } diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index cfc7f14210..cf6579a696 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -52,14 +52,14 @@ trait ScalaSettings extends AbsScalaSettings val jvmargs = PrefixSetting("-J<flag>", "-J", "Pass <flag> directly to the runtime system.") val defines = PrefixSetting("-Dproperty=value", "-D", "Pass -Dproperty=value directly to the runtime system.") - val toolcp = PathSetting("-toolcp", "Add to the runner classpath.", "") + /*val toolcp =*/ PathSetting("-toolcp", "Add to the runner classpath.", "") val nobootcp = BooleanSetting("-nobootcp", "Do not use the boot classpath for the scala jars.") /** * Standard settings */ // argfiles is only for the help message - val argfiles = BooleanSetting ("@<file>", "A text file containing compiler arguments (options and source files)") + /*val argfiles = */ BooleanSetting ("@<file>", "A text file containing compiler arguments (options and source files)") val classpath = PathSetting ("-classpath", "Specify where to find user class files.", defaultClasspath) withAbbreviation "-cp" val d = OutputSetting (outputDirs, ".") val nospecialization = BooleanSetting ("-no-specialization", "Ignore @specialize annotations.") @@ -74,6 +74,7 @@ trait ScalaSettings extends AbsScalaSettings val assemextdirs = StringSetting ("-Xassem-extdirs", "dirs", "(Requires -target:msil) List of directories containing assemblies. default:lib", Defaults.scalaLibDir.path).dependsOn(target, "msil") val sourcedir = StringSetting ("-Xsourcedir", "directory", "(Requires -target:msil) Mirror source folder structure in output directory.", ".").dependsOn(target, "msil") val checkInit = BooleanSetting ("-Xcheckinit", "Wrap field accessors to throw an exception on uninitialized access.") + val developer = BooleanSetting ("-Xdev", "Indicates user is a developer - issue warnings about anything which seems amiss") val noassertions = BooleanSetting ("-Xdisable-assertions", "Generate no assertions or assumptions.") val elidebelow = IntSetting ("-Xelide-below", "Calls to @elidable methods are omitted if method priority is lower than argument", elidable.MINIMUM, None, elidable.byName get _) @@ -114,7 +115,6 @@ trait ScalaSettings extends AbsScalaSettings /** Compatibility stubs for options whose value name did * not previously match the option name. */ - def XO = optimise def debuginfo = g def dependenciesFile = dependencyfile def nowarnings = nowarn @@ -127,6 +127,7 @@ trait ScalaSettings extends AbsScalaSettings val overrideObjects = BooleanSetting ("-Yoverride-objects", "Allow member objects to be overridden.") val overrideVars = BooleanSetting ("-Yoverride-vars", "Allow vars to be overridden.") val Yhelp = BooleanSetting ("-Y", "Print a synopsis of private options.") + val breakCycles = BooleanSetting ("-Ybreak-cycles", "Attempt to break cycles encountered during typing") val browse = PhasesSetting ("-Ybrowse", "Browse the abstract syntax tree after") val check = PhasesSetting ("-Ycheck", "Check the tree at the end of") val Yshow = PhasesSetting ("-Yshow", "(Requires -Xshow-class or -Xshow-object) Show after") @@ -169,6 +170,7 @@ trait ScalaSettings extends AbsScalaSettings val Ybuilderdebug = ChoiceSetting ("-Ybuilder-debug", "manager", "Compile using the specified build manager.", List("none", "refined", "simple"), "none") val Yreifycopypaste = BooleanSetting ("-Yreify-copypaste", "Dump the reified trees in copypasteable representation.") val Yreplsync = BooleanSetting ("-Yrepl-sync", "Do not use asynchronous code for repl startup") + val Yreploutdir = StringSetting ("-Yrepl-outdir", "path", "Write repl-generated classfiles to given output directory (use \"\" to generate a temporary dir)" , "") val Ynotnull = BooleanSetting ("-Ynotnull", "Enable (experimental and incomplete) scala.NotNull.") val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overriden methods.") val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.") @@ -178,12 +180,9 @@ trait ScalaSettings extends AbsScalaSettings val exposeEmptyPackage = BooleanSetting("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly() - def stop = stopAfter - /** Area-specific debug output. */ val Ybuildmanagerdebug = BooleanSetting("-Ybuild-manager-debug", "Generate debug information for the Refined Build Manager compiler.") - val Ycompletion = BooleanSetting("-Ycompletion-debug", "Trace all tab completion activity.") val Ydocdebug = BooleanSetting("-Ydoc-debug", "Trace all scaladoc activity.") val Yidedebug = BooleanSetting("-Yide-debug", "Generate, validate and output trees using the interactive compiler.") val Yinferdebug = BooleanSetting("-Yinfer-debug", "Trace type inference and implicit search.") diff --git a/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala index e866ad6ae0..98ef74aee3 100644 --- a/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala @@ -48,9 +48,4 @@ trait StandardScalaSettings { val usejavacp = BooleanSetting ("-usejavacp", "Utilize the java.class.path in classpath resolution.") val verbose = BooleanSetting ("-verbose", "Output messages about what the compiler is doing.") val version = BooleanSetting ("-version", "Print product version and exit.") - - /** These are @<file> and -Dkey=val style settings, which don't - * nicely map to identifiers. - */ - val argfiles: BooleanSetting // exists only to echo help message, should be done differently } diff --git a/src/compiler/scala/tools/nsc/settings/Warnings.scala b/src/compiler/scala/tools/nsc/settings/Warnings.scala index 9f9879210c..2649a150ad 100644 --- a/src/compiler/scala/tools/nsc/settings/Warnings.scala +++ b/src/compiler/scala/tools/nsc/settings/Warnings.scala @@ -26,11 +26,11 @@ trait Warnings { // These warnings should be pretty quiet unless you're doing // something inadvisable. protected def lintWarnings = List( - // warnDeadCode, warnInaccessible, warnNullaryOverride, warnNullaryUnit, - warnAdaptedArgs + warnAdaptedArgs, + warnInferAny ) // Warning groups. @@ -38,9 +38,13 @@ trait Warnings { BooleanSetting("-Xlint", "Enable recommended additional warnings.") withPostSetHook (_ => lintWarnings foreach (_.value = true)) ) - val warnEverything = ( + + /*val warnEverything = */ ( BooleanSetting("-Ywarn-all", "Enable all -Y warnings.") - withPostSetHook (_ => lintWarnings foreach (_.value = true)) + withPostSetHook { _ => + lint.value = true + allWarnings foreach (_.value = true) + } ) // Individual warnings. @@ -53,9 +57,10 @@ trait Warnings { val warnInaccessible = BooleanSetting ("-Ywarn-inaccessible", "Warn about inaccessible types in method signatures.") val warnNullaryOverride = BooleanSetting ("-Ywarn-nullary-override", "Warn when non-nullary overrides nullary, e.g. `def foo()` over `def foo`.") + val warnInferAny = BooleanSetting ("-Ywarn-infer-any", "Warn when a type argument is inferred to be `Any`.") // Backward compatibility. - def Xwarnfatal = fatalWarnings - def Xchecknull = warnSelectNullable - def Ywarndeadcode = warnDeadCode + @deprecated("Use fatalWarnings", "2.11.0") def Xwarnfatal = fatalWarnings // used by sbt + @deprecated("Use warnSelectNullable", "2.11.0") def Xchecknull = warnSelectNullable // used by ide + @deprecated("Use warnDeadCode", "2.11.0") def Ywarndeadcode = warnDeadCode // used by ide } diff --git a/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala index f2aab36b51..4e4efef607 100644 --- a/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala @@ -6,7 +6,6 @@ package scala.tools.nsc package symtab -import scala.reflect.internal.util.BatchSourceFile import scala.tools.nsc.io.AbstractFile /** A subclass of SymbolLoaders that implements browsing behavior. @@ -28,7 +27,7 @@ abstract class BrowsingLoaders extends SymbolLoaders { override protected def enterIfNew(owner: Symbol, member: Symbol, completer: SymbolLoader): Symbol = { completer.sourcefile match { case Some(src) => - (if (member.isModule) member.moduleClass else member).sourceFile = src + (if (member.isModule) member.moduleClass else member).associatedFile = src case _ => } val decls = owner.info.decls diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 348c7f688f..19502f0d7e 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -10,7 +10,6 @@ import java.io.IOException import scala.compat.Platform.currentTime import scala.tools.nsc.util.{ ClassPath } import classfile.ClassfileParser -import scala.reflect.internal.Flags._ import scala.reflect.internal.MissingRequirementError import scala.reflect.internal.util.Statistics import scala.tools.nsc.io.{ AbstractFile, MsilFile } @@ -162,8 +161,8 @@ abstract class SymbolLoaders { private def setSource(sym: Symbol) { sourcefile foreach (sf => sym match { - case cls: ClassSymbol => cls.sourceFile = sf - case mod: ModuleSymbol => mod.moduleClass.sourceFile = sf + case cls: ClassSymbol => cls.associatedFile = sf + case mod: ModuleSymbol => mod.moduleClass.associatedFile = sf case _ => () }) } @@ -226,7 +225,6 @@ abstract class SymbolLoaders { assert(root.isPackageClass, root) root.setInfo(new PackageClassInfoType(newScope, root)) - val sourcepaths = classpath.sourcepaths if (!root.isRoot) { for (classRep <- classpath.classes if platform.doLoad(classRep)) { initializeFromClassPath(root, classRep) diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTrackers.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTrackers.scala index 7a84441e09..035244e421 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolTrackers.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolTrackers.scala @@ -6,7 +6,6 @@ package scala.tools.nsc package symtab -import scala.collection.{ mutable, immutable } import scala.language.implicitConversions import scala.language.postfixOps @@ -17,9 +16,6 @@ trait SymbolTrackers { val global: Global import global._ - private implicit lazy val TreeOrdering: Ordering[Tree] = - Ordering by (x => (x.shortClass, x.symbol)) - private implicit lazy val SymbolOrdering: Ordering[Symbol] = Ordering by (x => (x.kindString, x.name.toString)) @@ -76,7 +72,6 @@ trait SymbolTrackers { private def isFlagsChange(sym: Symbol) = changed.flags contains sym private implicit def NodeOrdering: Ordering[Node] = Ordering by (_.root) - private def ownersString(sym: Symbol, num: Int) = sym.ownerChain drop 1 take num mkString " -> " object Node { def nodes(syms: Set[Symbol]): List[Node] = { @@ -114,7 +109,6 @@ trait SymbolTrackers { case Some(oldFlags) => val added = masked & ~oldFlags val removed = oldFlags & ~masked - val steady = masked & ~(added | removed) val all = masked | oldFlags val strs = 0 to 63 map { bit => val flag = 1L << bit @@ -181,7 +175,7 @@ trait SymbolTrackers { } def show(label: String): String = { val hierarchy = Node(current) - val Change(added, removed, symMap, owners, flags) = history.head + val Change(_, removed, symMap, _, _) = history.head def detailString(sym: Symbol) = { val ownerString = sym.ownerChain splitAt 3 match { case (front, back) => diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/AbstractFileReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/AbstractFileReader.scala index 427b5bf887..17e3b08ec2 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/AbstractFileReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/AbstractFileReader.scala @@ -29,11 +29,6 @@ class AbstractFileReader(val file: AbstractFile) { */ var bp: Int = 0 - /** return byte at offset 'pos' - */ - @throws(classOf[IndexOutOfBoundsException]) - def byteAt(pos: Int): Byte = buf(pos) - /** read a byte */ @throws(classOf[IndexOutOfBoundsException]) @@ -45,7 +40,7 @@ class AbstractFileReader(val file: AbstractFile) { /** read some bytes */ - def nextBytes(len: Int): Array[Byte] = { + def nextBytes(len: Int): Array[Byte] = { // used in ide bp += len buf.slice(bp - len, bp) } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index a708a262e7..6d213af2b6 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -23,7 +23,6 @@ import scala.tools.nsc.io.AbstractFile abstract class ClassfileParser { val global: Global import global._ - import definitions.{ AnnotationClass, ClassfileAnnotationClass } import scala.reflect.internal.ClassfileConstants._ import Flags._ @@ -186,7 +185,7 @@ abstract class ClassfileParser { if (in.buf(start).toInt != CONSTANT_CLASS) errorBadTag(start) val name = getExternalName(in.getChar(start + 1)) if (nme.isModuleName(name)) - c = rootMirror.getModule(nme.stripModuleSuffix(name)) + c = rootMirror.getModuleByName(nme.stripModuleSuffix(name)) else c = classNameToSymbol(name) @@ -237,7 +236,7 @@ abstract class ClassfileParser { //assert(name.endsWith("$"), "Not a module class: " + name) f = forceMangledName(name dropRight 1, true) if (f == NoSymbol) - f = rootMirror.getModule(name dropRight 1) + f = rootMirror.getModuleByName(name dropRight 1) } else { val origName = nme.originalName(name) val owner = if (static) ownerTpe.typeSymbol.linkedClassOfClass else ownerTpe.typeSymbol @@ -361,7 +360,7 @@ abstract class ClassfileParser { } value match { case ct: Constant => ct - case cls: Symbol => Constant(cls.tpe) + case cls: Symbol => Constant(cls.tpe_*) case arr: Type => Constant(arr) } } @@ -423,9 +422,9 @@ abstract class ClassfileParser { var sym: Symbol = rootMirror.RootClass // was "at flatten.prev" - beforeFlatten { + enteringFlatten { for (part0 <- parts; if !(part0 == ""); part = newTermName(part0)) { - val sym1 = beforeIcode { + val sym1 = enteringIcode { sym.linkedClassOfClass.info sym.info.decl(part.encode) }//.suchThat(module == _.isModule) @@ -478,7 +477,7 @@ abstract class ClassfileParser { if (name.pos('.') == name.length) definitions.getMember(rootMirror.EmptyPackageClass, name.toTypeName) else - rootMirror.getClass(name) // see tickets #2464, #3756 + rootMirror.getClassByName(name) // see tickets #2464, #3756 } catch { case _: FatalError => loadClassSymbol(name) } @@ -500,8 +499,8 @@ abstract class ClassfileParser { def parseClass() { val jflags = in.nextChar val isAnnotation = hasAnnotation(jflags) - var sflags = toScalaClassFlags(jflags) - var nameIdx = in.nextChar + val sflags = toScalaClassFlags(jflags) + val nameIdx = in.nextChar currentClass = pool.getClassName(nameIdx) /** Parse parents for Java classes. For Scala, return AnyRef, since the real type will be unpickled. @@ -515,9 +514,9 @@ abstract class ClassfileParser { } else raiseLoaderLevel { val superType = if (isAnnotation) { in.nextChar; definitions.AnnotationClass.tpe } - else pool.getSuperClass(in.nextChar).tpe + else pool.getSuperClass(in.nextChar).tpe_* val ifaceCount = in.nextChar - var ifaces = for (i <- List.range(0, ifaceCount)) yield pool.getSuperClass(in.nextChar).tpe + var ifaces = for (i <- List.range(0, ifaceCount)) yield pool.getSuperClass(in.nextChar).tpe_* if (isAnnotation) ifaces = definitions.ClassfileAnnotationClass.tpe :: ifaces superType :: ifaces } @@ -565,7 +564,7 @@ abstract class ClassfileParser { 0 until in.nextChar foreach (_ => parseMethod()) val needsConstructor = ( !sawPrivateConstructor - && instanceScope.lookup(nme.CONSTRUCTOR) == NoSymbol + && !(instanceScope containsName nme.CONSTRUCTOR) && (sflags & INTERFACE) == 0 ) if (needsConstructor) @@ -599,7 +598,7 @@ abstract class ClassfileParser { def parseField() { val jflags = in.nextChar - var sflags = toScalaFieldFlags(jflags) + val sflags = toScalaFieldFlags(jflags) if ((sflags & PRIVATE) != 0L && !global.settings.optimise.value) { in.skip(4); skipAttributes() } else { @@ -629,7 +628,7 @@ abstract class ClassfileParser { def parseMethod() { val jflags = in.nextChar.toInt - var sflags = toScalaMethodFlags(jflags) + val sflags = toScalaMethodFlags(jflags) if (isPrivate(jflags) && !global.settings.optimise.value) { val name = pool.getName(in.nextChar) if (name == nme.CONSTRUCTOR) @@ -735,17 +734,19 @@ abstract class ClassfileParser { } accept('>') assert(xs.length > 0, tp) - newExistentialType(existentials.toList, typeRef(pre, classSym, xs.toList)) - } else if (classSym.isMonomorphicType) { + logResult("new existential")(newExistentialType(existentials.toList, typeRef(pre, classSym, xs.toList))) + } + // isMonomorphicType is false if the info is incomplete, as it usually is here + // so have to check unsafeTypeParams.isEmpty before worrying about raw type case below, + // or we'll create a boatload of needless existentials. + else if (classSym.isMonomorphicType || classSym.unsafeTypeParams.isEmpty) { tp - } else { + } + else { // raw type - existentially quantify all type parameters val eparams = typeParamsToExistentials(classSym, classSym.unsafeTypeParams) - val t = typeRef(pre, classSym, eparams.map(_.tpeHK)) - val res = newExistentialType(eparams, t) - if (settings.debug.value && settings.verbose.value) - println("raw type " + classSym + " -> " + res) - res + val t = typeRef(pre, classSym, eparams.map(_.tpeHK)) + logResult(s"raw type from $classSym")(newExistentialType(eparams, t)) } case tp => assert(sig.charAt(index) != '<', tp) @@ -754,7 +755,7 @@ abstract class ClassfileParser { val classSym = classNameToSymbol(subName(c => c == ';' || c == '<')) assert(!classSym.isOverloaded, classSym.alternatives) - var tpe = processClassType(processInner(classSym.tpe)) + var tpe = processClassType(processInner(classSym.tpe_*)) while (sig.charAt(index) == '.') { accept('.') val name = subName(c => c == ';' || c == '<' || c == '.').toTypeName @@ -787,7 +788,7 @@ abstract class ClassfileParser { index += 1 val restype = if (sym != null && sym.isClassConstructor) { accept('V') - clazz.tpe + clazz.tpe_* } else sig2type(tparams, skiptvs) JavaMethodType(sym.newSyntheticValueParams(paramtypes.toList), restype) @@ -875,7 +876,7 @@ abstract class ClassfileParser { sym.setFlag(SYNTHETIC | ARTIFACT) in.skip(attrLen) case tpnme.BridgeATTR => - sym.setFlag(BRIDGE) + sym.setFlag(BRIDGE | ARTIFACT) in.skip(attrLen) case tpnme.DeprecatedATTR => val arg = Literal(Constant("see corresponding Javadoc for more information.")) @@ -1079,7 +1080,7 @@ abstract class ClassfileParser { def enterClassAndModule(entry: InnerClassEntry, file: AbstractFile, jflags: Int) { val completer = new global.loaders.ClassfileLoader(file) val name = entry.originalName - var sflags = toScalaClassFlags(jflags) + val sflags = toScalaClassFlags(jflags) val owner = getOwner(jflags) val scope = getScope(jflags) val innerClass = owner.newClass(name.toTypeName, NoPosition, sflags) setInfo completer @@ -1167,21 +1168,7 @@ abstract class ClassfileParser { originalName + " in " + outerName + "(" + externalName +")" } - object innerClasses extends scala.collection.mutable.HashMap[Name, InnerClassEntry] { - /** Return the Symbol of the top level class enclosing `name`, - * or 'name's symbol if no entry found for `name`. - */ - def topLevelClass(name: Name): Symbol = { - val tlName = if (isDefinedAt(name)) { - var entry = this(name) - while (isDefinedAt(entry.outerName)) - entry = this(entry.outerName) - entry.outerName - } else - name - classNameToSymbol(tlName) - } - + object innerClasses extends mutable.HashMap[Name, InnerClassEntry] { /** Return the class symbol for `externalName`. It looks it up in its outer class. * Forces all outer class symbols to be completed. * @@ -1206,7 +1193,7 @@ abstract class ClassfileParser { // if loading during initialization of `definitions` typerPhase is not yet set. // in that case we simply load the member at the current phase if (currentRun.typerPhase != null) - beforeTyper(getMember(sym, innerName.toTypeName)) + enteringTyper(getMember(sym, innerName.toTypeName)) else getMember(sym, innerName.toTypeName) diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala index 13c0d8993a..b5459ec773 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala @@ -9,9 +9,7 @@ package classfile import scala.collection.{ mutable, immutable } import mutable.ListBuffer -import backend.icode._ import ClassfileConstants._ -import scala.reflect.internal.Flags._ /** ICode reader from Java bytecode. * @@ -33,7 +31,6 @@ abstract class ICodeReader extends ClassfileParser { * for non-static members. */ def readClass(cls: Symbol): (IClass, IClass) = { - var classFile: io.AbstractFile = null; cls.info // ensure accurate type information isScalaModule = cls.isModule && !cls.isJavaDefined @@ -58,11 +55,9 @@ abstract class ICodeReader extends ClassfileParser { override def parseClass() { this.instanceCode = new IClass(clazz) this.staticCode = new IClass(staticModule) - val jflags = in.nextChar - val isAttribute = (jflags & JAVA_ACC_ANNOTATION) != 0 - val sflags = toScalaClassFlags(jflags) // what, this is never used?? - val c = pool getClassSymbol in.nextChar + in.nextChar + pool getClassSymbol in.nextChar parseInnerClasses() in.skip(2) // super class @@ -125,7 +120,7 @@ abstract class ICodeReader extends ClassfileParser { override def parseMethod() { val (jflags, sym) = parseMember(false) - var beginning = in.bp + val beginning = in.bp try { if (sym != NoSymbol) { this.method = new IMethod(sym) @@ -170,11 +165,11 @@ abstract class ICodeReader extends ClassfileParser { } else if (nme.isModuleName(name)) { val strippedName = nme.stripModuleSuffix(name) - forceMangledName(newTermName(strippedName.decode), true) orElse rootMirror.getModule(strippedName) + forceMangledName(newTermName(strippedName.decode), true) orElse rootMirror.getModuleByName(strippedName) } else { forceMangledName(name, false) - afterFlatten(rootMirror.getClassByName(name.toTypeName)) + exitingFlatten(rootMirror.getClassByName(name.toTypeName)) } if (sym.isModule) sym.moduleClass @@ -637,9 +632,9 @@ abstract class ICodeReader extends ClassfileParser { else instanceCode class LinearCode { - var instrs: ListBuffer[(Int, Instruction)] = new ListBuffer - var jmpTargets: mutable.Set[Int] = perRunCaches.newSet[Int]() - var locals: mutable.Map[Int, List[(Local, TypeKind)]] = perRunCaches.newMap() + val instrs: ListBuffer[(Int, Instruction)] = new ListBuffer + val jmpTargets: mutable.Set[Int] = perRunCaches.newSet[Int]() + val locals: mutable.Map[Int, List[(Local, TypeKind)]] = perRunCaches.newMap() var containsDUPX = false var containsNEW = false @@ -669,7 +664,6 @@ abstract class ICodeReader extends ClassfileParser { val blocks = makeBasicBlocks var otherBlock: BasicBlock = NoBasicBlock - var disableJmpTarget = false for ((pc, instr) <- instrs.iterator) { // Console.println("> " + pc + ": " + instr); @@ -720,11 +714,9 @@ abstract class ICodeReader extends ClassfileParser { val tfa = new analysis.MethodTFA() { import analysis._ - import analysis.typeFlowLattice.IState /** Abstract interpretation for one instruction. */ override def mutatingInterpret(out: typeFlowLattice.Elem, i: Instruction): typeFlowLattice.Elem = { - val bindings = out.vars val stack = out.stack import stack.push i match { @@ -901,7 +893,7 @@ abstract class ICodeReader extends ClassfileParser { for (bb <- method.code.blocks ; (i, idx) <- bb.toList.zipWithIndex) i match { case cm @ CALL_METHOD(m, Static(true)) if m.isClassConstructor => - def loop(bb0: BasicBlock, idx0: Int, depth: Int = 0): Unit = { + def loop(bb0: BasicBlock, idx0: Int, depth: Int): Unit = { rdef.findDefs(bb0, idx0, 1, depth) match { case ((bb1, idx1)) :: _ => bb1(idx1) match { diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index b9eb1ba0cd..42ea7e61f0 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -26,15 +26,23 @@ import Flags._ abstract class Pickler extends SubComponent { import global._ - private final val showSig = false - val phaseName = "pickler" - currentRun - def newPhase(prev: Phase): StdPhase = new PicklePhase(prev) class PicklePhase(prev: Phase) extends StdPhase(prev) { + override def run() { + super.run() + // This is run here rather than after typer because I found + // some symbols - usually annotations, possibly others - had not + // yet performed the necessary symbol lookup, leading to + // spurious claims of unusedness. + if (settings.lint.value) { + log("Clearing recorded import selectors.") + analyzer.clearUnusedImports() + } + } + def apply(unit: CompilationUnit) { def pickle(tree: Tree) { def add(sym: Symbol, pickle: Pickle) = { @@ -68,17 +76,19 @@ abstract class Pickler extends SubComponent { return } - if (!t.isDef && t.hasSymbol && t.symbol.isTermMacro) { + if (!t.isDef && t.hasSymbolField && t.symbol.isTermMacro) { unit.error(t.pos, t.symbol.typeParams.length match { case 0 => "macro has not been expanded" - case 1 => "type parameter not specified" - case _ => "type parameters not specified" + case 1 => "this type parameter must be specified" + case _ => "these type parameters must be specified" }) return } } pickle(unit.body) + if (settings.lint.value) + analyzer.warnUnusedImports(unit) } } @@ -139,8 +149,6 @@ abstract class Pickler extends SubComponent { } /** Store symbol in index. If symbol is local, also store everything it references. - * - * @param sym ... */ def putSymbol(sym: Symbol) { if (putEntry(sym)) { @@ -177,7 +185,7 @@ abstract class Pickler extends SubComponent { */ private def putType(tp: Type): Unit = if (putEntry(tp)) { tp match { - case NoType | NoPrefix /*| DeBruijnIndex(_, _) */ => + case NoType | NoPrefix => ; case ThisType(sym) => putSymbol(sym) @@ -235,7 +243,7 @@ abstract class Pickler extends SubComponent { private def putTree(tree: Tree): Unit = if (putEntry(tree)) { if (tree != EmptyTree) putType(tree.tpe) - if (tree.hasSymbol) + if (tree.hasSymbolField) putSymbol(tree.symbol) tree match { @@ -427,7 +435,7 @@ abstract class Pickler extends SubComponent { * argument of some Annotation */ private def putMods(mods: Modifiers) = if (putEntry(mods)) { // annotations in Modifiers are removed by the typechecker - val Modifiers(flags, privateWithin, Nil) = mods + val Modifiers(_, privateWithin, Nil) = mods putEntry(privateWithin) } @@ -568,7 +576,7 @@ abstract class Pickler extends SubComponent { tag case sym: ClassSymbol => writeSymInfo(sym) - if (sym.thisSym.tpe != sym.tpe) writeRef(sym.typeOfThis) + if (sym.thisSym.tpe_* != sym.tpe_*) writeRef(sym.typeOfThis) CLASSsym case sym: TypeSymbol => writeSymInfo(sym) @@ -609,8 +617,6 @@ abstract class Pickler extends SubComponent { writeRef(restpe); writeRefs(tparams); POLYtpe case ExistentialType(tparams, restpe) => writeRef(restpe); writeRefs(tparams); EXISTENTIALtpe - // case DeBruijnIndex(l, i) => - // writeNat(l); writeNat(i); DEBRUIJNINDEXtpe case c @ Constant(_) => if (c.tag == BooleanTag) writeLong(if (c.booleanValue) 1 else 0) else if (ByteTag <= c.tag && c.tag <= LongTag) writeLong(c.longValue) @@ -993,115 +999,6 @@ abstract class Pickler extends SubComponent { patchNat(startpos + 1, writeIndex - (startpos + 2)) } - /** Print entry for diagnostics */ - def printEntryAtIndex(idx: Int) = printEntry(entries(idx)) - def printEntry(entry: AnyRef) { - def printRef(ref: AnyRef) { - print(index(ref)+ - (if (ref.isInstanceOf[Name]) "("+ref+") " else " ")) - } - def printRefs(refs: List[AnyRef]) { refs foreach printRef } - def printSymInfo(sym: Symbol) { - var posOffset = 0 - printRef(sym.name) - printRef(localizedOwner(sym)) - print(flagsToString(sym.flags & PickledFlags)+" ") - if (sym.hasAccessBoundary) printRef(sym.privateWithin) - printRef(sym.info) - } - def printBody(entry: AnyRef) = entry match { - case name: Name => - print((if (name.isTermName) "TERMname " else "TYPEname ")+name) - case NoSymbol => - print("NONEsym") - case sym: Symbol if !isLocal(sym) => - if (sym.isModuleClass) { - print("EXTMODCLASSref "); printRef(sym.name.toTermName) - } else { - print("EXTref "); printRef(sym.name) - } - if (!sym.owner.isRoot) printRef(sym.owner) - case sym: ClassSymbol => - print("CLASSsym ") - printSymInfo(sym) - if (sym.thisSym.tpe != sym.tpe) printRef(sym.typeOfThis) - case sym: TypeSymbol => - print(if (sym.isAbstractType) "TYPEsym " else "ALIASsym ") - printSymInfo(sym) - case sym: TermSymbol => - print(if (sym.isModule) "MODULEsym " else "VALsym ") - printSymInfo(sym) - if (sym.alias != NoSymbol) printRef(sym.alias) - case NoType => - print("NOtpe") - case NoPrefix => - print("NOPREFIXtpe") - case ThisType(sym) => - print("THIStpe "); printRef(sym) - case SingleType(pre, sym) => - print("SINGLEtpe "); printRef(pre); printRef(sym); - case ConstantType(value) => - print("CONSTANTtpe "); printRef(value); - case TypeRef(pre, sym, args) => - print("TYPEREFtpe "); printRef(pre); printRef(sym); printRefs(args); - case TypeBounds(lo, hi) => - print("TYPEBOUNDStpe "); printRef(lo); printRef(hi); - case tp @ RefinedType(parents, decls) => - print("REFINEDtpe "); printRef(tp.typeSymbol); printRefs(parents); - case ClassInfoType(parents, decls, clazz) => - print("CLASSINFOtpe "); printRef(clazz); printRefs(parents); - case mt @ MethodType(formals, restpe) => - print("METHODtpe"); printRef(restpe); printRefs(formals) - case PolyType(tparams, restpe) => - print("POLYtpe "); printRef(restpe); printRefs(tparams); - case ExistentialType(tparams, restpe) => - print("EXISTENTIALtpe "); printRef(restpe); printRefs(tparams); - print("||| "+entry) - // case DeBruijnIndex(l, i) => - // print("DEBRUIJNINDEXtpe "); print(l+" "+i) - case c @ Constant(_) => - print("LITERAL ") - if (c.tag == BooleanTag) print("Boolean "+(if (c.booleanValue) 1 else 0)) - else if (c.tag == ByteTag) print("Byte "+c.longValue) - else if (c.tag == ShortTag) print("Short "+c.longValue) - else if (c.tag == CharTag) print("Char "+c.longValue) - else if (c.tag == IntTag) print("Int "+c.longValue) - else if (c.tag == LongTag) print("Long "+c.longValue) - else if (c.tag == FloatTag) print("Float "+c.floatValue) - else if (c.tag == DoubleTag) print("Double "+c.doubleValue) - else if (c.tag == StringTag) { print("String "); printRef(newTermName(c.stringValue)) } - else if (c.tag == ClazzTag) { print("Class "); printRef(c.typeValue) } - else if (c.tag == EnumTag) { print("Enum "); printRef(c.symbolValue) } - case AnnotatedType(annots, tp, selfsym) => - if (settings.selfInAnnots.value) { - print("ANNOTATEDWSELFtpe ") - printRef(tp) - printRef(selfsym) - printRefs(annots) - } else { - print("ANNOTATEDtpe ") - printRef(tp) - printRefs(annots) - } - case (target: Symbol, AnnotationInfo(atp, args, Nil)) => - print("SYMANNOT ") - printRef(target) - printRef(atp) - for (c <- args) printRef(c) - case (target: Symbol, children: List[_]) => - print("CHILDREN ") - printRef(target) - for (c <- children) printRef(c.asInstanceOf[Symbol]) - case AnnotationInfo(atp, args, Nil) => - print("ANNOTINFO") - printRef(atp) - for (c <- args) printRef(c) - case _ => - throw new FatalError("bad entry: " + entry + " " + entry.getClass) - } - printBody(entry); println() - } - /** Write byte array */ def writeArray() { assert(writeIndex == 0) diff --git a/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala b/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala index 40189b9444..624db027f1 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala @@ -7,12 +7,8 @@ package scala.tools.nsc package symtab package clr -import java.io.File -import java.util.{Comparator, StringTokenizer} -import scala.util.Sorting import ch.epfl.lamp.compiler.msil._ import scala.collection.{ mutable, immutable } -import scala.reflect.internal.util.{Position, NoPosition} /** * Collects all types from all reference assemblies. @@ -21,7 +17,6 @@ abstract class CLRTypes { val global: Global import global.Symbol - import global.definitions //########################################################################## diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala index 5a0253c18b..f0e49ce500 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala @@ -12,7 +12,6 @@ import ch.epfl.lamp.compiler.msil.{Type => MSILType, Attribute => MSILAttribute, import scala.collection.{ mutable, immutable } import scala.reflect.internal.pickling.UnPickler import ch.epfl.lamp.compiler.msil.Type.TMVarUsage -import scala.language.implicitConversions /** * @author Nikolay Mihaylov @@ -520,12 +519,12 @@ abstract class TypeParser { val delegateParamTypes: List[Type] = List(typClrType); // not ImplicitMethodType, this is for methods with implicit parameters (not implicit methods) val forwardViewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(delegateParamTypes), funType) - val fmsym = createMethod(nme.view_, flags, forwardViewMethodType, null, true); + createMethod(nme.view_, flags, forwardViewMethodType, null, true); // create the backward view: function => delegate val functionParamTypes: List[Type] = List(funType); val backwardViewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(functionParamTypes), typClrType) - val bmsym = createMethod(nme.view_, flags, backwardViewMethodType, null, true); + createMethod(nme.view_, flags, backwardViewMethodType, null, true); } private def createDelegateChainers(typ: MSILType) = { diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index bacd8c39e1..5fbc15f858 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -8,8 +8,6 @@ package transform import symtab._ import Flags._ -import scala.collection.{ mutable, immutable } -import scala.collection.mutable.ListBuffer abstract class AddInterfaces extends InfoTransform { self: Erasure => import global._ // the global environment @@ -94,7 +92,7 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => impl.typeOfThis = iface.typeOfThis impl.thisSym setName iface.thisSym.name } - impl.sourceFile = iface.sourceFile + impl.associatedFile = iface.sourceFile if (inClass) iface.owner.info.decls enter impl @@ -111,7 +109,7 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => def implClass(iface: Symbol): Symbol = { iface.info - implClassMap.getOrElse(iface, atPhase(implClassPhase) { + implClassMap.getOrElse(iface, enteringPhase(implClassPhase) { if (iface.implClass eq NoSymbol) debuglog(s"${iface.fullLocationString} has no implClass yet, creating it now.") else @@ -196,7 +194,7 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => case PolyType(_, restpe) => implType(restpe) } - implSym setInfo implType(beforeErasure(iface.info)) + implSym setInfo implType(enteringErasure(iface.info)) } override def load(clazz: Symbol) { complete(clazz) } @@ -317,10 +315,10 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => // body until now, because the typer knows that Any has no // constructor and won't accept a call to super.init. assert((clazz isSubClass AnyValClass) || clazz.info.parents.isEmpty, clazz) - Block(List(Apply(gen.mkSuperSelect, Nil)), expr) + Block(List(Apply(gen.mkSuperInitCall, Nil)), expr) case Block(stats, expr) => - // needs `hasSymbol` check because `supercall` could be a block (named / default args) + // needs `hasSymbolField` check because `supercall` could be a block (named / default args) val (presuper, supercall :: rest) = stats span (t => t.hasSymbolWhich(_ hasFlag PRESUPER)) treeCopy.Block(tree, presuper ::: (supercall :: mixinConstructorCalls ::: rest), expr) } @@ -352,7 +350,7 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => val mix1 = mix if (mix == tpnme.EMPTY) mix else { - val ps = beforeErasure { + val ps = enteringErasure { sym.info.parents dropWhile (p => p.symbol.name != mix) } assert(!ps.isEmpty, tree); diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 0c9cb31d58..847ca574a9 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -15,6 +15,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { import global._ import definitions._ import CODE._ + import treeInfo.StripCast /** the following two members override abstract members in Transform */ val phaseName: String = "cleanup" @@ -45,7 +46,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { result } private def transformTemplate(tree: Tree) = { - val Template(parents, self, body) = tree + val Template(_, _, body) = tree clearStatics() val newBody = transformTrees(body) val templ = deriveTemplate(tree)(_ => transformTrees(newStaticMembers.toList) ::: newBody) @@ -437,19 +438,31 @@ abstract class CleanUp extends Transform with ast.TreeDSL { * is a value type (int et al.) in which case it must cast to the boxed version * because invoke only returns object and erasure made sure the result is * expected to be an AnyRef. */ - val t: Tree = ad.symbol.tpe match { - case MethodType(mparams, resType) => - assert(params.length == mparams.length, mparams) - - typedPos { - val sym = currentOwner.newValue(mkTerm("qual"), ad.pos) setInfo qual0.tpe - qual = REF(sym) + val t: Tree = { + val (mparams, resType) = ad.symbol.tpe match { + case MethodType(mparams, resType) => + assert(params.length == mparams.length, ((params, mparams))) + (mparams, resType) + case tpe @ OverloadedType(pre, alts) => + unit.warning(ad.pos, s"Overloaded type reached the backend! This is a bug in scalac.\n Symbol: ${ad.symbol}\n Overloads: $tpe\n Arguments: " + ad.args.map(_.tpe)) + alts filter (_.paramss.flatten.size == params.length) map (_.tpe) match { + case mt @ MethodType(mparams, resType) :: Nil => + unit.warning(NoPosition, "Only one overload has the right arity, proceeding with overload " + mt) + (mparams, resType) + case _ => + unit.error(ad.pos, "Cannot resolve overload.") + (Nil, NoType) + } + } + typedPos { + val sym = currentOwner.newValue(mkTerm("qual"), ad.pos) setInfo qual0.tpe + qual = REF(sym) - BLOCK( - VAL(sym) === qual0, - callAsReflective(mparams map (_.tpe), resType) - ) - } + BLOCK( + VAL(sym) === qual0, + callAsReflective(mparams map (_.tpe), resType) + ) + } } /* For testing purposes, the dynamic application's condition @@ -606,14 +619,16 @@ abstract class CleanUp extends Transform with ast.TreeDSL { } transformApply - // This transform replaces Array(Predef.wrapArray(Array(...)), <tag>) - // with just Array(...) - case Apply(appMeth, List(Apply(wrapRefArrayMeth, List(array)), _)) - if (wrapRefArrayMeth.symbol == Predef_wrapRefArray && - appMeth.symbol == ArrayModule_overloadedApply.suchThat { - _.tpe.resultType.dealias.typeSymbol == ObjectClass - }) => - super.transform(array) + // Replaces `Array(Predef.wrapArray(ArrayValue(...).$asInstanceOf[...]), <tag>)` + // with just `ArrayValue(...).$asInstanceOf[...]` + // + // See SI-6611; we must *only* do this for literal vararg arrays. + case Apply(appMeth, List(Apply(wrapRefArrayMeth, List(arg @ StripCast(ArrayValue(_, _)))), _)) + if wrapRefArrayMeth.symbol == Predef_wrapRefArray && appMeth.symbol == ArrayModule_genericApply => + super.transform(arg) + case Apply(appMeth, List(elem0, Apply(wrapArrayMeth, List(rest @ ArrayValue(elemtpt, _))))) + if wrapArrayMeth.symbol == Predef_wrapArray(elemtpt.tpe) && appMeth.symbol == ArrayModule_apply(elemtpt.tpe) => + super.transform(treeCopy.ArrayValue(rest, rest.elemtpt, elem0 :: rest.elems)) case _ => super.transform(tree) diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index 4092d1262a..323c7c7261 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -130,7 +130,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { if (from.name != nme.OUTER || from.tpe.typeSymbol.isPrimitiveValueClass) result else localTyper.typedPos(to.pos) { - IF (from OBJ_EQ NULL) THEN Throw(NullPointerExceptionClass.tpe) ELSE result + IF (from OBJ_EQ NULL) THEN Throw(NewFromConstructor(NPEConstructor)) ELSE result } } @@ -422,7 +422,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { def ensureAccessor(sym: Symbol)(acc: => Symbol) = if (sym.owner == clazz && !sym.isMethod && sym.isPrivate) { // there's an access to a naked field of the enclosing class - var getr = acc + val getr = acc getr makeNotPrivate clazz getr } else { @@ -529,7 +529,8 @@ abstract class Constructors extends Transform with ast.TreeDSL { (pre ::: supercalls, rest) } - var (uptoSuperStats, remainingConstrStats) = splitAtSuper(constrStatBuf.toList) + val (uptoSuperStats, remainingConstrStats0) = splitAtSuper(constrStatBuf.toList) + var remainingConstrStats = remainingConstrStats0 /** XXX This is not corect: remainingConstrStats.nonEmpty excludes too much, * but excluding it includes too much. The constructor sequence being mimicked diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 7b9b13ae1c..ba799f9186 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -172,7 +172,7 @@ abstract class Erasure extends AddInterfaces /** The Java signature of type 'info', for symbol sym. The symbol is used to give the right return * type for constructors. */ - def javaSig(sym0: Symbol, info: Type): Option[String] = beforeErasure { + def javaSig(sym0: Symbol, info: Type): Option[String] = enteringErasure { val isTraitSignature = sym0.enclClass.isTrait def superSig(parents: List[Type]) = { @@ -206,7 +206,7 @@ abstract class Erasure extends AddInterfaces // Anything which could conceivably be a module (i.e. isn't known to be // a type parameter or similar) must go through here or the signature is // likely to end up with Foo<T>.Empty where it needs Foo<T>.Empty$. - def fullNameInSig(sym: Symbol) = "L" + beforeIcode(sym.javaBinaryName) + def fullNameInSig(sym: Symbol) = "L" + enteringIcode(sym.javaBinaryName) def jsig(tp0: Type, existentiallyBound: List[Symbol] = Nil, toplevel: Boolean = false, primitiveOK: Boolean = true): String = { val tp = tp0.dealias @@ -398,7 +398,7 @@ abstract class Erasure extends AddInterfaces val bridgeTarget = mutable.HashMap[Symbol, Symbol]() var bridges = List[Tree]() - val opc = beforeExplicitOuter { + val opc = enteringExplicitOuter { new overridingPairs.Cursor(root) { override def parents = List(root.info.firstParent) override def exclude(sym: Symbol) = !sym.isMethod || sym.isPrivate || super.exclude(sym) @@ -410,7 +410,7 @@ abstract class Erasure extends AddInterfaces val member = opc.overriding val other = opc.overridden //println("bridge? " + member + ":" + member.tpe + member.locationString + " to " + other + ":" + other.tpe + other.locationString)//DEBUG - if (beforeExplicitOuter(!member.isDeferred)) + if (enteringExplicitOuter(!member.isDeferred)) checkPair(member, other) opc.next @@ -440,11 +440,11 @@ abstract class Erasure extends AddInterfaces sm"""bridge generated for member ${fulldef(member)} |which overrides ${fulldef(other)} |clashes with definition of $what; - |both have erased type ${afterPostErasure(bridge.tpe)}""") + |both have erased type ${exitingPostErasure(bridge.tpe)}""") } for (bc <- root.baseClasses) { if (settings.debug.value) - afterPostErasure(println( + exitingPostErasure(println( sm"""check bridge overrides in $bc |${bc.info.nonPrivateDecl(bridge.name)} |${site.memberType(bridge)} @@ -453,13 +453,13 @@ abstract class Erasure extends AddInterfaces def overriddenBy(sym: Symbol) = sym.matchingSymbol(bc, site).alternatives filter (sym => !sym.isBridge) - for (overBridge <- afterPostErasure(overriddenBy(bridge))) { + for (overBridge <- exitingPostErasure(overriddenBy(bridge))) { if (overBridge == member) { clashError("the member itself") } else { val overMembers = overriddenBy(member) if (!overMembers.exists(overMember => - afterPostErasure(overMember.tpe =:= overBridge.tpe))) { + exitingPostErasure(overMember.tpe =:= overBridge.tpe))) { clashError(fulldef(overBridge)) } } @@ -470,7 +470,7 @@ abstract class Erasure extends AddInterfaces def checkPair(member: Symbol, other: Symbol) { val otpe = specialErasure(root)(other.tpe) - val bridgeNeeded = afterErasure ( + val bridgeNeeded = exitingErasure ( !(other.tpe =:= member.tpe) && !(deconstMap(other.tpe) =:= deconstMap(member.tpe)) && { var e = bridgesScope.lookupEntry(member.name) @@ -482,7 +482,7 @@ abstract class Erasure extends AddInterfaces if (!bridgeNeeded) return - val newFlags = (member.flags | BRIDGE) & ~(ACCESSOR | DEFERRED | LAZY | lateDEFERRED) + val newFlags = (member.flags | BRIDGE | ARTIFACT) & ~(ACCESSOR | DEFERRED | LAZY | lateDEFERRED) val bridge = other.cloneSymbolImpl(root, newFlags) setPos root.pos debuglog("generating bridge from %s (%s): %s to %s: %s".format( @@ -497,9 +497,9 @@ abstract class Erasure extends AddInterfaces if (!(member.tpe exists (_.typeSymbol.isDerivedValueClass)) || checkBridgeOverrides(member, other, bridge)) { - afterErasure(root.info.decls enter bridge) + exitingErasure(root.info.decls enter bridge) if (other.owner == root) { - afterErasure(root.info.decls.unlink(other)) + exitingErasure(root.info.decls.unlink(other)) toBeRemoved += other } @@ -508,7 +508,7 @@ abstract class Erasure extends AddInterfaces } } - def makeBridgeDefDef(bridge: Symbol, member: Symbol, other: Symbol) = afterErasure { + def makeBridgeDefDef(bridge: Symbol, member: Symbol, other: Symbol) = exitingErasure { // type checking ensures we can safely call `other`, but unless `member.tpe <:< other.tpe`, // calling `member` is not guaranteed to succeed in general, there's // nothing we can do about this, except for an unapply: when this subtype test fails, @@ -519,7 +519,7 @@ abstract class Erasure extends AddInterfaces def maybeWrap(bridgingCall: Tree): Tree = { val guardExtractor = ( // can't statically know which member is going to be selected, so don't let this depend on member.isSynthetic (member.name == nme.unapply || member.name == nme.unapplySeq) - && !afterErasure((member.tpe <:< other.tpe))) // no static guarantees (TODO: is the subtype test ever true?) + && !exitingErasure((member.tpe <:< other.tpe))) // no static guarantees (TODO: is the subtype test ever true?) import CODE._ val _false = FALSE_typed @@ -724,19 +724,11 @@ abstract class Erasure extends AddInterfaces case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List()) if tree.symbol == Any_asInstanceOf => val qual1 = typedQualifier(qual, NOmode, ObjectClass.tpe) // need to have an expected type, see #3037 - val qualClass = qual1.tpe.typeSymbol -/* - val targClass = targ.tpe.typeSymbol - if (isNumericValueClass(qualClass) && isNumericValueClass(targClass)) - // convert numeric type casts - atPos(tree.pos)(Apply(Select(qual1, "to" + targClass.name), List())) - else -*/ if (isPrimitiveValueType(targ.tpe) || isErasedValueType(targ.tpe)) { val noNullCheckNeeded = targ.tpe match { case ErasedValueType(tref) => - atPhase(currentRun.erasurePhase) { + enteringPhase(currentRun.erasurePhase) { isPrimitiveValueClass(erasedValueClassArg(tref).typeSymbol) } case _ => @@ -744,7 +736,6 @@ abstract class Erasure extends AddInterfaces } if (noNullCheckNeeded) unbox(qual1, targ.tpe) else { - def nullConst = Literal(Constant(null)) setType NullClass.tpe val untyped = // util.trace("new asinstanceof test") { gen.evalOnce(qual1, context.owner, context.unit) { qual => @@ -822,7 +813,7 @@ abstract class Erasure extends AddInterfaces (tree.attachments.get[TypeRefAttachment]: @unchecked) match { case Some(itype) => val tref = itype.tpe - val argPt = atPhase(currentRun.erasurePhase)(erasedValueClassArg(tref)) + val argPt = enteringPhase(currentRun.erasurePhase)(erasedValueClassArg(tref)) log(s"transforming inject $arg -> $tref/$argPt") val result = typed(arg, mode, argPt) log(s"transformed inject $arg -> $tref/$argPt = $result:${result.tpe}") @@ -895,20 +886,20 @@ abstract class Erasure extends AddInterfaces private def checkNoDoubleDefs(root: Symbol) { def doubleDefError(sym1: Symbol, sym2: Symbol) { // the .toString must also be computed at the earlier phase - val tpe1 = afterRefchecks(root.thisType.memberType(sym1)) - val tpe2 = afterRefchecks(root.thisType.memberType(sym2)) + val tpe1 = exitingRefchecks(root.thisType.memberType(sym1)) + val tpe2 = exitingRefchecks(root.thisType.memberType(sym2)) if (!tpe1.isErroneous && !tpe2.isErroneous) unit.error( if (sym1.owner == root) sym1.pos else root.pos, (if (sym1.owner == sym2.owner) "double definition:\n" else if (sym1.owner == root) "name clash between defined and inherited member:\n" else "name clash between inherited members:\n") + - sym1 + ":" + afterRefchecks(tpe1.toString) + + sym1 + ":" + exitingRefchecks(tpe1.toString) + (if (sym1.owner == root) "" else sym1.locationString) + " and\n" + - sym2 + ":" + afterRefchecks(tpe2.toString) + + sym2 + ":" + exitingRefchecks(tpe2.toString) + (if (sym2.owner == root) " at line " + (sym2.pos).line else sym2.locationString) + "\nhave same type" + - (if (afterRefchecks(tpe1 =:= tpe2)) "" else " after erasure: " + afterPostErasure(sym1.tpe))) + (if (exitingRefchecks(tpe1 =:= tpe2)) "" else " after erasure: " + exitingPostErasure(sym1.tpe))) sym1.setInfo(ErrorType) } @@ -918,7 +909,7 @@ abstract class Erasure extends AddInterfaces if (e.sym.isTerm) { var e1 = decls.lookupNextEntry(e) while (e1 ne null) { - if (afterPostErasure(e1.sym.info =:= e.sym.info)) doubleDefError(e.sym, e1.sym) + if (exitingPostErasure(e1.sym.info =:= e.sym.info)) doubleDefError(e.sym, e1.sym) e1 = decls.lookupNextEntry(e1) } } @@ -926,16 +917,17 @@ abstract class Erasure extends AddInterfaces } val opc = new overridingPairs.Cursor(root) { - override def exclude(sym: Symbol): Boolean = - (!sym.isTerm || sym.isPrivate || super.exclude(sym) - // specialized members have no type history before 'specialize', causing double def errors for curried defs - || !sym.hasTypeAt(currentRun.refchecksPhase.id)) + override def exclude(sym: Symbol): Boolean = ( + !sym.isTerm || sym.isPrivate || super.exclude(sym) + // specialized members have no type history before 'specialize', causing double def errors for curried defs + || !sym.hasTypeAt(currentRun.refchecksPhase.id) + ) override def matches(sym1: Symbol, sym2: Symbol): Boolean = - afterPostErasure(sym1.tpe =:= sym2.tpe) + exitingPostErasure(sym1.tpe =:= sym2.tpe) } while (opc.hasNext) { - if (!afterRefchecks( + if (!exitingRefchecks( root.thisType.memberType(opc.overriding) matches root.thisType.memberType(opc.overridden))) { debuglog("" + opc.overriding.locationString + " " + @@ -954,8 +946,8 @@ abstract class Erasure extends AddInterfaces for (member <- root.info.nonPrivateMember(other.name).alternatives) { if (member != other && !(member hasFlag BRIDGE) && - afterErasure(member.tpe =:= other.tpe) && - !afterRefchecks( + exitingErasure(member.tpe =:= other.tpe) && + !exitingRefchecks( root.thisType.memberType(member) matches root.thisType.memberType(other))) { debuglog("" + member.locationString + " " + member.infosString + other.locationString + " " + other.infosString); doubleDefError(member, other) @@ -1051,17 +1043,17 @@ abstract class Erasure extends AddInterfaces Apply(Select(qual, cmpOp), List(gen.mkAttributedQualifier(targ.tpe))) } case RefinedType(parents, decls) if (parents.length >= 2) => - // Optimization: don't generate isInstanceOf tests if the static type - // conforms, because it always succeeds. (Or at least it had better.) - // At this writing the pattern matcher generates some instance tests - // involving intersections where at least one parent is statically known true. - // That needs fixing, but filtering the parents here adds an additional - // level of robustness (in addition to the short term fix.) - val parentTests = parents filterNot (qual.tpe <:< _) - - if (parentTests.isEmpty) Literal(Constant(true)) - else gen.evalOnce(qual, currentOwner, unit) { q => - atPos(tree.pos) { + gen.evalOnce(qual, currentOwner, unit) { q => + // Optimization: don't generate isInstanceOf tests if the static type + // conforms, because it always succeeds. (Or at least it had better.) + // At this writing the pattern matcher generates some instance tests + // involving intersections where at least one parent is statically known true. + // That needs fixing, but filtering the parents here adds an additional + // level of robustness (in addition to the short term fix.) + val parentTests = parents filterNot (qual.tpe <:< _) + + if (parentTests.isEmpty) Literal(Constant(true)) + else atPos(tree.pos) { parentTests map mkIsInstanceOf(q) reduceRight gen.mkAnd } } @@ -1077,6 +1069,7 @@ abstract class Erasure extends AddInterfaces } else if (fn.symbol == Any_isInstanceOf) { preEraseIsInstanceOf } else if (fn.symbol.owner.isRefinementClass && !fn.symbol.isOverridingSymbol) { + // !!! Another spot where we produce overloaded types (see test run/t6301) ApplyDynamic(qualifier, args) setSymbol fn.symbol setPos tree.pos } else if (fn.symbol.isMethodWithExtension && !fn.symbol.tpe.isErroneous) { Apply(gen.mkAttributedRef(extensionMethods.extensionMethod(fn.symbol)), qualifier :: args) @@ -1135,7 +1128,8 @@ abstract class Erasure extends AddInterfaces SelectFromArray(qual, name, erasure(tree.symbol)(qual.tpe)).copyAttrs(fn), args) } - } else if (args.isEmpty && interceptedMethods(fn.symbol)) { + } + else if (args.isEmpty && interceptedMethods(fn.symbol)) { if (fn.symbol == Any_## || fn.symbol == Object_##) { // This is unattractive, but without it we crash here on ().## because after // erasure the ScalaRunTime.hash overload goes from Unit => Int to BoxedUnit => Int. @@ -1147,7 +1141,18 @@ abstract class Erasure extends AddInterfaces case s @ (ShortClass | ByteClass | CharClass) => numericConversion(qual, s) case BooleanClass => If(qual, LIT(true.##), LIT(false.##)) case _ => - global.typer.typed(gen.mkRuntimeCall(nme.hash_, List(qual))) + // Since we are past typer, we need to avoid creating trees carrying + // overloaded types. This logic is custom (and technically incomplete, + // although serviceable) for def hash. What is really needed is for + // the overloading logic presently hidden away in a few different + // places to be properly exposed so we can just call "resolveOverload" + // after typer. Until then: + val alts = ScalaRunTimeModule.info.member(nme.hash_).alternatives + def alt1 = alts find (_.info.paramTypes.head =:= qual.tpe) + def alt2 = ScalaRunTimeModule.info.member(nme.hash_) suchThat (_.info.paramTypes.head.typeSymbol == AnyClass) + val newTree = gen.mkRuntimeCall(nme.hash_, qual :: Nil) setSymbol (alt1 getOrElse alt2) + + global.typer.typed(newTree) } } else if (isPrimitiveValueClass(qual.tpe.typeSymbol)) { // Rewrite 5.getClass to ScalaRunTime.anyValClass(5) @@ -1273,7 +1278,7 @@ abstract class Erasure extends AddInterfaces override def transform(tree: Tree): Tree = { val tree1 = preTransformer.transform(tree) // log("tree after pretransform: "+tree1) - afterErasure { + exitingErasure { val tree2 = mixinTransformer.transform(tree1) // debuglog("tree after addinterfaces: \n" + tree2) diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 1003d417f6..01c22245cb 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -83,12 +83,6 @@ abstract class ExplicitOuter extends InfoTransform } } - /** Issue a migration warning for instance checks which might be on an Array and - * for which the type parameter conforms to Seq, because these answers changed in 2.8. - */ - def isArraySeqTest(lhs: Type, rhs: Type) = - (ArrayClass.tpe <:< lhs.widen) && (rhs.widen matchesPattern SeqClass.tpe) - def outerAccessor(clazz: Symbol): Symbol = { val firstTry = clazz.info.decl(nme.expandedName(nme.OUTER, clazz)) if (firstTry != NoSymbol && firstTry.outerSource == clazz) firstTry @@ -97,7 +91,7 @@ abstract class ExplicitOuter extends InfoTransform def newOuterAccessor(clazz: Symbol) = { val accFlags = SYNTHETIC | ARTIFACT | METHOD | STABLE | ( if (clazz.isTrait) DEFERRED else 0 ) val sym = clazz.newMethod(nme.OUTER, clazz.pos, accFlags) - val restpe = if (clazz.isTrait) clazz.outerClass.tpe else clazz.outerClass.thisType + val restpe = if (clazz.isTrait) clazz.outerClass.tpe_* else clazz.outerClass.thisType sym expandName clazz sym.referenced = clazz @@ -164,16 +158,13 @@ abstract class ExplicitOuter extends InfoTransform var decls1 = decls if (isInner(clazz) && !clazz.isInterface) { decls1 = decls.cloneScope - val outerAcc = clazz.newMethod(nme.OUTER, clazz.pos) // 3 - outerAcc expandName clazz - - decls1 enter newOuterAccessor(clazz) + decls1 enter newOuterAccessor(clazz) // 3 if (hasOuterField(clazz)) //2 decls1 enter newOuterField(clazz) } if (!clazz.isTrait && !parents.isEmpty) { for (mc <- clazz.mixinClasses) { - val mixinOuterAcc: Symbol = afterExplicitOuter(outerAccessor(mc)) + val mixinOuterAcc: Symbol = exitingExplicitOuter(outerAccessor(mc)) if (mixinOuterAcc != NoSymbol) { if (decls1 eq decls) decls1 = decls.cloneScope val newAcc = mixinOuterAcc.cloneSymbol(clazz, mixinOuterAcc.flags & ~DEFERRED) @@ -243,11 +234,6 @@ abstract class ExplicitOuter extends InfoTransform * <blockquote><pre>`base'.$outer$$C1 ... .$outer$$Cn</pre></blockquote> * which refers to the outer instance of class to of * value base. The result is typed but not positioned. - * - * @param base ... - * @param from ... - * @param to ... - * @return ... */ protected def outerPath(base: Tree, from: Symbol, to: Symbol): Tree = { //Console.println("outerPath from "+from+" to "+to+" at "+base+":"+base.tpe) @@ -341,7 +327,7 @@ abstract class ExplicitOuter extends InfoTransform */ def outerAccessorDef: Tree = { val outerAcc = outerAccessor(currentClass) - var rhs: Tree = + val rhs: Tree = if (outerAcc.isDeferred) EmptyTree else This(currentClass) DOT outerField(currentClass) @@ -553,13 +539,6 @@ abstract class ExplicitOuter extends InfoTransform } case _ => - if (settings.Xmigration28.value) tree match { - case TypeApply(fn @ Select(qual, _), args) if fn.symbol == Object_isInstanceOf || fn.symbol == Any_isInstanceOf => - if (isArraySeqTest(qual.tpe, args.head.tpe)) - unit.warning(tree.pos, "An Array will no longer match as Seq[_].") - case _ => () - } - val x = super.transform(tree) if (x.tpe eq null) x else x setType transformInfo(currentOwner, x.tpe) @@ -568,7 +547,7 @@ abstract class ExplicitOuter extends InfoTransform /** The transformation method for whole compilation units */ override def transformUnit(unit: CompilationUnit) { - afterExplicitOuter(super.transformUnit(unit)) + exitingExplicitOuter(super.transformUnit(unit)) } } diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala index 6f3d7932a5..521d732664 100644 --- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -8,9 +8,6 @@ package transform import symtab._ import Flags._ import scala.collection.{ mutable, immutable } -import scala.collection.mutable -import scala.tools.nsc.util.FreshNameCreator -import scala.runtime.ScalaRunTime.{ isAnyVal, isTuple } /** * Perform Step 1 in the inline classes SIP: Creates extension methods for all @@ -23,7 +20,6 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { import global._ // the global environment import definitions._ // standard classes and methods - import typer.{ typed, atOwner } // methods to type trees /** the following two members override abstract members in Transform */ val phaseName: String = "extmethods" @@ -66,7 +62,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { /** Return the extension method that corresponds to given instance method `meth`. */ - def extensionMethod(imeth: Symbol): Symbol = atPhase(currentRun.refchecksPhase) { + def extensionMethod(imeth: Symbol): Symbol = enteringPhase(currentRun.refchecksPhase) { val companionInfo = imeth.owner.companionModule.info val candidates = extensionNames(imeth) map (companionInfo.decl(_)) filter (_.exists) val matching = candidates filter (alt => normalize(alt.tpe, imeth.owner) matches imeth.tpe) @@ -75,32 +71,41 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { matching.head } + /** Recognize a MethodType which represents an extension method. + * + * It may have a curried parameter list with the `$this` alone in the first + * parameter list, in which case that parameter list is dropped. Or, since + * the curried lists disappear during uncurry, it may have a single parameter + * list with `$this` as the first parameter, in which case that parameter is + * removed from the list. + */ + object ExtensionMethodType { + def unapply(tp: Type) = tp match { + case MethodType(thiz :: rest, restpe) if thiz.name == nme.SELF => + Some( if (rest.isEmpty) restpe else MethodType(rest, restpe) ) + case _ => + None + } + } + /** This method removes the `$this` argument from the parameter list a method. * * A method may be a `PolyType`, in which case we tear out the `$this` and the class - * type params from its nested `MethodType`. - * It may be a `MethodType`, either with a curried parameter list in which the first argument - * is a `$this` - we just return the rest of the list. - * This means that the corresponding symbol was generated during `extmethods`. - * - * It may also be a `MethodType` in which the `$this` does not appear in a curried parameter list. - * The curried lists disappear during `uncurry`, and the methods may be duplicated afterwards, - * for instance, during `specialize`. - * In this case, the first argument is `$this` and we just get rid of it. + * type params from its nested `MethodType`. Or it may be a MethodType, as + * described at the ExtensionMethodType extractor. */ private def normalize(stpe: Type, clazz: Symbol): Type = stpe match { case PolyType(tparams, restpe) => - GenPolyType(tparams dropRight clazz.typeParams.length, normalize(restpe.substSym(tparams takeRight clazz.typeParams.length, clazz.typeParams), clazz)) - case MethodType(List(thiz), restpe) if thiz.name == nme.SELF => - restpe - case MethodType(tparams, restpe) => - MethodType(tparams.drop(1), restpe) + // method type parameters, class type parameters + val (mtparams, ctparams) = tparams splitAt (tparams.length - clazz.typeParams.length) + GenPolyType(mtparams, normalize(restpe.substSym(ctparams, clazz.typeParams), clazz)) + case ExtensionMethodType(etpe) => + etpe case _ => stpe } class Extender(unit: CompilationUnit) extends TypingTransformer(unit) { - private val extensionDefs = mutable.Map[Symbol, mutable.ListBuffer[Tree]]() def checkNonCyclic(pos: Position, seen: Set[Symbol], clazz: Symbol): Unit = @@ -111,27 +116,51 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { if (unboxed.isDerivedValueClass) checkNonCyclic(pos, seen + clazz, unboxed) } + /** We will need to clone the info of the original method (which obtains clones + * of the method type parameters), clone the type parameters of the value class, + * and create a new polymethod with the union of all those type parameters, with + * their infos adjusted to be consistent with their new home. Example: + * + * class Foo[+A <: AnyRef](val xs: List[A]) extends AnyVal { + * def baz[B >: A](x: B): List[B] = x :: xs + * // baz has to be transformed into this extension method, where + * // A is cloned from class Foo and B is cloned from method baz: + * // def extension$baz[B >: A <: Any, A >: Nothing <: AnyRef]($this: Foo[A])(x: B): List[B] + * } + * + * TODO: factor out the logic for consolidating type parameters from a class + * and a method for re-use elsewhere, because nobody will get this right without + * some higher level facilities. + */ def extensionMethInfo(extensionMeth: Symbol, origInfo: Type, clazz: Symbol): Type = { - // No variance for method type parameters - var newTypeParams = cloneSymbolsAtOwner(clazz.typeParams, extensionMeth) map (_ resetFlag COVARIANT | CONTRAVARIANT) - val thisParamType = appliedType(clazz.typeConstructor, newTypeParams map (_.tpeHK)) - val thisParam = extensionMeth.newValueParameter(nme.SELF, extensionMeth.pos) setInfo thisParamType - def transform(clonedType: Type): Type = clonedType match { - case MethodType(params, restpe) => - // I assume it was a bug that this was dropping params... [Martin]: No, it wasn't; it's curried. - MethodType(List(thisParam), clonedType) - case NullaryMethodType(restpe) => - MethodType(List(thisParam), restpe) - } - val GenPolyType(tparams, restpe) = origInfo cloneInfo extensionMeth - GenPolyType(tparams ::: newTypeParams, transform(restpe) substSym (clazz.typeParams, newTypeParams)) - } + val GenPolyType(tparamsFromMethod, methodResult) = origInfo cloneInfo extensionMeth + // Start with the class type parameters - clones will be method type parameters + // so must drop their variance. + val tparamsFromClass = cloneSymbolsAtOwner(clazz.typeParams, extensionMeth) map (_ resetFlag COVARIANT | CONTRAVARIANT) + def fix(tp: Type) = tp.substSym(clazz.typeParams, tparamsFromClass) - private def allParams(tpe: Type): List[Symbol] = tpe match { - case MethodType(params, res) => params ::: allParams(res) - case _ => List() + val thisParamType = appliedType(clazz, tparamsFromClass map (_.tpeHK): _*) + val thisParam = extensionMeth.newValueParameter(nme.SELF, extensionMeth.pos) setInfo thisParamType + val resultType = MethodType(List(thisParam), dropNullaryMethod(methodResult)) + + // We can't substitute symbols on the entire polytype because we + // need to modify the bounds of the cloned type parameters, but we + // don't want to substitute for the cloned type parameters themselves. + val tparams = tparamsFromMethod ::: tparamsFromClass + GenPolyType(tparams map (_ modifyInfo fix), fix(resultType)) + + // For reference, calling fix on the GenPolyType plays out like this: + // error: scala.reflect.internal.Types$TypeError: type arguments [B#7344,A#6966] + // do not conform to method extension$baz#16148's type parameter bounds + // + // And the difference is visible here. See how B is bounded from below by A#16149 + // in both cases, but in the failing case, the other type parameter has turned into + // a different A. (What is that A? It is a clone of the original A created in + // SubstMap during the call to substSym, but I am not clear on all the particulars.) + // + // bad: [B#16154 >: A#16149, A#16155 <: AnyRef#2189]($this#16156: Foo#6965[A#16155])(x#16157: B#16154)List#2457[B#16154] + // good: [B#16151 >: A#16149, A#16149 <: AnyRef#2189]($this#16150: Foo#6965[A#16149])(x#16153: B#16151)List#2457[B#16151] } - override def transform(tree: Tree): Tree = { tree match { case Template(_, _, _) => @@ -146,37 +175,56 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { super.transform(tree) } else tree case DefDef(_, _, tparams, vparamss, _, rhs) if tree.symbol.isMethodWithExtension => - val companion = currentOwner.companionModule - val origMeth = tree.symbol - val extensionName = extensionNames(origMeth).head - val extensionMeth = companion.moduleClass.newMethod(extensionName, origMeth.pos, origMeth.flags & ~OVERRIDE & ~PROTECTED | FINAL) - .setAnnotations(origMeth.annotations) - companion.info.decls.enter(extensionMeth) - val newInfo = extensionMethInfo(extensionMeth, origMeth.info, currentOwner) + val origMeth = tree.symbol + val origThis = currentOwner + val origTpeParams = tparams.map(_.symbol) ::: origThis.typeParams // method type params ++ class type params + val origParams = vparamss.flatten map (_.symbol) + val companion = origThis.companionModule + + def makeExtensionMethodSymbol = { + val extensionName = extensionNames(origMeth).head + val extensionMeth = ( + companion.moduleClass.newMethod(extensionName, origMeth.pos, origMeth.flags & ~OVERRIDE & ~PROTECTED | FINAL) + setAnnotations origMeth.annotations + ) + companion.info.decls.enter(extensionMeth) + } + + val extensionMeth = makeExtensionMethodSymbol + val newInfo = extensionMethInfo(extensionMeth, origMeth.info, origThis) extensionMeth setInfo newInfo - log("Value class %s spawns extension method.\n Old: %s\n New: %s".format( - currentOwner, - origMeth.defString, - extensionMeth.defString)) // extensionMeth.defStringSeenAs(origInfo - - def thisParamRef = gen.mkAttributedIdent(extensionMeth.info.params.head setPos extensionMeth.pos) - val GenPolyType(extensionTpeParams, extensionMono) = extensionMeth.info - val origTpeParams = (tparams map (_.symbol)) ::: currentOwner.typeParams - val extensionBody = rhs + + log(s"Value class $origThis spawns extension method.\n Old: ${origMeth.defString}\n New: ${extensionMeth.defString}") + + val GenPolyType(extensionTpeParams, MethodType(thiz :: Nil, extensionMono)) = newInfo + val extensionParams = allParameters(extensionMono) + val extensionThis = gen.mkAttributedIdent(thiz setPos extensionMeth.pos) + + val extensionBody = ( + rhs .substituteSymbols(origTpeParams, extensionTpeParams) - .substituteSymbols(vparamss.flatten map (_.symbol), allParams(extensionMono).tail) - .substituteThis(currentOwner, thisParamRef) - .changeOwner((origMeth, extensionMeth)) - extensionDefs(companion) += atPos(tree.pos) { DefDef(extensionMeth, extensionBody) } - val extensionCallPrefix = Apply( - gen.mkTypeApply(gen.mkAttributedRef(companion), extensionMeth, origTpeParams map (_.tpeHK)), - List(This(currentOwner))) - val extensionCall = atOwner(origMeth) { - localTyper.typedPos(rhs.pos) { - gen.mkForwarder(extensionCallPrefix, mmap(vparamss)(_.symbol)) - } - } - deriveDefDef(tree)(_ => extensionCall) + .substituteSymbols(origParams, extensionParams) + .substituteThis(origThis, extensionThis) + .changeOwner(origMeth -> extensionMeth) + ) + + // Record the extension method ( FIXME: because... ? ) + extensionDefs(companion) += atPos(tree.pos)(DefDef(extensionMeth, extensionBody)) + + // These three lines are assembling Foo.bar$extension[T1, T2, ...]($this) + // which leaves the actual argument application for extensionCall. + val sel = Select(gen.mkAttributedRef(companion), extensionMeth) + val targs = origTpeParams map (_.tpeHK) + val callPrefix = gen.mkMethodCall(sel, targs, This(origThis) :: Nil) + + // Apply all the argument lists. + deriveDefDef(tree)(_ => + atOwner(origMeth)( + localTyper.typedPos(rhs.pos)( + gen.mkForwarder(callPrefix, mmap(vparamss)(_.symbol)) + ) + ) + ) case _ => super.transform(tree) } diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala index cd26f95958..a52dadb134 100644 --- a/src/compiler/scala/tools/nsc/transform/Flatten.scala +++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala @@ -8,28 +8,22 @@ package transform import symtab._ import Flags._ -import scala.collection.{ mutable, immutable } import scala.collection.mutable.ListBuffer abstract class Flatten extends InfoTransform { import global._ - import definitions._ /** the following two members override abstract members in Transform */ val phaseName: String = "flatten" - /** Updates the owning scope with the given symbol; returns the old symbol. + /** Updates the owning scope with the given symbol, unlinking any others. */ - private def replaceSymbolInCurrentScope(sym: Symbol): Symbol = afterFlatten { + private def replaceSymbolInCurrentScope(sym: Symbol): Unit = exitingFlatten { val scope = sym.owner.info.decls - val old = scope lookup sym.name andAlso scope.unlink + val old = (scope lookupUnshadowedEntries sym.name).toList + old foreach (scope unlink _) scope enter sym - - if (old eq NoSymbol) - log(s"lifted ${sym.fullLocationString}") - else - log(s"lifted ${sym.fullLocationString} after unlinking existing $old from scope.") - + log(s"lifted ${sym.fullLocationString}" + ( if (old.isEmpty) "" else " after unlinking $old from scope." )) old } @@ -53,7 +47,7 @@ abstract class Flatten extends InfoTransform { clazz.isClass && !clazz.isPackageClass && { // Cannot flatten here: class A[T] { object B } // was "at erasurePhase.prev" - beforeErasure(clazz.typeParams.isEmpty) + enteringErasure(clazz.typeParams.isEmpty) } } @@ -67,11 +61,11 @@ abstract class Flatten extends InfoTransform { val decls1 = scopeTransform(clazz) { val decls1 = newScope if (clazz.isPackageClass) { - afterFlatten { decls foreach (decls1 enter _) } + exitingFlatten { decls foreach (decls1 enter _) } } else { val oldowner = clazz.owner - afterFlatten { oldowner.info } + exitingFlatten { oldowner.info } parents1 = parents mapConserve (this) for (sym <- decls) { @@ -123,7 +117,7 @@ abstract class Flatten extends InfoTransform { liftedDefs(sym.enclosingTopLevelClass.owner) += tree EmptyTree case Select(qual, name) if (sym.isStaticModule && !sym.owner.isPackageClass) => - afterFlatten(atPos(tree.pos)(gen.mkAttributedRef(sym))) + exitingFlatten(atPos(tree.pos)(gen.mkAttributedRef(sym))) case _ => tree } diff --git a/src/compiler/scala/tools/nsc/transform/InfoTransform.scala b/src/compiler/scala/tools/nsc/transform/InfoTransform.scala index b6dbacaa29..dc321e26ca 100644 --- a/src/compiler/scala/tools/nsc/transform/InfoTransform.scala +++ b/src/compiler/scala/tools/nsc/transform/InfoTransform.scala @@ -10,11 +10,11 @@ package transform * An InfoTransform contains a compiler phase that transforms trees and symbol infos -- making sure they stay consistent. * The symbol info is transformed assuming it is consistent right before this phase. * The info transformation is triggered by Symbol::rawInfo, which caches the results in the symbol's type history. - * This way sym.info (during an atPhase(p)) can look up what the symbol's info should look like at the beginning of phase p. + * This way sym.info (during an enteringPhase(p)) can look up what the symbol's info should look like at the beginning of phase p. * (If the transformed info had not been stored yet, rawInfo will compute the info by composing the info-transformers * of the most recent phase before p, up to the transformer of the phase right before p.) * - * Concretely, atPhase(p) { sym.info } yields the info *before* phase p has transformed it. Imagine you're a phase and it all makes sense. + * Concretely, enteringPhase(p) { sym.info } yields the info *before* phase p has transformed it. Imagine you're a phase and it all makes sense. */ trait InfoTransform extends Transform { import global.{Symbol, Type, InfoTransformer, infoTransformers} diff --git a/src/compiler/scala/tools/nsc/transform/InlineErasure.scala b/src/compiler/scala/tools/nsc/transform/InlineErasure.scala index 0af3cf732f..83dbc23014 100644 --- a/src/compiler/scala/tools/nsc/transform/InlineErasure.scala +++ b/src/compiler/scala/tools/nsc/transform/InlineErasure.scala @@ -1,9 +1,11 @@ package scala.tools.nsc package transform -trait InlineErasure { self: Erasure => - +trait InlineErasure { + self: Erasure => + +/** import global._ import definitions._ - -}
\ No newline at end of file + **/ +} diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala index 21213cf9d9..481228fb3d 100644 --- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala +++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala @@ -278,7 +278,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD bmps(n) else { val sym = meth.newVariable(nme.newBitmapName(nme.BITMAP_NORMAL, n), meth.pos).setInfo(ByteClass.tpe) - beforeTyper { + enteringTyper { sym addAnnotation VolatileAttr } diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 64bb98e2c5..ac1cdd1f46 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -68,7 +68,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { * maps all other types to themselves. */ private def toInterface(tp: Type): Type = - beforeMixin(tp.typeSymbol.toInterface).tpe + enteringMixin(tp.typeSymbol.toInterface).tpe private def isFieldWithBitmap(field: Symbol) = { field.info // ensure that nested objects are transformed @@ -102,7 +102,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { private val toInterfaceMap = new TypeMap { def apply(tp: Type): Type = mapOver( tp match { case TypeRef(pre, sym, args) if sym.isImplClass => - typeRef(pre, beforeMixin(sym.toInterface), args) + typeRef(pre, enteringMixin(sym.toInterface), args) case _ => tp }) } @@ -119,7 +119,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { * @param mixinClass The mixin class that produced the superaccessor */ private def rebindSuper(base: Symbol, member: Symbol, mixinClass: Symbol): Symbol = - afterPickler { + exitingPickler { var bcs = base.info.baseClasses.dropWhile(mixinClass != _).tail var sym: Symbol = NoSymbol debuglog("starting rebindsuper " + base + " " + member + ":" + member.tpe + @@ -165,7 +165,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { addMember(clazz, cloneBeforeErasure(mixinClass, mixinMember, clazz)) def cloneBeforeErasure(mixinClass: Symbol, mixinMember: Symbol, clazz: Symbol): Symbol = { - val newSym = beforeErasure { + val newSym = enteringErasure { // since we used `mixinMember` from the interface that represents the trait that's // being mixed in, have to instantiate the interface type params (that may occur in mixinMember's // info) as they are seen from the class. We can't use the member that we get from the @@ -197,9 +197,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { * - lazy fields don't get a setter. */ def addLateInterfaceMembers(clazz: Symbol) { - def makeConcrete(member: Symbol) = - member setPos clazz.pos resetFlag (DEFERRED | lateDEFERRED) - if (treatedClassInfos(clazz) != clazz.info) { treatedClassInfos(clazz) = clazz.info assert(phase == currentRun.mixinPhase, phase) @@ -292,7 +289,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { for (mixinMember <- mixinClass.info.decls) { if (isConcreteAccessor(mixinMember)) { if (isOverriddenAccessor(mixinMember, clazz.info.baseClasses)) - debugwarn("!!! is overridden val: "+mixinMember.fullLocationString) + devWarning(s"Overridden concrete accessor: ${mixinMember.fullLocationString}") else { // mixin field accessors val mixedInAccessor = cloneAndAddMixinMember(mixinClass, mixinMember) @@ -311,12 +308,12 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { // mixinMember is a value of type unit. No field needed ; case _ => // otherwise mixin a field as well - // atPhase: the private field is moved to the implementation class by erasure, + // enteringPhase: the private field is moved to the implementation class by erasure, // so it can no longer be found in the mixinMember's owner (the trait) - val accessed = beforePickler(mixinMember.accessed) + val accessed = enteringPickler(mixinMember.accessed) // #3857, need to retain info before erasure when cloning (since cloning only // carries over the current entry in the type history) - val sym = beforeErasure { + val sym = enteringErasure { // so we have a type history entry before erasure clazz.newValue(nme.getterToLocal(mixinMember.name), mixinMember.pos).setInfo(mixinMember.tpe.resultType) } @@ -380,14 +377,14 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { var parents1 = parents var decls1 = decls if (!clazz.isPackageClass) { - afterMixin(clazz.owner.info) + exitingMixin(clazz.owner.info) if (clazz.isImplClass) { clazz setFlag lateMODULE var sourceModule = clazz.owner.info.decls.lookup(sym.name.toTermName) if (sourceModule != NoSymbol) { sourceModule setPos sym.pos if (sourceModule.flags != MODULE) { - log("!!! Directly setting sourceModule flags from %s to MODULE".format(flagsToString(sourceModule.flags))) + log("!!! Directly setting sourceModule flags from %s to MODULE".format(sourceModule.flagString)) sourceModule.flags = MODULE } } @@ -408,7 +405,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { parents1 = parents.head :: (parents.tail map toInterface) } } - //decls1 = atPhase(phase.next)(newScopeWith(decls1.toList: _*))//debug + //decls1 = enteringPhase(phase.next)(newScopeWith(decls1.toList: _*))//debug if ((parents1 eq parents) && (decls1 eq decls)) tp else ClassInfoType(parents1, decls1, clazz) @@ -438,7 +435,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { tree match { case Assign(lhs, rhs) => traverse(rhs) // assignments don't count case _ => - if (tree.hasSymbol && tree.symbol != NoSymbol) { + if (tree.hasSymbolField && tree.symbol != NoSymbol) { val sym = tree.symbol if ((sym.hasAccessorFlag || (sym.isTerm && !sym.isMethod)) && sym.isPrivate @@ -525,7 +522,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { tree match { case Template(parents, self, body) => localTyper = erasure.newTyper(rootContext.make(tree, currentOwner)) - afterMixin(currentOwner.owner.info)//todo: needed? + exitingMixin(currentOwner.owner.info)//todo: needed? if (!currentOwner.isTrait && !isPrimitiveValueClass(currentOwner)) addMixedinMembers(currentOwner, unit) @@ -544,7 +541,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { else EmptyTree } else { - if (currentOwner.isTrait && sym.isSetter && !beforePickler(sym.isDeferred)) { + if (currentOwner.isTrait && sym.isSetter && !enteringPickler(sym.isDeferred)) { sym.addAnnotation(TraitSetterAnnotationClass) } tree @@ -591,8 +588,8 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { tree } - /** Create a static reference to given symbol <code>sym</code> of the - * form <code>M.sym</code> where M is the symbol's implementation module. + /** Create a static reference to given symbol `sym` of the + * form `M.sym` where M is the symbol's implementation module. */ private def staticRef(sym: Symbol): Tree = { sym.owner.info //todo: needed? @@ -674,8 +671,8 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { def addValDef(sym: Symbol, rhs: Tree = EmptyTree) = addDef(position(sym), ValDef(sym, rhs)) /** Add `newdefs` to `stats`, removing any abstract method definitions - * in <code>stats</code> that are matched by some symbol defined in - * <code>newDefs</code>. + * in `stats` that are matched by some symbol defined in + * `newDefs`. */ def add(stats: List[Tree], newDefs: List[Tree]) = { val newSyms = newDefs map (_.symbol) @@ -703,7 +700,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { val rhs0 = (Super(clazz, tpnme.EMPTY) DOT stat.symbol.alias)(vparams map (v => Ident(v.symbol)): _*) val rhs1 = localTyped(stat.pos, rhs0, stat.symbol.tpe.resultType) - deriveDefDef(stat)(_ => beforeMixin(transform(rhs1))) + deriveDefDef(stat)(_ => enteringMixin(transform(rhs1))) case _ => stat } @@ -722,7 +719,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { def createBitmap: Symbol = { val bitmapKind = bitmapKindForCategory(category) val sym = clazz0.newVariable(bitmapName, clazz0.pos) setInfo bitmapKind.tpe - beforeTyper(sym addAnnotation VolatileAttr) + enteringTyper(sym addAnnotation VolatileAttr) category match { case nme.BITMAP_TRANSIENT | nme.BITMAP_CHECKINIT_TRANSIENT => sym addAnnotation TransientAttr @@ -804,7 +801,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { */ class TreeSymSubstituterWithCopying(from: List[Symbol], to: List[Symbol]) extends TreeSymSubstituter(from, to) { override def transform(tree: Tree): Tree = - if (tree.hasSymbol && from.contains(tree.symbol)) + if (tree.hasSymbolField && from.contains(tree.symbol)) super.transform(tree.duplicate) else super.transform(tree.duplicate) @@ -868,7 +865,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { rhs match { case Block(List(assign), returnTree) => val Assign(moduleVarRef, _) = assign - val cond = Apply(Select(moduleVarRef, nme.eq), List(NULL)) + val cond = Apply(Select(moduleVarRef, Object_eq), List(NULL)) mkFastPathBody(clazz, moduleSym, cond, List(assign), List(NULL), returnTree, attrThis, args) case _ => assert(false, "Invalid getter " + rhs + " for module in class " + clazz) @@ -884,7 +881,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { val result = IF (mkTest(clazz, mask, bitmapSym, false, kind)) . THEN (retVal) . - ELSE (THROW(UninitializedErrorClass, LIT(msg))) + ELSE (Throw(NewFromConstructor(UninitializedFieldConstructor, LIT(msg)))) typedPos(pos)(BLOCK(result, retVal)) } @@ -980,12 +977,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { def addInitBits(clazz: Symbol, rhs: Tree): Tree = new AddInitBitsTransformer(clazz) transform rhs - def isCheckInitField(field: Symbol) = - needsInitFlag(field) && !field.isDeferred - - def superClassesToCheck(clazz: Symbol) = - clazz.ancestors filterNot (_ hasFlag TRAIT | JAVA) - // begin addNewDefs /** Fill the map from fields to offset numbers. @@ -1153,9 +1144,9 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { qual case Apply(Select(qual, _), args) => - /** Changes <code>qual.m(args)</code> where m refers to an implementation + /** Changes `qual.m(args)` where m refers to an implementation * class method to Q.m(S, args) where Q is the implementation module of - * <code>m</code> and S is the self parameter for the call, which + * `m` and S is the self parameter for the call, which * is determined as follows: * - if qual != super, qual itself * - if qual == super, and we are in an implementation class, @@ -1166,7 +1157,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { def implSym = implClass(sym.owner).info.member(sym.name) assert(target ne NoSymbol, List(sym + ":", sym.tpe, sym.owner, implClass(sym.owner), implSym, - beforePrevPhase(implSym.tpe), phase) mkString " " + enteringPrevPhase(implSym.tpe), phase) mkString " " ) typedPos(tree.pos)(Apply(staticRef(target), transformSuper(qual) :: args)) } @@ -1195,7 +1186,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { typedPos(tree.pos)((transformSuper(qual) DOT sym1)()) } else { - staticCall(beforePrevPhase(sym.overridingSymbol(implClass(sym.owner)))) + staticCall(enteringPrevPhase(sym.overridingSymbol(implClass(sym.owner)))) } } else { @@ -1213,7 +1204,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { tree case Select(qual, name) if sym.owner.isImplClass && !isStaticOnly(sym) => - assert(!sym.isMethod, "no method allowed here: %s%s %s".format(sym, sym.isImplOnly, flagsToString(sym.flags))) + assert(!sym.isMethod, "no method allowed here: %s%s %s".format(sym, sym.isImplOnly, sym.flagString)) // refer to fields in some implementation class via an abstract // getter in the interface. val iface = toInterface(sym.owner.tpe).typeSymbol @@ -1245,7 +1236,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { val tree1 = super.transform(preTransform(tree)) // localTyper needed when not flattening inner classes. parts after an // inner class will otherwise be typechecked with a wrong scope - try afterMixin(postTransform(tree1)) + try exitingMixin(postTransform(tree1)) finally localTyper = saved } } diff --git a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala index 67be81bd3c..28e6e3be26 100644 --- a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala +++ b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala @@ -31,11 +31,11 @@ abstract class OverridingPairs { private val self = base.thisType /** Symbols to exclude: Here these are constructors, private locals, - * and bridges. But it may be refined in subclasses. + * and hidden symbols, including bridges. But it may be refined in subclasses. * */ protected def exclude(sym: Symbol): Boolean = - sym.isConstructor || sym.isPrivateLocal || sym.hasFlag(BRIDGE) + sym.isConstructor || sym.isPrivateLocal || sym.isArtifact /** The parents of base (may also be refined). */ diff --git a/src/compiler/scala/tools/nsc/transform/PostErasure.scala b/src/compiler/scala/tools/nsc/transform/PostErasure.scala index 3ef32caa2c..a8dc47046b 100644 --- a/src/compiler/scala/tools/nsc/transform/PostErasure.scala +++ b/src/compiler/scala/tools/nsc/transform/PostErasure.scala @@ -24,7 +24,7 @@ trait PostErasure extends InfoTransform with TypingTransformers { case ConstantType(Constant(tp: Type)) => ConstantType(Constant(apply(tp))) case ErasedValueType(tref) => - atPhase(currentRun.erasurePhase)(erasure.erasedValueClassArg(tref)) + enteringPhase(currentRun.erasurePhase)(erasure.erasedValueClassArg(tref)) case _ => mapOver(tp) } } @@ -39,7 +39,7 @@ trait PostErasure extends InfoTransform with TypingTransformers { Apply(sel @ Select( Apply(Select(New(tpt), nme.CONSTRUCTOR), List(arg)), acc), List()) - if atPhase(currentRun.erasurePhase) { + if enteringPhase(currentRun.erasurePhase) { tpt.tpe.typeSymbol.isDerivedValueClass && sel.symbol == tpt.tpe.typeSymbol.derivedValueClassUnbox } => @@ -50,7 +50,7 @@ trait PostErasure extends InfoTransform with TypingTransformers { Apply(Select(New(tpt1), nme.CONSTRUCTOR), List(arg1)), cmp), List(Apply(Select(New(tpt2), nme.CONSTRUCTOR), List(arg2)))) - if atPhase(currentRun.erasurePhase) { + if enteringPhase(currentRun.erasurePhase) { tpt1.tpe.typeSymbol.isDerivedValueClass && (sel.symbol == Object_== || sel.symbol == Object_!=) && tpt2.tpe.typeSymbol == tpt1.tpe.typeSymbol diff --git a/src/compiler/scala/tools/nsc/transform/SampleTransform.scala b/src/compiler/scala/tools/nsc/transform/SampleTransform.scala index 44d8860916..cffb483072 100644 --- a/src/compiler/scala/tools/nsc/transform/SampleTransform.scala +++ b/src/compiler/scala/tools/nsc/transform/SampleTransform.scala @@ -11,9 +11,8 @@ package transform abstract class SampleTransform extends Transform { // inherits abstract value `global` and class `Phase` from Transform - import global._ // the global environment - import definitions._ // standard classes and methods - import typer.{typed, atOwner} // methods to type trees + import global._ // the global environment + import typer.typed // method to type trees /** the following two members override abstract members in Transform */ val phaseName: String = "sample-phase" diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 2f79472cfb..2574644727 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -101,7 +101,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { /** Concrete methods that use a specialized type, or override such methods. */ private val concreteSpecMethods = perRunCaches.newWeakSet[Symbol]() - private def specializedTypes(tps: List[Symbol]) = tps filter (_.isSpecialized) private def specializedOn(sym: Symbol): List[Symbol] = { sym getAnnotation SpecializedClass match { case Some(AnnotationInfo(_, Nil, _)) => specializableTypes.map(_.typeSymbol) @@ -119,6 +118,22 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } } + @annotation.tailrec private def findSymbol[T](candidates: List[T], f: T => Symbol): Symbol = { + if (candidates.isEmpty) NoSymbol + else f(candidates.head) match { + case NoSymbol => findSymbol(candidates.tail, f) + case sym => sym + } + } + private def hasNewParents(tree: Tree) = { + val parents = tree.symbol.info.parents + val prev = enteringPrevPhase(tree.symbol.info.parents) + (parents != prev) && { + debuglog(s"$tree parents changed from: $prev to: $parents") + true + } + } + // If we replace `isBoundedGeneric` with (tp <:< AnyRefClass.tpe), // then pos/spec-List.scala fails - why? Does this kind of check fail // for similar reasons? Does `sym.isAbstractType` make a difference? @@ -169,15 +184,16 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } } - /** Returns the generic class that was specialized to 'sClass', or - * 'sClass' itself if sClass is not a specialized subclass. - */ - def genericClass(sClass: Symbol): Symbol = - if (sClass.isSpecialized) sClass.superClass - else sClass - case class Overload(sym: Symbol, env: TypeEnv) { override def toString = "specialized overload " + sym + " in " + env + def matchesSym(sym1: Symbol) = sym.info =:= sym1.info + def matchesEnv(env1: TypeEnv) = TypeEnv.includes(env, env1) + } + private def newOverload(method: Symbol, specializedMethod: Symbol, env: TypeEnv) = { + assert(!specializedMethod.isOverloaded, specializedMethod.defString) + val om = Overload(specializedMethod, env) + overloads(method) ::= om + om } /** Just to mark uncheckable */ @@ -199,8 +215,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * type bounds of other @specialized type parameters (and not in its result type). */ def degenerate = false - - def isAccessor = false } /** Symbol is a special overloaded method of 'original', in the environment env. */ @@ -218,11 +232,14 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { def target = t } - /** Symbol is a specialized accessor for the `target` field. */ - case class SpecializedAccessor(target: Symbol) extends SpecializedInfo { - override def isAccessor = true + /** Symbol is a special overload of the super accessor. */ + case class SpecialSuperAccessor(t: Symbol) extends SpecializedInfo { + def target = t } + /** Symbol is a specialized accessor for the `target` field. */ + case class SpecializedAccessor(target: Symbol) extends SpecializedInfo { } + /** Symbol is a specialized method whose body should be the target's method body. */ case class Implementation(target: Symbol) extends SpecializedInfo @@ -260,9 +277,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { def specializedParams(sym: Symbol): List[Symbol] = sym.info.typeParams filter (_.isSpecialized) - def splitParams(tps: List[Symbol]) = - tps partition (_.isSpecialized) - /** Given an original class symbol and a list of types its type parameters are instantiated at * returns a list of type parameters that should remain in the TypeRef when instantiating a * specialized type. @@ -289,10 +303,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } } - /** Return the specialized overload of sym in the given env, if any. */ - def overload(sym: Symbol, env: TypeEnv) = - overloads(sym).find(ov => TypeEnv.includes(ov.env, env)) - /** Return the specialized name of 'sym' in the given environment. It * guarantees the same result regardless of the map order by sorting * type variables alphabetically. @@ -397,7 +407,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { tpes foreach (tp => buf ++= specializedTypeVars(tp)) buf.result } - def specializedTypeVars(sym: Symbol): immutable.Set[Symbol] = beforeTyper(specializedTypeVars(sym.info)) + def specializedTypeVars(sym: Symbol): immutable.Set[Symbol] = enteringTyper(specializedTypeVars(sym.info)) /** Return the set of @specialized type variables mentioned by the given type. * It only counts type variables that appear: @@ -521,7 +531,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { def cloneInSpecializedClass(member: Symbol, flagFn: Long => Long, newName: Name = null) = member.cloneSymbol(sClass, flagFn(member.flags | SPECIALIZED), newName) - sClass.sourceFile = clazz.sourceFile + sClass.associatedFile = clazz.sourceFile currentRun.symSource(sClass) = clazz.sourceFile // needed later on by mixin val env = mapAnyRefsInSpecSym(env0, clazz, sClass) @@ -533,7 +543,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { var newClassTParams: List[Symbol] = Nil // unspecialized type parameters of 'specializedClass' (cloned) // has to be a val in order to be computed early. It is later called - // within 'atPhase(next)', which would lead to an infinite cycle otherwise + // within 'enteringPhase(next)', which would lead to an infinite cycle otherwise val specializedInfoType: Type = { oldClassTParams = survivingParams(clazz.info.typeParams, env) newClassTParams = produceTypeParameters(oldClassTParams, sClass, env) map subst(env) @@ -553,7 +563,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { var res: List[Type] = Nil // log(specializedClass + ": seeking specialized parents of class with parents: " + parents.map(_.typeSymbol)) for (p <- parents) { - val stp = afterSpecialize(specializedType(p)) + val stp = exitingSpecialize(specializedType(p)) if (stp != p) if (p.typeSymbol.isTrait) res ::= stp else if (currentRun.compiles(clazz)) @@ -563,7 +573,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { res } - var parents = List(applyContext(beforeTyper(clazz.tpe))) + var parents = List(applyContext(enteringTyper(clazz.tpe_*))) // log("!!! Parents: " + parents + ", sym: " + parents.map(_.typeSymbol)) if (parents.head.typeSymbol.isTrait) parents = parents.head.parents.head :: parents @@ -585,7 +595,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { GenPolyType(newClassTParams, ClassInfoType(parents ::: extraSpecializedMixins, decls1, sClass)) } - afterSpecialize(sClass setInfo specializedInfoType) + exitingSpecialize(sClass setInfo specializedInfoType) val fullEnv = outerEnv ++ env /** Enter 'sym' in the scope of the current specialized class. It's type is @@ -628,7 +638,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { info(om) = if (original.isDeferred) Forward(original) else Implementation(original) typeEnv(om) = env ++ typeEnv(m) // add the environment for any method tparams - overloads(specMember) ::= Overload(om, typeEnv(om)) + newOverload(specMember, om, typeEnv(om)) enterMember(om) } @@ -773,7 +783,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { if (existing != NoSymbol) clazz.owner.info.decls.unlink(existing) - afterSpecialize(clazz.owner.info.decls enter spc) //!!! assumes fully specialized classes + exitingSpecialize(clazz.owner.info.decls enter spc) //!!! assumes fully specialized classes } if (subclasses.nonEmpty) clazz.resetFlag(FINAL) cleanAnyRefSpecCache(clazz, decls1) @@ -791,7 +801,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ private def normalizeMember(owner: Symbol, sym: Symbol, outerEnv: TypeEnv): List[Symbol] = { sym :: ( - if (!sym.isMethod || beforeTyper(sym.typeParams.isEmpty)) Nil + if (!sym.isMethod || enteringTyper(sym.typeParams.isEmpty)) Nil else { // debuglog("normalizeMember: " + sym.fullNameAsName('.').decode) var specializingOn = specializedParams(sym) @@ -835,7 +845,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { debuglog("%s expands to %s in %s".format(sym, specMember.name.decode, pp(env))) info(specMember) = NormalizedMember(sym) - overloads(sym) ::= Overload(specMember, env) + newOverload(sym, specMember, env) owner.info.decls.enter(specMember) specMember } @@ -870,6 +880,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } val specMember = subst(outerEnv)(specializedOverload(owner, sym, spec)) + owner.info.decls.enter(specMember) typeEnv(specMember) = typeEnv(sym) ++ outerEnv ++ spec wasSpecializedForTypeVars(specMember) ++= spec collect { case (s, tp) if s.tpe == tp => s } @@ -877,9 +888,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { if (wasSpec.nonEmpty) debuglog("specialized overload for %s in %s".format(specMember, pp(typeEnv(specMember)))) - overloads(sym) ::= Overload(specMember, spec) + newOverload(sym, specMember, spec) info(specMember) = SpecialOverload(sym, typeEnv(specMember)) - specMember } @@ -899,10 +909,11 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } /** Return the specialized overload of `m`, in the given environment. */ - private def specializedOverload(owner: Symbol, sym: Symbol, env: TypeEnv): Symbol = { + private def specializedOverload(owner: Symbol, sym: Symbol, env: TypeEnv, nameSymbol: Symbol = NoSymbol): Symbol = { val newFlags = (sym.flags | SPECIALIZED) & ~(DEFERRED | CASEACCESSOR) // this method properly duplicates the symbol's info - ( sym.cloneSymbol(owner, newFlags, newName = specializedName(sym, env)) + val specname = specializedName(nameSymbol orElse sym, env) + ( sym.cloneSymbol(owner, newFlags, newName = specname) modifyInfo (info => subst(env, info.asSeenFrom(owner.thisType, sym.owner))) ) } @@ -949,7 +960,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { checkOverriddenTParams(overridden) val env = unify(overridden.info, overriding.info, emptyEnv, false, true) - def atNext = afterSpecialize(overridden.owner.info.decl(specializedName(overridden, env))) + def atNext = exitingSpecialize(overridden.owner.info.decl(specializedName(overridden, env))) if (TypeEnv.restrict(env, stvars).nonEmpty && TypeEnv.isValid(env, overridden) && atNext != NoSymbol) { debuglog(" " + pp(env) + " found " + atNext) @@ -962,14 +973,32 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } (clazz.info.decls flatMap { overriding => needsSpecialOverride(overriding) match { - case (NoSymbol, _) => None + case (NoSymbol, _) => + if (overriding.isSuperAccessor) { + val alias = overriding.alias + debuglog("checking special overload for super accessor: %s, alias for %s".format(overriding.fullName, alias.fullName)) + needsSpecialOverride(alias) match { + case nope @ (NoSymbol, _) => None + case (overridden, env) => + val om = specializedOverload(clazz, overriding, env, overridden) + om.setName(nme.superName(om.name)) + om.asInstanceOf[TermSymbol].setAlias(info(alias).target) + om.owner.info.decls.enter(om) + info(om) = SpecialSuperAccessor(om) + om.makeNotPrivate(om.owner) + newOverload(overriding, om, env) + Some(om) + } + } else None case (overridden, env) => val om = specializedOverload(clazz, overridden, env) + clazz.info.decls.enter(om) debuglog("specialized overload %s for %s in %s: %s".format(om, overriding.name.decode, pp(env), om.info)) + if (overriding.isAbstractOverride) om.setFlag(ABSOVERRIDE) typeEnv(om) = env addConcreteSpecMethod(overriding) info(om) = ( - if (overriding.isDeferred) { // abstract override + if (overriding.isDeferred) { // abstract override debuglog("abstract override " + overriding.fullName + " with specialized " + om.fullName) Forward(overriding) } @@ -989,8 +1018,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { SpecialOverride(impl) } ) - overloads(overriding) ::= Overload(om, env) - ifDebug(afterSpecialize(assert( + newOverload(overriding, om, env) + ifDebug(exitingSpecialize(assert( overridden.owner.info.decl(om.name) != NoSymbol, "Could not find " + om.name + " in " + overridden.owner.info.decls)) ) @@ -1019,7 +1048,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { if (isPrimitiveValueClass(tp2.typeSymbol) || isSpecializedAnyRefSubtype(tp2, sym1)) env + ((sym1, tp2)) else if (isSpecializedAnyRefSubtype(tp2, sym1)) - env + ((sym1, tp2)) // env + ((sym1, AnyRefClass.tpe)) + env + ((sym1, tp2)) else if (strict) unifyError(tp1, tp2) else @@ -1076,10 +1105,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } } - /** Apply type bindings in the given environment `env` to all declarations. */ - private def subst(env: TypeEnv, decls: List[Symbol]): List[Symbol] = - decls map subst(env) - /** Apply the type environment 'env' to the given type. All type * bindings are supposed to be to primitive types. A type variable * that is annotated with 'uncheckedVariance' is mapped to the corresponding @@ -1106,33 +1131,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { private def subst(env: TypeEnv)(decl: Symbol): Symbol = decl modifyInfo (info => - if (decl.isConstructor) MethodType(subst(env, info).params, decl.owner.tpe) + if (decl.isConstructor) MethodType(subst(env, info).params, decl.owner.tpe_*) else subst(env, info) ) - /** Checks if the type parameter symbol is not specialized - * and is used as type parameters when extending a class with a specialized - * type parameter. - * At some point we may remove this restriction. - * - * Example: - * - * class Base[@specialized T] - * class Derived[T] extends Base[T] // a non-specialized T is - * // used as a type param for Base - * // -> returning true - */ - private def notSpecializedIn(tsym: Symbol, supertpe: Type) = supertpe match { - case TypeRef(_, supersym, supertargs) => - val tspec = specializedOn(tsym).toSet - for (supt <- supersym.typeParams) { - val supspec = specializedOn(supt).toSet - if (tspec != supspec && tspec.subsetOf(supspec)) - reporter.error(tsym.pos, "Type parameter has to be specialized at least for the same types as in the superclass. Missing types: " + (supspec.diff(tspec)).mkString(", ")) - } - case _ => //log("nope") - } - private def unspecializableClass(tp: Type) = ( definitions.isRepeatedParamType(tp) // ??? || tp.typeSymbol.isJavaDefined @@ -1148,7 +1150,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { case cinfo @ ClassInfoType(parents, decls, clazz) if !unspecializableClass(cinfo) => val tparams = tpe.typeParams if (tparams.isEmpty) - afterSpecialize(parents map (_.typeSymbol.info)) + exitingSpecialize(parents map (_.typeSymbol.info)) val parents1 = parents mapConserve specializedType if (parents ne parents1) { @@ -1169,7 +1171,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * * A conflicting type environment could still be satisfiable. */ - def conflicting(env: TypeEnv) = !nonConflicting(env) def nonConflicting(env: TypeEnv) = env forall { case (tvar, tpe) => (subst(env, tvar.info.bounds.lo) <:< tpe) && (tpe <:< subst(env, tvar.info.bounds.hi)) } @@ -1292,7 +1293,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { if (sym.isPrivate) debuglog( "seeing private member %s, currentClass: %s, owner: %s, isAccessible: %b, isLocalName: %b".format( sym, currentClass, sym.owner.enclClass, isAccessible(sym), nme.isLocalName(sym.name)) - ) + ) if (shouldMakePublic(sym) && !isAccessible(sym)) { debuglog("changing private flag of " + sym) sym.makeNotPrivate(sym.owner) @@ -1377,59 +1378,72 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { def transform1(tree: Tree) = { val symbol = tree.symbol - /** The specialized symbol of 'tree.symbol' for tree.tpe, if there is one */ - def specSym(qual: Tree): Option[Symbol] = { + def specSym(qual: Tree): Symbol = { val env = unify(symbol.tpe, tree.tpe, emptyEnv, false) - debuglog("[specSym] checking for rerouting: %s with \n\tsym.tpe: %s, \n\ttree.tpe: %s \n\tenv: %s \n\tname: %s" - .format(tree, symbol.tpe, tree.tpe, env, specializedName(symbol, env))) - if (!env.isEmpty) { // a method? - val specCandidates = qual.tpe.member(specializedName(symbol, env)) - val specMember = specCandidates suchThat { s => - doesConform(symbol, tree.tpe, qual.tpe.memberType(s), env) - } + def isMatch(member: Symbol) = ( + doesConform(symbol, tree.tpe, qual.tpe memberType member, env) + && TypeEnv.includes(typeEnv(member), env) + ) + if (env.isEmpty) NoSymbol + else qual.tpe member specializedName(symbol, env) suchThat isMatch + } - debuglog("[specSym] found: " + specCandidates.tpe + ", instantiated as: " + tree.tpe) - debuglog("[specSym] found specMember: " + specMember) - if (specMember ne NoSymbol) - if (TypeEnv.includes(typeEnv(specMember), env)) Some(specMember) - else { - debuglog("wrong environments for specialized member: \n\ttypeEnv(%s) = %s\n\tenv = %s".format(specMember, typeEnv(specMember), env)) - None - } - else None - } else None + def matchingSymbolInPrefix(pre: Type, member: Symbol, env: TypeEnv): Symbol = { + pre member specializedName(member, env) suchThat (_.tpe matches subst(env, member.tpe)) + } + + def transformSelect(sel: Select) = { + val Select(qual, name) = sel + debuglog(s"specializing Select(sym=${symbol.defString}, tree.tpe=${tree.tpe})") + + val qual1 = transform(qual) + def copySelect = treeCopy.Select(tree, qual1, name) + def newSelect(member: Symbol) = atPos(tree.pos)(Select(qual1, member)) + def typedOp(member: Symbol) = localTyper typedOperator newSelect(member) + def typedTree(member: Symbol) = localTyper typed newSelect(member) + + val ignoreEnv = specializedTypeVars(symbol.info).isEmpty || name == nme.CONSTRUCTOR + if (ignoreEnv) overloads(symbol) find (_ matchesSym symbol) match { + case Some(Overload(member, _)) => typedOp(member) + case _ => copySelect + } + else { + val env = unify(symbol.tpe, tree.tpe, emptyEnv, false) + overloads(symbol) find (_ matchesEnv env) match { + case Some(Overload(member, _)) => typedOp(member) + case _ => + matchingSymbolInPrefix(qual1.tpe, symbol, env) match { + case NoSymbol => copySelect + case member if member.isMethod => typedOp(member) + case member => typedTree(member) + } + } + } } curTree = tree tree match { case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) => def transformNew = { - debuglog("Attempting to specialize new %s(%s)".format(tpt, args.mkString(", "))) - val found = findSpec(tpt.tpe) - if (found.typeSymbol ne tpt.tpe.typeSymbol) { - // the ctor can be specialized - debuglog("** instantiated specialized type: " + found) - reportError { - localTyper.typedPos(tree.pos)(New(found, transformTrees(args): _*)) - } { - _ => super.transform(tree) + debuglog("Attempting to specialize new %s(%s)".format(tpt, args.mkString(", "))) + val found = specializedType(tpt.tpe) + if (found.typeSymbol ne tpt.tpe.typeSymbol) { // the ctor can be specialized + val inst = New(found, transformTrees(args): _*) + reportError(localTyper.typedPos(tree.pos)(inst))(_ => super.transform(tree)) } - } else super.transform(tree) + else + super.transform(tree) } transformNew - case Apply(sel @ Select(sup @ Super(qual, name), name1), args) - if (sup.symbol.info.parents != beforePrevPhase(sup.symbol.info.parents)) => + case Apply(sel @ Select(sup @ Super(qual, name), name1), args) if hasNewParents(sup) => def transformSuperApply = { - - def parents = sup.symbol.info.parents - debuglog(tree + " parents changed from: " + beforePrevPhase(parents) + " to: " + parents) - - val res = localTyper.typed( - Apply(Select(Super(qual, name) setPos sup.pos, name1) setPos sel.pos, transformTrees(args)) setPos tree.pos) - debuglog("retyping call to super, from: " + symbol + " to " + res.symbol) - res + val sup1 = Super(qual, name) setPos sup.pos + val tree1 = Apply(Select(sup1, name1) setPos sel.pos, transformTrees(args)) + val res = localTyper.typedPos(tree.pos)(tree1) + debuglog(s"retyping call to super, from: $symbol to ${res.symbol}") + res } transformSuperApply @@ -1440,7 +1454,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val qual1 = transform(qual) // log(">>> TypeApply: " + tree + ", qual1: " + qual1) specSym(qual1) match { - case Some(specMember) => + case NoSymbol => + // See pos/exponential-spec.scala - can't call transform on the whole tree again. + treeCopy.TypeApply(tree, treeCopy.Select(sel, qual1, name), transformTrees(targs)) + case specMember => debuglog("found " + specMember.fullName) ifDebug(assert(symbol.info.typeParams.length == targs.length, symbol.info.typeParams + " / " + targs)) @@ -1450,7 +1467,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } // See SI-5583. Don't know why it happens now if it didn't before. if (specMember.info.typeParams.isEmpty && residualTargs.nonEmpty) { - log("!!! Type args to be applied, but symbol says no parameters: " + ((specMember.defString, residualTargs))) + devWarning("Type args to be applied, but symbol says no parameters: " + ((specMember.defString, residualTargs))) localTyper.typed(sel) } else { @@ -1462,63 +1479,17 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { debuglog("rewrote " + tree + " to " + tree1) localTyper.typedOperator(atPos(tree.pos)(tree1)) // being polymorphic, it must be a method } - - case None => - treeCopy.TypeApply(tree, treeCopy.Select(sel, qual1, name), super.transformTrees(targs)) - // See pos/exponential-spec.scala - can't call transform on the whole tree again. - // super.transform(tree) } } transformTypeApply - case Select(qual, name) => - def transformSelect = { - qual match { - case _: Super if illegalSpecializedInheritance(currentClass) => - val pos = tree.pos - debuglog(pos.source.file.name+":"+pos.line+": not specializing call to super inside illegal specialized inheritance class.") - debuglog(pos.lineContent) - tree - case _ => + case Select(Super(_, _), _) if illegalSpecializedInheritance(currentClass) => + val pos = tree.pos + debuglog(pos.source.file.name+":"+pos.line+": not specializing call to super inside illegal specialized inheritance class.\n" + pos.lineContent) + tree - debuglog("specializing Select %s [tree.tpe: %s]".format(symbol.defString, tree.tpe)) - - //log("!!! select " + tree + " -> " + symbol.info + " specTypeVars: " + specializedTypeVars(symbol.info)) - if (specializedTypeVars(symbol.info).nonEmpty && name != nme.CONSTRUCTOR) { - // log("!!! unifying " + (symbol, symbol.tpe) + " and " + (tree, tree.tpe)) - val env = unify(symbol.tpe, tree.tpe, emptyEnv, false) - // log("!!! found env: " + env + "; overloads: " + overloads(symbol)) - if (!env.isEmpty) { - // debuglog("checking for rerouting: " + tree + " with sym.tpe: " + symbol.tpe + " tree.tpe: " + tree.tpe + " env: " + env) - val specMember = overload(symbol, env) - if (specMember.isDefined) { - localTyper.typedOperator(atPos(tree.pos)(Select(transform(qual), specMember.get.sym.name))) - } - else { - val qual1 = transform(qual) - val specMember = qual1.tpe.member(specializedName(symbol, env)).suchThat(_.tpe matches subst(env, symbol.tpe)) - if (specMember ne NoSymbol) { - val tree1 = atPos(tree.pos)(Select(qual1, specMember)) - if (specMember.isMethod) - localTyper.typedOperator(tree1) - else - localTyper.typed(tree1) - } else - treeCopy.Select(tree, qual1, name) - } - } else - super.transform(tree) - } else overloads(symbol).find(_.sym.info =:= symbol.info) match { - case Some(specMember) => - val qual1 = transform(qual) - debuglog("** routing " + tree + " to " + specMember.sym.fullName + " tree: " + Select(qual1, specMember.sym)) - localTyper.typedOperator(atPos(tree.pos)(Select(qual1, specMember.sym))) - case None => - super.transform(tree) - } - } - } - transformSelect + case sel @ Select(_, _) => + transformSelect(sel) case PackageDef(pid, stats) => tree.symbol.info // make sure specializations have been performed @@ -1543,47 +1514,37 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { transformTemplate case ddef @ DefDef(_, _, _, vparamss, _, _) if info.isDefinedAt(symbol) => - def transformDefDef = { - // log("--> method: " + ddef + " in " + ddef.symbol.owner + ", " + info(symbol)) - def reportTypeError(body: =>Tree) = reportError(body)(_ => ddef) - + def transformDefDef = { if (symbol.isConstructor) { - - val t = atOwner(symbol)(forwardCtorCall(tree.pos, gen.mkSuperSelect, vparamss, symbol.owner)) - + val t = atOwner(symbol)(forwardCtorCall(tree.pos, gen.mkSuperInitCall, vparamss, symbol.owner)) if (symbol.isPrimaryConstructor) localTyper.typedPos(symbol.pos)(deriveDefDef(tree)(_ => Block(List(t), Literal(Constant())))) else // duplicate the original constructor - reportTypeError(duplicateBody(ddef, info(symbol).target)) + reportError(duplicateBody(ddef, info(symbol).target))(_ => ddef) } else info(symbol) match { case Implementation(target) => assert(body.isDefinedAt(target), "sym: " + symbol.fullName + " target: " + target.fullName) // we have an rhs, specialize it - val tree1 = reportTypeError { - duplicateBody(ddef, target) - } + val tree1 = reportError(duplicateBody(ddef, target))(_ => ddef) debuglog("implementation: " + tree1) deriveDefDef(tree1)(transform) case NormalizedMember(target) => - val constraints = satisfiabilityConstraints(typeEnv(symbol)) - log("constraints: " + constraints) - if (target.isDeferred || constraints == None) { - deriveDefDef(tree)(_ => localTyper typed gen.mkSysErrorCall("Fatal error in code generation: this should never be called.")) - } else { - // we have an rhs, specialize it - val tree1 = reportTypeError { - duplicateBody(ddef, target, constraints.get) - } - debuglog("implementation: " + tree1) - deriveDefDef(tree1)(transform) + logResult("constraints")(satisfiabilityConstraints(typeEnv(symbol))) match { + case Some(constraint) if !target.isDeferred => + // we have an rhs, specialize it + val tree1 = reportError(duplicateBody(ddef, target, constraint))(_ => ddef) + debuglog("implementation: " + tree1) + deriveDefDef(tree1)(transform) + case _ => + deriveDefDef(tree)(_ => localTyper typed gen.mkSysErrorCall("Fatal error in code generation: this should never be called.")) } case SpecialOverride(target) => assert(body.isDefinedAt(target), "sym: " + symbol.fullName + " target: " + target.fullName) //debuglog("moving implementation, body of target " + target + ": " + body(target)) - debuglog("%s is param accessor? %b".format(ddef.symbol, ddef.symbol.isParamAccessor)) + log("%s is param accessor? %b".format(ddef.symbol, ddef.symbol.isParamAccessor)) // we have an rhs, specialize it val tree1 = addBody(ddef, target) (new ChangeOwnerTraverser(target, tree1.symbol))(tree1.rhs) @@ -1631,6 +1592,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { case Abstract(targ) => debuglog("abstract: " + targ) localTyper.typed(deriveDefDef(tree)(rhs => rhs)) + + case SpecialSuperAccessor(targ) => + debuglog("special super accessor: " + targ + " for " + tree) + localTyper.typed(deriveDefDef(tree)(rhs => rhs)) } } transformDefDef @@ -1652,7 +1617,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { deriveValDef(newValDef)(transform) } transformValDef - case _ => super.transform(tree) } @@ -1689,7 +1653,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val symbol = tree.symbol debuglog("specializing body of" + symbol.defString) val DefDef(_, _, tparams, vparams :: Nil, tpt, _) = tree -// val (_, origtparams) = splitParams(source.typeParams) val env = typeEnv(symbol) val boundTvars = env.keySet val origtparams = source.typeParams.filter(tparam => !boundTvars(tparam) || !isPrimitiveValueType(env(tparam))) @@ -1824,6 +1787,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * }} */ private def forwardCtorCall(pos: scala.reflect.internal.util.Position, receiver: Tree, paramss: List[List[ValDef]], clazz: Symbol): Tree = { + log(s"forwardCtorCall($pos, $receiver, $paramss, $clazz)") /** A constructor parameter `f` initializes a specialized field * iff: @@ -1860,16 +1824,12 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { //! TODO: make sure the param types are seen from the right prefix map2(fun.info.paramTypes, vparams)((tp, arg) => gen.maybeMkAsInstanceOf(Ident(arg), tp, arg.tpe)) ) - private def findSpec(tp: Type): Type = tp match { - case TypeRef(pre, sym, _ :: _) => specializedType(tp) - case _ => tp - } class SpecializationTransformer(unit: CompilationUnit) extends Transformer { informProgress("specializing " + unit) override def transform(tree: Tree) = { val resultTree = if (settings.nospecialization.value) tree - else afterSpecialize(specializeCalls(unit).transform(tree)) + else exitingSpecialize(specializeCalls(unit).transform(tree)) // Remove the final modifier and @inline annotation from anything in the // original class (since it's being overridden in at least onesubclass). @@ -1889,11 +1849,4 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { resultTree } } - - def printSpecStats() { - println(" concreteSpecMembers: %7d".format(concreteSpecMethods.size)) - println(" overloads: %7d".format(overloads.size)) - println(" typeEnv: %7d".format(typeEnv.size)) - println(" info: %7d".format(info.size)) - } } diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index 95cb052fda..6ab99eaec6 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -17,7 +17,7 @@ import Flags.SYNTHETIC abstract class TailCalls extends Transform { import global._ // the global environment import definitions._ // standard classes and methods - import typer.{ typed, typedPos } // methods to type trees + import typer.typedPos // methods to type trees val phaseName: String = "tailcalls" @@ -82,7 +82,7 @@ abstract class TailCalls extends Transform { * that label. * </p> * <p> - * Assumes: <code>Uncurry</code> has been run already, and no multiple + * Assumes: `Uncurry` has been run already, and no multiple * parameter lists exit. * </p> */ @@ -147,7 +147,6 @@ abstract class TailCalls extends Transform { } def enclosingType = method.enclClass.typeOfThis - def methodTypeParams = method.tpe.typeParams def isEligible = method.isEffectivelyFinal // @tailrec annotation indicates mandatory transformation def isMandatory = method.hasAnnotation(TailrecClass) && !forMSIL diff --git a/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala b/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala index c7bc16f249..73f39225bd 100644 --- a/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala +++ b/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala @@ -6,8 +6,6 @@ package scala.tools.nsc package transform -import scala.collection.{ mutable, immutable } - /** A base class for transforms. * A transform contains a compiler phase which applies a tree transformer. */ @@ -23,13 +21,11 @@ trait TypingTransformers { else analyzer.newTyper(analyzer.rootContext(unit, EmptyTree, true)) protected var curTree: Tree = _ - protected def typedPos(pos: Position)(tree: Tree) = localTyper typed { atPos(pos)(tree) } override final def atOwner[A](owner: Symbol)(trans: => A): A = atOwner(curTree, owner)(trans) def atOwner[A](tree: Tree, owner: Symbol)(trans: => A): A = { val savedLocalTyper = localTyper -// println("transformer atOwner: " + owner + " isPackage? " + owner.isPackage) localTyper = localTyper.atOwner(tree, if (owner.isModule) owner.moduleClass else owner) val result = super.atOwner(owner)(trans) localTyper = savedLocalTyper diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 529009a058..8ae9490dbe 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -112,8 +112,6 @@ abstract class UnCurry extends InfoTransform private lazy val serialVersionUIDAnnotation = AnnotationInfo(SerialVersionUIDAttr.tpe, List(Literal(Constant(0))), List()) - private var nprinted = 0 - // I don't have a clue why I'm catching TypeErrors here, but it's better // than spewing stack traces at end users for internal errors. Examples // which hit at this point should not be hard to come by, but the immediate @@ -134,7 +132,7 @@ abstract class UnCurry extends InfoTransform def isByNameRef(tree: Tree) = ( tree.isTerm && !byNameArgs(tree) - && tree.hasSymbolWhich(s => isByNameParamType(s.tpe)) + && tree.hasSymbolWhich(isByName) ) /** Uncurry a type of a tree node. @@ -205,6 +203,9 @@ abstract class UnCurry extends InfoTransform val keyDef = ValDef(key, New(ObjectClass.tpe)) val tryCatch = Try(body, pat -> rhs) + for (Try(t, catches, _) <- body ; cdef <- catches ; if treeInfo catchesThrowable cdef) + unit.warning(body.pos, "catch block may intercept non-local return from " + meth) + Block(List(keyDef), tryCatch) } } @@ -296,7 +297,8 @@ abstract class UnCurry extends InfoTransform * If there's a default case, the original match is used for applyOrElse, and isDefinedAt returns `true` */ def synthPartialFunction(fun: Function) = { - if (!settings.XoldPatmat.value) debugwarn("Under the new pattern matching scheme, PartialFunction should have been synthesized during typers.") + if (!settings.XoldPatmat.value) + devWarning("Under the new pattern matching scheme, PartialFunction should have been synthesized during typers.") val targs = fun.tpe.typeArgs val (formals, restpe) = (targs.init, targs.last) @@ -335,7 +337,7 @@ abstract class UnCurry extends InfoTransform // def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = val applyOrElseMethodDef = { - val methSym = anonClass.newMethod(fun.pos, nme.applyOrElse) setFlag (FINAL | OVERRIDE) + val methSym = anonClass.newMethod(nme.applyOrElse, fun.pos, newFlags = FINAL | OVERRIDE | SYNTHETIC) val List(argtpe) = formals val A1 = methSym newTypeParameter(newTypeName("A1")) setInfo TypeBounds.upper(argtpe) @@ -405,7 +407,7 @@ abstract class UnCurry extends InfoTransform // when calling into scala varargs, make sure it's a sequence. def arrayToSequence(tree: Tree, elemtp: Type) = { - afterUncurry { + exitingUncurry { localTyper.typedPos(pos) { val pt = arrayType(elemtp) val adaptedTree = // might need to cast to Array[elemtp], as arrays are not covariant @@ -435,7 +437,7 @@ abstract class UnCurry extends InfoTransform case _ => EmptyTree } } - afterUncurry { + exitingUncurry { localTyper.typedPos(pos) { gen.mkMethodCall(tree, toArraySym, Nil, List(traversableClassTag(tree.tpe))) } @@ -459,7 +461,7 @@ abstract class UnCurry extends InfoTransform else arrayToSequence(mkArray, varargsElemType) } - afterUncurry { + exitingUncurry { if (isJava && !isReferenceArray(suffix.tpe) && isArrayOfSymbol(fun.tpe.params.last.tpe, ObjectClass)) { // The array isn't statically known to be a reference array, so call ScalaRuntime.toObjectArray. suffix = localTyper.typedPos(pos) { @@ -624,7 +626,7 @@ abstract class UnCurry extends InfoTransform treeCopy.Apply(tree, transform(fn), transformTrees(transformArgs(tree.pos, fn.symbol, args, formals))) } - case Assign(Select(_, _), _) => + case Assign(_: RefTree, _) => withNeedLift(true) { super.transform(tree) } case Assign(lhs, _) if lhs.symbol.owner != currentMethod || lhs.symbol.hasFlag(LAZY | ACCESSOR) => @@ -670,7 +672,7 @@ abstract class UnCurry extends InfoTransform result setType uncurryTreeType(result.tpe) } - def postTransform(tree: Tree): Tree = afterUncurry { + def postTransform(tree: Tree): Tree = exitingUncurry { def applyUnary(): Tree = { // TODO_NMT: verify that the inner tree of a type-apply also gets parens if the // whole tree is a polymorphic nullary method application @@ -701,9 +703,9 @@ abstract class UnCurry extends InfoTransform val body = tree.block val catches = tree.catches val finalizer = tree.finalizer - if (opt.virtPatmat) { + if (!settings.XoldPatmat.value) { if (catches exists (cd => !treeInfo.isCatchCase(cd))) - debugwarn("VPM BUG! illegal try/catch " + catches) + devWarning("VPM BUG - illegal try/catch " + catches) tree } else if (catches forall treeInfo.isCatchCase) { tree @@ -799,10 +801,6 @@ abstract class UnCurry extends InfoTransform if (!dd.symbol.hasAnnotation(VarargsClass) || !repeatedParams.contains(dd.symbol)) return flatdd - def toSeqType(tp: Type): Type = { - val arg = elementType(ArrayClass, tp) - seqType(arg) - } def toArrayType(tp: Type): Type = { val arg = elementType(SeqClass, tp) // to prevent generation of an `Object` parameter from `Array[T]` parameter later diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala index 78175f393a..5e8bb3e424 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala @@ -87,22 +87,25 @@ trait Analyzer extends AnyRef override def run() { val start = if (Statistics.canEnable) Statistics.startTimer(typerNanos) else null global.echoPhaseSummary(this) - currentRun.units foreach applyPhase - undoLog.clear() - // need to clear it after as well or 10K+ accumulated entries are - // uncollectable the rest of the way. + for (unit <- currentRun.units) { + applyPhase(unit) + undoLog.clear() + } if (Statistics.canEnable) Statistics.stopTimer(typerNanos, start) } def apply(unit: CompilationUnit) { try { - unit.body = newTyper(rootContext(unit)).typed(unit.body) + val typer = newTyper(rootContext(unit)) + unit.body = typer.typed(unit.body) if (global.settings.Yrangepos.value && !global.reporter.hasErrors) global.validatePositions(unit.body) for (workItem <- unit.toCheck) workItem() - } finally { + if (settings.lint.value) + typer checkUnused unit + } + finally { unit.toCheck.clear() } } } } } - diff --git a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala index d30b5c2601..9efa3f36b0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala @@ -6,12 +6,8 @@ package scala.tools.nsc package typechecker -import scala.collection.{ mutable, immutable } -import scala.collection.mutable.ListBuffer -import scala.util.control.ControlThrowable -import symtab.Flags._ -import scala.annotation.tailrec import Checkability._ +import scala.language.postfixOps /** On pattern matcher checkability: * @@ -134,7 +130,7 @@ trait Checkable { else if (P3) RuntimeCheckable else if (uncheckableType == NoType) { // Avoid warning (except ourselves) if we can't pinpoint the uncheckable type - debugwarn("Checkability checker says 'Uncheckable', but uncheckable type cannot be found:\n" + summaryString) + debuglog("Checkability checker says 'Uncheckable', but uncheckable type cannot be found:\n" + summaryString) CheckabilityError } else Uncheckable @@ -154,6 +150,7 @@ trait Checkable { def neverSubClass = isNeverSubClass(Xsym, Psym) def neverMatches = result == StaticallyFalse def isUncheckable = result == Uncheckable + def isCheckable = !isUncheckable def uncheckableMessage = uncheckableType match { case NoType => "something" case tp @ RefinedType(_, _) => "refinement " + tp @@ -232,6 +229,17 @@ trait Checkable { trait InferCheckable { self: Inferencer => + def isUncheckable(P0: Type) = !isCheckable(P0) + + def isCheckable(P0: Type): Boolean = ( + uncheckedOk(P0) || (P0.widen match { + case TypeRef(_, NothingClass | NullClass | AnyValClass, _) => false + case RefinedType(_, decls) if !decls.isEmpty => false + case p => + new CheckabilityChecker(AnyClass.tpe, p) isCheckable + }) + ) + /** TODO: much better error positions. * Kind of stuck right now because they just pass us the one tree. * TODO: Eliminate inPattern, canRemedy, which have no place here. diff --git a/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala b/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala index 89e2ee44be..65bfd8e34e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala @@ -6,7 +6,6 @@ package scala.tools.nsc package typechecker - import java.lang.ArithmeticException /** This class ... @@ -18,7 +17,6 @@ abstract class ConstantFolder { val global: Global import global._ - import definitions._ /** If tree is a constant operation, replace with result. */ def apply(tree: Tree): Tree = fold(tree, tree match { @@ -29,9 +27,6 @@ abstract class ConstantFolder { /** If tree is a constant value that can be converted to type `pt`, perform * the conversion. - * - * @param tree ... - * @param pt ... */ def apply(tree: Tree, pt: Type): Tree = fold(apply(tree), tree.tpe match { case ConstantType(x) => x convertTo pt diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index faacb60d75..a6d11f13d4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -6,9 +6,8 @@ package scala.tools.nsc package typechecker -import scala.collection.{ mutable, immutable } import scala.reflect.internal.util.StringOps.{ countElementsAsString, countAsString } -import symtab.Flags.{ PRIVATE, PROTECTED, IS_ERROR } +import symtab.Flags.IS_ERROR import scala.compat.Platform.EOL import scala.reflect.runtime.ReflectionUtils import scala.reflect.macros.runtime.AbortMacroException @@ -157,7 +156,6 @@ trait ContextErrors { case RefinedType(parents, decls) if !decls.isEmpty && found.typeSymbol.isAnonOrRefinementClass => val retyped = typed (tree.duplicate setType null) val foundDecls = retyped.tpe.decls filter (sym => !sym.isConstructor && !sym.isSynthetic) - if (foundDecls.isEmpty || (found.typeSymbol eq NoSymbol)) found else { // The members arrive marked private, presumably because there was no @@ -171,11 +169,11 @@ trait ContextErrors { case _ => found } - assert(!found.isErroneous && !req.isErroneous, (found, req)) + assert(!foundType.isErroneous && !req.isErroneous, (foundType, req)) - issueNormalTypeError(tree, withAddendum(tree.pos)(typeErrorMsg(found, req, infer.isPossiblyMissingArgs(found, req))) ) + issueNormalTypeError(tree, withAddendum(tree.pos)(typeErrorMsg(foundType, req, infer.isPossiblyMissingArgs(foundType, req))) ) if (settings.explaintypes.value) - explainTypes(found, req) + explainTypes(foundType, req) } def WithFilterError(tree: Tree, ex: AbsTypeError) = { @@ -269,9 +267,6 @@ trait ContextErrors { def VolatileValueError(vdef: Tree) = issueNormalTypeError(vdef, "values cannot be volatile") - def FinalVolatileVarError(vdef: Tree) = - issueNormalTypeError(vdef, "final vars cannot be volatile") - def LocalVarUninitializedError(vdef: Tree) = issueNormalTypeError(vdef, "local variables must be initialized") @@ -660,8 +655,8 @@ trait ContextErrors { def CyclicAliasingOrSubtypingError(errPos: Position, sym0: Symbol) = issueTypeError(PosAndMsgTypeError(errPos, "cyclic aliasing or subtyping involving "+sym0)) - def CyclicReferenceError(errPos: Position, lockedSym: Symbol) = - issueTypeError(PosAndMsgTypeError(errPos, "illegal cyclic reference involving " + lockedSym)) + def CyclicReferenceError(errPos: Position, tp: Type, lockedSym: Symbol) = + issueTypeError(PosAndMsgTypeError(errPos, s"illegal cyclic reference involving $tp and $lockedSym")) // macro-related errors (also see MacroErrors below) @@ -673,10 +668,9 @@ trait ContextErrors { // same reason as for MacroBodyTypecheckException case object MacroExpansionException extends Exception with scala.util.control.ControlThrowable - private def macroExpansionError(expandee: Tree, msg: String = null, pos: Position = NoPosition) = { + private def macroExpansionError(expandee: Tree, msg: String, pos: Position = NoPosition) = { def msgForLog = if (msg != null && (msg contains "exception during macro expansion")) msg.split(EOL).drop(1).headOption.getOrElse("?") else msg macroLogLite("macro expansion has failed: %s".format(msgForLog)) - val errorPos = if (pos != NoPosition) pos else (if (expandee.pos != NoPosition) expandee.pos else enclosingMacroPosition) if (msg != null) context.error(pos, msg) // issueTypeError(PosAndMsgTypeError(..)) won't work => swallows positions setError(expandee) throw MacroExpansionException @@ -805,7 +799,10 @@ trait ContextErrors { ) } - def AccessError(tree: Tree, sym: Symbol, pre: Type, owner0: Symbol, explanation: String) = { + def AccessError(tree: Tree, sym: Symbol, ctx: Context, explanation: String): AbsTypeError = + AccessError(tree, sym, ctx.enclClass.owner.thisType, ctx.enclClass.owner, explanation) + + def AccessError(tree: Tree, sym: Symbol, pre: Type, owner0: Symbol, explanation: String): AbsTypeError = { def errMsg = { val location = if (sym.isClassConstructor) owner0 else pre.widen.directObjectString diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 507825ff15..1af61d31ec 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -6,8 +6,7 @@ package scala.tools.nsc package typechecker -import symtab.Flags._ -import scala.collection.mutable.{LinkedHashSet, Set} +import scala.collection.mutable import scala.annotation.tailrec /** @@ -16,6 +15,7 @@ import scala.annotation.tailrec */ trait Contexts { self: Analyzer => import global._ + import definitions.{ JavaLangPackage, ScalaPackage, PredefModule } object NoContext extends Context { outer = this @@ -28,13 +28,17 @@ trait Contexts { self: Analyzer => override def toString = "NoContext" } private object RootImports { - import definitions._ // Possible lists of root imports val javaList = JavaLangPackage :: Nil val javaAndScalaList = JavaLangPackage :: ScalaPackage :: Nil val completeList = JavaLangPackage :: ScalaPackage :: PredefModule :: Nil } + def ambiguousImports(imp1: ImportInfo, imp2: ImportInfo) = + LookupAmbiguous(s"it is imported twice in the same scope by\n$imp1\nand $imp2") + def ambiguousDefnAndImport(owner: Symbol, imp: ImportInfo) = + LookupAmbiguous(s"it is both defined in $owner and imported subsequently by \n$imp") + private val startContext = { NoContext.make( Template(List(), emptyValDef, List()) setSymbol global.NoSymbol setType global.NoType, @@ -42,6 +46,28 @@ trait Contexts { self: Analyzer => rootMirror.RootClass.info.decls) } + private lazy val allUsedSelectors = + mutable.Map[ImportInfo, Set[ImportSelector]]() withDefaultValue Set() + private lazy val allImportInfos = + mutable.Map[CompilationUnit, List[ImportInfo]]() withDefaultValue Nil + + def clearUnusedImports() { + allUsedSelectors.clear() + allImportInfos.clear() + } + def warnUnusedImports(unit: CompilationUnit) = { + val imps = allImportInfos(unit).reverse.distinct + + for (imp <- imps) { + val used = allUsedSelectors(imp) + def isMask(s: ImportSelector) = s.name != nme.WILDCARD && s.rename == nme.WILDCARD + + imp.tree.selectors filterNot (s => isMask(s) || used(s)) foreach { sel => + unit.warning(imp posOf sel, "Unused import") + } + } + } + var lastAccessCheckDetails: String = "" /** List of symbols to import from in a root context. Typically that @@ -64,7 +90,6 @@ trait Contexts { self: Analyzer => def rootContext(unit: CompilationUnit): Context = rootContext(unit, EmptyTree, false) def rootContext(unit: CompilationUnit, tree: Tree): Context = rootContext(unit, tree, false) def rootContext(unit: CompilationUnit, tree: Tree, erasedTypes: Boolean): Context = { - import definitions._ var sc = startContext for (sym <- rootImports(unit)) { sc = sc.makeNewImport(sym) @@ -143,7 +168,7 @@ trait Contexts { self: Analyzer => var typingIndentLevel: Int = 0 def typingIndent = " " * typingIndentLevel - var buffer: Set[AbsTypeError] = _ + var buffer: mutable.Set[AbsTypeError] = _ def enclClassOrMethod: Context = if ((owner eq NoSymbol) || (owner.isClass) || (owner.isMethod)) this @@ -182,20 +207,18 @@ trait Contexts { self: Analyzer => def setThrowErrors() = mode &= (~AllMask) def setAmbiguousErrors(report: Boolean) = if (report) mode |= AmbiguousErrors else mode &= notThrowMask - def updateBuffer(errors: Set[AbsTypeError]) = buffer ++= errors + def updateBuffer(errors: mutable.Set[AbsTypeError]) = buffer ++= errors def condBufferFlush(removeP: AbsTypeError => Boolean) { val elems = buffer.filter(removeP) buffer --= elems } def flushBuffer() { buffer.clear() } - def flushAndReturnBuffer(): Set[AbsTypeError] = { + def flushAndReturnBuffer(): mutable.Set[AbsTypeError] = { val current = buffer.clone() buffer.clear() current } - def logError(err: AbsTypeError) = buffer += err - def withImplicitsEnabled[T](op: => T): T = { val saved = implicitsEnabled implicitsEnabled = true @@ -281,26 +304,22 @@ trait Contexts { self: Analyzer => c.checking = this.checking c.retyping = this.retyping c.openImplicits = this.openImplicits - c.buffer = if (this.buffer == null) LinkedHashSet[AbsTypeError]() else this.buffer // need to initialize + c.buffer = if (this.buffer == null) mutable.LinkedHashSet[AbsTypeError]() else this.buffer // need to initialize registerContext(c.asInstanceOf[analyzer.Context]) debuglog("[context] ++ " + c.unit + " / " + tree.summaryString) c } - // TODO: remove? Doesn't seem to be used - def make(unit: CompilationUnit): Context = { - val c = make(unit, EmptyTree, owner, scope, imports) - c.setReportErrors() - c.implicitsEnabled = true - c.macrosEnabled = true - c - } - def makeNewImport(sym: Symbol): Context = makeNewImport(gen.mkWildcardImport(sym)) - def makeNewImport(imp: Import): Context = - make(unit, imp, owner, scope, new ImportInfo(imp, depth) :: imports) + def makeNewImport(imp: Import): Context = { + val impInfo = new ImportInfo(imp, depth) + if (settings.lint.value && imp.pos.isDefined) // pos.isDefined excludes java.lang/scala/Predef imports + allImportInfos(unit) ::= impInfo + + make(unit, imp, owner, scope, impInfo :: imports) + } def make(tree: Tree, owner: Symbol, scope: Scope): Context = if (tree == this.tree && owner == this.owner && scope == this.scope) this @@ -323,7 +342,7 @@ trait Contexts { self: Analyzer => val c = make(newtree) c.setBufferErrors() c.setAmbiguousErrors(reportAmbiguousErrors) - c.buffer = new LinkedHashSet[AbsTypeError]() + c.buffer = mutable.LinkedHashSet[AbsTypeError]() c } @@ -368,8 +387,10 @@ trait Contexts { self: Analyzer => unit.error(pos, if (checking) "\n**** ERROR DURING INTERNAL CHECKING ****\n" + msg else msg) @inline private def issueCommon(err: AbsTypeError)(pf: PartialFunction[AbsTypeError, Unit]) { - debugwarn("issue error: " + err.errMsg) - if (settings.Yissuedebug.value) (new Exception).printStackTrace() + if (settings.Yissuedebug.value) { + log("issue error: " + err.errMsg) + (new Exception).printStackTrace() + } if (pf isDefinedAt err) pf(err) else if (bufferErrors) { buffer += err } else throw new TypeError(err.errPos, err.errMsg) @@ -459,17 +480,6 @@ trait Contexts { self: Analyzer => sub.isNonBottomSubClass(base) || sub.isModuleClass && sub.linkedClassOfClass.isNonBottomSubClass(base) - /** Return closest enclosing context that defines a superclass of `clazz`, or a - * companion module of a superclass of `clazz`, or NoContext if none exists */ - def enclosingSuperClassContext(clazz: Symbol): Context = { - var c = this.enclClass - while (c != NoContext && - !clazz.isNonBottomSubClass(c.owner) && - !(c.owner.isModuleClass && clazz.isNonBottomSubClass(c.owner.companionClass))) - c = c.outer.enclClass - c - } - /** Return the closest enclosing context that defines a subclass of `clazz` * or a companion object thereof, or `NoContext` if no such context exists. */ @@ -480,8 +490,7 @@ trait Contexts { self: Analyzer => c } - /** Is `sym` accessible as a member of tree `site` with type - * `pre` in current context? + /** Is `sym` accessible as a member of `pre` in current context? */ def isAccessible(sym: Symbol, pre: Type, superAccess: Boolean = false): Boolean = { lastAccessCheckDetails = "" @@ -507,20 +516,6 @@ trait Contexts { self: Analyzer => } else (owner hasTransOwner ab) } -/* - var c = this - while (c != NoContext && c.owner != owner) { - if (c.outer eq null) assert(false, "accessWithin(" + owner + ") " + c);//debug - if (c.outer.enclClass eq null) assert(false, "accessWithin(" + owner + ") " + c);//debug - c = c.outer.enclClass - } - c != NoContext - } -*/ - /** Is `clazz` a subclass of an enclosing class? */ - def isSubClassOfEnclosing(clazz: Symbol): Boolean = - enclosingSuperClassContext(clazz) != NoContext - def isSubThisType(pre: Type, clazz: Symbol): Boolean = pre match { case ThisType(pclazz) => pclazz isNonBottomSubClass clazz case _ => false @@ -632,7 +627,7 @@ trait Contexts { self: Analyzer => case ImportSelector(from, _, to, _) :: sels1 => var impls = collect(sels1) filter (info => info.name != from) if (to != nme.WILDCARD) { - for (sym <- imp.importedSymbol(to).alternatives) + for (sym <- importedAccessibleSymbol(imp, to).alternatives) if (isQualifyingImplicit(to, sym, pre, imported = true)) impls = new ImplicitInfo(to, pre, sym) :: impls } @@ -678,6 +673,259 @@ trait Contexts { self: Analyzer => implicitsCache } + /** It's possible that seemingly conflicting identifiers are + * identifiably the same after type normalization. In such cases, + * allow compilation to proceed. A typical example is: + * package object foo { type InputStream = java.io.InputStream } + * import foo._, java.io._ + */ + private def resolveAmbiguousImport(name: Name, imp1: ImportInfo, imp2: ImportInfo): Option[ImportInfo] = { + val imp1Explicit = imp1 isExplicitImport name + val imp2Explicit = imp2 isExplicitImport name + val ambiguous = if (imp1.depth == imp2.depth) imp1Explicit == imp2Explicit else !imp1Explicit && imp2Explicit + val imp1Symbol = (imp1 importedSymbol name).initialize filter (s => isAccessible(s, imp1.qual.tpe, superAccess = false)) + val imp2Symbol = (imp2 importedSymbol name).initialize filter (s => isAccessible(s, imp2.qual.tpe, superAccess = false)) + + // The types of the qualifiers from which the ambiguous imports come. + // If the ambiguous name is a value, these must be the same. + def t1 = imp1.qual.tpe + def t2 = imp2.qual.tpe + // The types of the ambiguous symbols, seen as members of their qualifiers. + // If the ambiguous name is a monomorphic type, we can relax this far. + def mt1 = t1 memberType imp1Symbol + def mt2 = t2 memberType imp2Symbol + + def characterize = List( + s"types: $t1 =:= $t2 ${t1 =:= t2} members: ${mt1 =:= mt2}", + s"member type 1: $mt1", + s"member type 2: $mt2" + ).mkString("\n ") + + if (!ambiguous || !imp2Symbol.exists) Some(imp1) + else if (!imp1Symbol.exists) Some(imp2) + else ( + // The symbol names are checked rather than the symbols themselves because + // each time an overloaded member is looked up it receives a new symbol. + // So foo.member("x") != foo.member("x") if x is overloaded. This seems + // likely to be the cause of other bugs too... + if (t1 =:= t2 && imp1Symbol.name == imp2Symbol.name) { + log(s"Suppressing ambiguous import: $t1 =:= $t2 && $imp1Symbol == $imp2Symbol") + Some(imp1) + } + // Monomorphism restriction on types is in part because type aliases could have the + // same target type but attach different variance to the parameters. Maybe it can be + // relaxed, but doesn't seem worth it at present. + else if (mt1 =:= mt2 && name.isTypeName && imp1Symbol.isMonomorphicType && imp2Symbol.isMonomorphicType) { + log(s"Suppressing ambiguous import: $mt1 =:= $mt2 && $imp1Symbol and $imp2Symbol are equivalent") + Some(imp1) + } + else { + log(s"Import is genuinely ambiguous:\n " + characterize) + None + } + ) + } + + /** The symbol with name `name` imported via the import in `imp`, + * if any such symbol is accessible from this context. + */ + def importedAccessibleSymbol(imp: ImportInfo, name: Name): Symbol = + importedAccessibleSymbol(imp, name, requireExplicit = false) + + private def importedAccessibleSymbol(imp: ImportInfo, name: Name, requireExplicit: Boolean): Symbol = + imp.importedSymbol(name, requireExplicit) filter (s => isAccessible(s, imp.qual.tpe, superAccess = false)) + + /** Is `sym` defined in package object of package `pkg`? + * Since sym may be defined in some parent of the package object, + * we cannot inspect its owner only; we have to go through the + * info of the package object. However to avoid cycles we'll check + * what other ways we can before pushing that way. + */ + def isInPackageObject(sym: Symbol, pkg: Symbol): Boolean = { + def uninitialized(what: String) = { + log(s"Cannot look for $sym in package object of $pkg; $what is not initialized.") + false + } + def pkgClass = if (pkg.isTerm) pkg.moduleClass else pkg + def matchesInfo = ( + // need to be careful here to not get a cyclic reference during bootstrap + if (pkg.isInitialized) { + val module = pkg.info member nme.PACKAGEkw + if (module.isInitialized) + module.info.member(sym.name).alternatives contains sym + else + uninitialized("" + module) + } + else uninitialized("" + pkg) + ) + def inPackageObject(sym: Symbol) = ( + // To be in the package object, one of these must be true: + // 1) sym.owner is a package object class, and sym.owner.owner is the package class for `pkg` + // 2) sym.owner is inherited by the correct package object class + // We try to establish 1) by inspecting the owners directly, and then we try + // to rule out 2), and only if both those fail do we resort to looking in the info. + !sym.isPackage && (sym.owner ne NoSymbol) && ( + if (sym.owner.isPackageObjectClass) + sym.owner.owner == pkgClass + else + !sym.owner.isPackageClass && matchesInfo + ) + ) + + // An overloaded symbol might not have the expected owner! + // The alternatives must be inspected directly. + pkgClass.isPackageClass && ( + if (sym.isOverloaded) + sym.alternatives forall (isInPackageObject(_, pkg)) + else + inPackageObject(sym) + ) + } + + /** Find the symbol of a simple name starting from this context. + * All names are filtered through the "qualifies" predicate, + * the search continuing as long as no qualifying name is found. + */ + def lookupSymbol(name: Name, qualifies: Symbol => Boolean): NameLookup = { + var lookupError: NameLookup = null // set to non-null if a definite error is encountered + var inaccessible: NameLookup = null // records inaccessible symbol for error reporting in case none is found + var defSym: Symbol = NoSymbol // the directly found symbol + var pre: Type = NoPrefix // the prefix type of defSym, if a class member + var cx: Context = this // the context under consideration + var symbolDepth: Int = -1 // the depth of the directly found symbol + + def finish(qual: Tree, sym: Symbol): NameLookup = ( + if (lookupError ne null) lookupError + else sym match { + case NoSymbol if inaccessible ne null => inaccessible + case NoSymbol => LookupNotFound + case _ => LookupSucceeded(qual, sym) + } + ) + def isPackageOwnedInDifferentUnit(s: Symbol) = ( + s.isDefinedInPackage && ( + !currentRun.compiles(s) + || unit.exists && s.sourceFile != unit.source.file + ) + ) + def requiresQualifier(s: Symbol) = ( + s.owner.isClass + && !s.owner.isPackageClass + && !s.isTypeParameterOrSkolem + ) + def lookupInPrefix(name: Name) = pre member name filter qualifies + def accessibleInPrefix(s: Symbol) = isAccessible(s, pre, superAccess = false) + + def searchPrefix = { + cx = cx.enclClass + val found0 = lookupInPrefix(name) + val found1 = found0 filter accessibleInPrefix + if (found0.exists && !found1.exists && inaccessible == null) + inaccessible = LookupInaccessible(found0, analyzer.lastAccessCheckDetails) + + found1 + } + // cx.scope eq null arises during FixInvalidSyms in Duplicators + while (defSym == NoSymbol && (cx ne NoContext) && (cx.scope ne null)) { + pre = cx.enclClass.prefix + val entries = (cx.scope lookupUnshadowedEntries name filter (e => qualifies(e.sym))).toList + defSym = entries match { + case Nil => searchPrefix + case hd :: tl => + // we have a winner: record the symbol depth + symbolDepth = (cx.depth - cx.scope.nestingLevel) + hd.depth + if (tl.isEmpty) hd.sym + else logResult(s"!!! lookup overloaded")(cx.owner.newOverloaded(pre, entries map (_.sym))) + } + if (!defSym.exists) + cx = cx.outer // push further outward + } + if (symbolDepth < 0) + symbolDepth = cx.depth + + var impSym: Symbol = NoSymbol + var imports = Context.this.imports + def imp1 = imports.head + def imp2 = imports.tail.head + def sameDepth = imp1.depth == imp2.depth + def imp1Explicit = imp1 isExplicitImport name + def imp2Explicit = imp2 isExplicitImport name + + def lookupImport(imp: ImportInfo, requireExplicit: Boolean) = + importedAccessibleSymbol(imp, name, requireExplicit) filter qualifies + + while (!impSym.exists && imports.nonEmpty && imp1.depth > symbolDepth) { + impSym = lookupImport(imp1, requireExplicit = false) + if (!impSym.exists) + imports = imports.tail + } + + if (defSym.exists && impSym.exists) { + // imported symbols take precedence over package-owned symbols in different compilation units. + if (isPackageOwnedInDifferentUnit(defSym)) + defSym = NoSymbol + // Defined symbols take precedence over erroneous imports. + else if (impSym.isError || impSym.name == nme.CONSTRUCTOR) + impSym = NoSymbol + // Otherwise they are irreconcilably ambiguous + else + return ambiguousDefnAndImport(defSym.owner, imp1) + } + + // At this point only one or the other of defSym and impSym might be set. + if (defSym.exists) { + if (requiresQualifier(defSym)) + finish(gen.mkAttributedQualifier(pre), defSym) + else + finish(EmptyTree, defSym) + } + else if (impSym.exists) { + // We continue walking down the imports as long as the tail is non-empty, which gives us: + // imports == imp1 :: imp2 :: _ + // And at least one of the following is true: + // - imp1 and imp2 are at the same depth + // - imp1 is a wildcard import, so all explicit imports from outer scopes must be checked + def keepLooking = ( + lookupError == null + && imports.tail.nonEmpty + && (sameDepth || !imp1Explicit) + ) + // If we find a competitor imp2 which imports the same name, possible outcomes are: + // + // - same depth, imp1 wild, imp2 explicit: imp2 wins, drop imp1 + // - same depth, imp1 wild, imp2 wild: ambiguity check + // - same depth, imp1 explicit, imp2 explicit: ambiguity check + // - differing depth, imp1 wild, imp2 explicit: ambiguity check + // - all others: imp1 wins, drop imp2 + // + // The ambiguity check is: if we can verify that both imports refer to the same + // symbol (e.g. import foo.X followed by import foo._) then we discard imp2 + // and proceed. If we cannot, issue an ambiguity error. + while (keepLooking) { + // If not at the same depth, limit the lookup to explicit imports. + // This is desirable from a performance standpoint (compare to + // filtering after the fact) but also necessary to keep the unused + // import check from being misled by symbol lookups which are not + // actually used. + val other = lookupImport(imp2, requireExplicit = !sameDepth) + def imp1wins = { imports = imp1 :: imports.tail.tail } + def imp2wins = { impSym = other ; imports = imports.tail } + + if (!other.exists) // imp1 wins; drop imp2 and continue. + imp1wins + else if (sameDepth && !imp1Explicit && imp2Explicit) // imp2 wins; drop imp1 and continue. + imp2wins + else resolveAmbiguousImport(name, imp1, imp2) match { + case Some(imp) => if (imp eq imp1) imp1wins else imp2wins + case _ => lookupError = ambiguousImports(imp1, imp2) + } + } + // optimization: don't write out package prefixes + finish(resetPos(imp1.qual.duplicate), impSym) + } + else finish(EmptyTree, NoSymbol) + } + /** * Find a symbol in this context or one of its outers. * @@ -702,11 +950,14 @@ trait Contexts { self: Analyzer => } //class Context class ImportInfo(val tree: Import, val depth: Int) { + def pos = tree.pos + def posOf(sel: ImportSelector) = tree.pos withPoint sel.namePos + /** The prefix expression */ def qual: Tree = tree.symbol.info match { case ImportType(expr) => expr - case ErrorType => tree setType NoType // fix for #2870 - case _ => throw new FatalError("symbol " + tree.symbol + " has bad type: " + tree.symbol.info) //debug + case ErrorType => tree setType NoType // fix for #2870 + case _ => throw new FatalError("symbol " + tree.symbol + " has bad type: " + tree.symbol.info) //debug } /** Is name imported explicitly, not via wildcard? */ @@ -715,25 +966,46 @@ trait Contexts { self: Analyzer => /** The symbol with name `name` imported from import clause `tree`. */ - def importedSymbol(name: Name): Symbol = { + def importedSymbol(name: Name): Symbol = importedSymbol(name, requireExplicit = false) + + private def recordUsage(sel: ImportSelector, result: Symbol) { + def posstr = pos.source.file.name + ":" + posOf(sel).safeLine + def resstr = if (tree.symbol.hasCompleteInfo) s"(qual=$qual, $result)" else s"(expr=${tree.expr}, ${result.fullLocationString})" + debuglog(s"In $this at $posstr, selector '${selectorString(sel)}' resolved to $resstr") + allUsedSelectors(this) += sel + } + + /** If requireExplicit is true, wildcard imports are not considered. */ + def importedSymbol(name: Name, requireExplicit: Boolean): Symbol = { var result: Symbol = NoSymbol var renamed = false var selectors = tree.selectors - while (selectors != Nil && result == NoSymbol) { - if (selectors.head.rename == name.toTermName) + def current = selectors.head + while (selectors.nonEmpty && result == NoSymbol) { + if (current.rename == name.toTermName) result = qual.tpe.nonLocalMember( // new to address #2733: consider only non-local members for imports - if (name.isTypeName) selectors.head.name.toTypeName else selectors.head.name) - else if (selectors.head.name == name.toTermName) + if (name.isTypeName) current.name.toTypeName else current.name) + else if (current.name == name.toTermName) renamed = true - else if (selectors.head.name == nme.WILDCARD && !renamed) + else if (current.name == nme.WILDCARD && !renamed && !requireExplicit) result = qual.tpe.nonLocalMember(name) - selectors = selectors.tail + + if (result == NoSymbol) + selectors = selectors.tail } + if (settings.lint.value && selectors.nonEmpty && result != NoSymbol && pos != NoPosition) + recordUsage(current, result) + result } + private def selectorString(s: ImportSelector): String = { + if (s.name == nme.WILDCARD && s.rename == null) "_" + else if (s.name == s.rename) "" + s.name + else s.name + " => " + s.rename + } def allImportedSymbols: Iterable[Symbol] = - qual.tpe.members flatMap (transformImport(tree.selectors, _)) + importableMembers(qual.tpe) flatMap (transformImport(tree.selectors, _)) private def transformImport(selectors: List[ImportSelector], sym: Symbol): List[Symbol] = selectors match { case List() => List() @@ -744,7 +1016,12 @@ trait Contexts { self: Analyzer => case _ :: rest => transformImport(rest, sym) } - override def toString() = tree.toString() + override def hashCode = tree.## + override def equals(other: Any) = other match { + case that: ImportInfo => (tree == that.tree) + case _ => false + } + override def toString = tree.toString } case class ImportType(expr: Tree) extends Type { diff --git a/src/compiler/scala/tools/nsc/typechecker/DestructureTypes.scala b/src/compiler/scala/tools/nsc/typechecker/DestructureTypes.scala index 3e249e57bb..73572bcae9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/DestructureTypes.scala +++ b/src/compiler/scala/tools/nsc/typechecker/DestructureTypes.scala @@ -6,8 +6,6 @@ package scala.tools.nsc package typechecker -import scala.language.implicitConversions - /** A generic means of breaking down types into their subcomponents. * Types are decomposed top down, and recognizable substructure is * dispatched via self-apparently named methods. Those methods can @@ -37,8 +35,6 @@ trait DestructureTypes { def wrapSequence(nodes: List[Node]): Node def wrapAtom[U](value: U): Node - private implicit def liftToTerm(name: String): TermName = newTermName(name) - private val openSymbols = scala.collection.mutable.Set[Symbol]() private def nodeList[T](elems: List[T], mkNode: T => Node): Node = @@ -68,15 +64,6 @@ trait DestructureTypes { }, tree.productPrefix ) - def wrapSymbol(label: String, sym: Symbol): Node = { - if (sym eq NoSymbol) wrapEmpty - else atom(label, sym) - } - def wrapInfo(sym: Symbol) = sym.info match { - case TypeBounds(lo, hi) => typeBounds(lo, hi) - case PolyType(tparams, restpe) => polyFunction(tparams, restpe) - case _ => wrapEmpty - } def wrapSymbolInfo(sym: Symbol): Node = { if ((sym eq NoSymbol) || openSymbols(sym)) wrapEmpty else { @@ -99,7 +86,6 @@ trait DestructureTypes { def constant(label: String, const: Constant): Node = atom(label, const) def scope(decls: Scope): Node = node("decls", scopeMemberList(decls.toList)) - def const[T](named: (String, T)): Node = constant(named._1, Constant(named._2)) def resultType(restpe: Type): Node = this("resultType", restpe) def typeParams(tps: List[Symbol]): Node = node("typeParams", symbolList(tps)) @@ -188,7 +174,6 @@ trait DestructureTypes { case AntiPolyType(pre, targs) => product(tp, prefix(pre), typeArgs(targs)) case ClassInfoType(parents, decls, clazz) => product(tp, parentList(parents), scope(decls), wrapAtom(clazz)) case ConstantType(const) => product(tp, constant("value", const)) - case DeBruijnIndex(level, index, args) => product(tp, const("level" -> level), const("index" -> index), typeArgs(args)) case OverloadedType(pre, alts) => product(tp, prefix(pre), node("alts", typeList(alts map pre.memberType))) case RefinedType(parents, decls) => product(tp, parentList(parents), scope(decls)) case SingleType(pre, sym) => product(tp, prefix(pre), wrapAtom(sym)) diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala index df753ba53c..9c23b8663c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala @@ -19,11 +19,6 @@ abstract class Duplicators extends Analyzer { import global._ import definitions.{ AnyRefClass, AnyValClass } - def retyped(context: Context, tree: Tree): Tree = { - resetClassOwners - (newBodyDuplicator(context)).typed(tree) - } - /** Retype the given tree in the given context. Use this method when retyping * a method in a different class. The typer will replace references to the this of * the old class with the new class, and map symbols through the given 'env'. The @@ -42,9 +37,6 @@ abstract class Duplicators extends Analyzer { protected def newBodyDuplicator(context: Context) = new BodyDuplicator(context) - def retypedMethod(context: Context, tree: Tree, oldThis: Symbol, newThis: Symbol): Tree = - (newBodyDuplicator(context)).retypedMethod(tree.asInstanceOf[DefDef], oldThis, newThis) - /** Return the special typer for duplicate method bodies. */ override def newTyper(context: Context): Typer = newBodyDuplicator(context) @@ -186,31 +178,6 @@ abstract class Duplicators extends Analyzer { stats.foreach(invalidate(_, owner)) } - def retypedMethod(ddef: DefDef, oldThis: Symbol, newThis: Symbol): Tree = { - oldClassOwner = oldThis - newClassOwner = newThis - invalidateAll(ddef.tparams) - mforeach(ddef.vparamss) { vdef => - invalidate(vdef) - vdef.tpe = null - } - ddef.symbol = NoSymbol - enterSym(context, ddef) - debuglog("remapping this of " + oldClassOwner + " to " + newClassOwner) - typed(ddef) - } - - private def inspectTpe(tpe: Type) = { - tpe match { - case MethodType(_, res) => - res + ", " + res.bounds.hi + ", " + (res.bounds.hi match { - case TypeRef(_, _, args) if (args.length > 0) => args(0) + ", " + args(0).bounds.hi - case _ => "non-tref: " + res.bounds.hi.getClass - }) - case _ => - } - } - /** Optionally cast this tree into some other type, if required. * Unless overridden, just returns the tree. */ @@ -233,7 +200,7 @@ abstract class Duplicators extends Analyzer { override def typed(tree: Tree, mode: Int, pt: Type): Tree = { debuglog("typing " + tree + ": " + tree.tpe + ", " + tree.getClass) val origtreesym = tree.symbol - if (tree.hasSymbol && tree.symbol != NoSymbol + if (tree.hasSymbolField && tree.symbol != NoSymbol && !tree.symbol.isLabel // labels cannot be retyped by the type checker as LabelDef has no ValDef/return type trees && invalidSyms.isDefinedAt(tree.symbol)) { debuglog("removed symbol " + tree.symbol) @@ -317,15 +284,39 @@ abstract class Duplicators extends Analyzer { super.typed(tree, mode, pt) case Select(th @ This(_), sel) if (oldClassOwner ne null) && (th.symbol == oldClassOwner) => - // log("selection on this, no type ascription required") - // we use the symbol name instead of the tree name because the symbol may have been - // name mangled, rendering the tree name obsolete - // log(tree) - val t = super.typedPos(tree.pos, mode, pt) { - Select(This(newClassOwner), tree.symbol.name) - } - // log("typed to: " + t + "; tpe = " + t.tpe + "; " + inspectTpe(t.tpe)) - t + // We use the symbol name instead of the tree name because the symbol + // may have been name mangled, rendering the tree name obsolete. + // ...but you can't just do a Select on a name because if the symbol is + // overloaded, you will crash in the backend. + val memberByName = newClassOwner.thisType.member(tree.symbol.name) + def nameSelection = Select(This(newClassOwner), tree.symbol.name) + val newTree = ( + if (memberByName.isOverloaded) { + // Find the types of the overload alternatives as seen in the new class, + // and filter the list down to those which match the old type (after + // fixing the old type so it is seen as if from the new class.) + val typeInNewClass = fixType(oldClassOwner.info memberType tree.symbol) + val alts = memberByName.alternatives + val memberTypes = alts map (newClassOwner.info memberType _) + val memberString = memberByName.defString + alts zip memberTypes filter (_._2 =:= typeInNewClass) match { + case ((alt, tpe)) :: Nil => + log(s"Arrested overloaded type in Duplicators, narrowing to ${alt.defStringSeenAs(tpe)}\n Overload was: $memberString") + Select(This(newClassOwner), alt) + case xs => + alts filter (alt => (alt.paramss corresponds tree.symbol.paramss)(_.size == _.size)) match { + case alt :: Nil => + log(s"Resorted to parameter list arity to disambiguate to $alt\n Overload was: $memberString") + Select(This(newClassOwner), alt) + case _ => + log(s"Could not disambiguate $memberTypes. Attempting name-based selection, but we may crash later.") + nameSelection + } + } + } + else nameSelection + ) + super.typed(atPos(tree.pos)(newTree), mode, pt) case This(_) if (oldClassOwner ne null) && (tree.symbol == oldClassOwner) => // val tree1 = Typed(This(newClassOwner), TypeTree(fixType(tree.tpe.widen))) @@ -379,7 +370,7 @@ abstract class Duplicators extends Analyzer { case _ => debuglog("Duplicators default case: " + tree.summaryString) debuglog(" ---> " + tree) - if (tree.hasSymbol && tree.symbol != NoSymbol && (tree.symbol.owner == definitions.AnyClass)) { + if (tree.hasSymbolField && tree.symbol != NoSymbol && (tree.symbol.owner == definitions.AnyClass)) { tree.symbol = NoSymbol // maybe we can find a more specific member in a subclass of Any (see AnyVal members, like ==) } val ntree = castType(tree, pt) diff --git a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala index bbba7e0435..2806d7b2d9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala +++ b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala @@ -33,7 +33,7 @@ trait EtaExpansion { self: Analyzer => } /** <p> - * Expand partial function applications of type <code>type</code>. + * Expand partial function applications of type `type`. * </p><pre> * p.f(es_1)...(es_n) * ==> { @@ -56,11 +56,8 @@ trait EtaExpansion { self: Analyzer => } val defs = new ListBuffer[Tree] - /** Append to <code>defs</code> value definitions for all non-stable - * subexpressions of the function application <code>tree</code>. - * - * @param tree ... - * @return ... + /** Append to `defs` value definitions for all non-stable + * subexpressions of the function application `tree`. */ def liftoutPrefix(tree: Tree): Tree = { def liftout(tree: Tree, byName: Boolean): Tree = @@ -118,7 +115,7 @@ trait EtaExpansion { self: Analyzer => val origTpe = sym.tpe val isRepeated = definitions.isRepeatedParamType(origTpe) // SI-4176 Don't leak A* in eta-expanded function types. See t4176b.scala - val droppedStarTpe = if (settings.etaExpandKeepsStar.value) origTpe else dropRepeatedParamType(origTpe) + val droppedStarTpe = if (settings.etaExpandKeepsStar.value) origTpe else dropIllegalStarTypes(origTpe) val valDef = ValDef(Modifiers(SYNTHETIC | PARAM), sym.name.toTermName, TypeTree(droppedStarTpe), EmptyTree) (valDef, isRepeated) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index fc10f68454..739e28bf0c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -30,7 +30,7 @@ trait Implicits { import global._ import definitions._ import ImplicitsStats._ - import typeDebug.{ ptTree, ptBlock, ptLine } + import typeDebug.{ ptBlock, ptLine } import global.typer.{ printTyping, deindentTyping, indentTyping, printInference } def inferImplicit(tree: Tree, pt: Type, reportAmbiguous: Boolean, isView: Boolean, context: Context): SearchResult = @@ -82,7 +82,7 @@ trait Implicits { val result = new ImplicitSearch(tree, pt, isView, implicitSearchContext, pos).bestImplicit if (saveAmbiguousDivergent && implicitSearchContext.hasErrors) { context.updateBuffer(implicitSearchContext.errBuffer.filter(err => err.kind == ErrorKinds.Ambiguous || err.kind == ErrorKinds.Divergent)) - debugwarn("update buffer: " + implicitSearchContext.errBuffer) + debuglog("update buffer: " + implicitSearchContext.errBuffer) } printInference("[infer implicit] inferred " + result) context.undetparams = context.undetparams filterNot result.subst.from.contains @@ -132,7 +132,7 @@ trait Implicits { } /* Map a polytype to one in which all type parameters and argument-dependent types are replaced by wildcards. - * Consider `implicit def b(implicit x: A): x.T = error("")`. We need to approximate DebruijnIndex types + * Consider `implicit def b(implicit x: A): x.T = error("")`. We need to approximate debruijn index types * when checking whether `b` is a valid implicit, as we haven't even searched a value for the implicit arg `x`, * so we have to approximate (otherwise it is excluded a priori). */ @@ -233,10 +233,6 @@ trait Implicits { object HasMember { private val hasMemberCache = perRunCaches.newMap[Name, Type]() def apply(name: Name): Type = hasMemberCache.getOrElseUpdate(name, memberWildcardType(name, WildcardType)) - def unapply(pt: Type): Option[Name] = pt match { - case RefinedType(List(WildcardType), Scope(sym)) if sym.tpe == WildcardType => Some(sym.name) - case _ => None - } } /** An extractor for types of the form ? { name: (? >: argtpe <: Any*)restp } @@ -664,10 +660,6 @@ trait Implicits { // duplicating the code here, but this is probably a // hotspot (and you can't just call typed, need to force // re-typecheck) - // TODO: the return tree is ignored. This seems to make - // no difference, but it's bad practice regardless. - - val checked = itree2 match { case TypeApply(fun, args) => typedTypeApply(itree2, EXPRmode, fun, args) case Apply(TypeApply(fun, args), _) => typedTypeApply(itree2, EXPRmode, fun, args) // t2421c @@ -677,7 +669,7 @@ trait Implicits { if (context.hasErrors) fail("typing TypeApply reported errors for the implicit tree: " + context.errBuffer.head.errMsg) else { - val result = new SearchResult(itree2, subst) + val result = new SearchResult(checked, subst) if (Statistics.canEnable) Statistics.incCounter(foundImplicits) printInference("[success] found %s for pt %s".format(result, ptInstantiated)) result @@ -997,7 +989,7 @@ trait Implicits { case Some(imap) => imap case None => val result = new InfoMap - getClassParts(sym.tpe)(result, new mutable.HashSet(), pending + sym) + getClassParts(sym.tpeHK)(result, new mutable.HashSet(), pending + sym) infoMapCache(sym) = result result } @@ -1205,7 +1197,7 @@ trait Implicits { } ) // todo. migrate hardcoded materialization in Implicits to corresponding implicit macros - var materializer = atPos(pos.focus)(gen.mkMethodCall(TagMaterializers(tagClass), List(tp), if (prefix != EmptyTree) List(prefix) else List())) + val materializer = atPos(pos.focus)(gen.mkMethodCall(TagMaterializers(tagClass), List(tp), if (prefix != EmptyTree) List(prefix) else List())) if (settings.XlogImplicits.value) println("materializing requested %s.%s[%s] using %s".format(pre, tagClass.name, tp, materializer)) if (context.macrosEnabled) success(materializer) // don't call `failure` here. if macros are disabled, we just fail silently @@ -1472,7 +1464,6 @@ trait Implicits { interpolate(msg, Map((typeParamNames zip typeArgs): _*)) // TODO: give access to the name and type of the implicit argument, etc? def validate: Option[String] = { - import scala.util.matching.Regex; import scala.collection.breakOut // is there a shorter way to avoid the intermediate toList? val refs = """\$\{([^}]+)\}""".r.findAllIn(msg).matchData.map(_ group 1).toSet val decls = typeParamNames.toSet @@ -1498,9 +1489,7 @@ object ImplicitsStats { val subtypeImpl = Statistics.newSubCounter(" of which in implicit", subtypeCount) val findMemberImpl = Statistics.newSubCounter(" of which in implicit", findMemberCount) val subtypeAppInfos = Statistics.newSubCounter(" of which in app impl", subtypeCount) - val subtypeImprovCount = Statistics.newSubCounter(" of which in improves", subtypeCount) val implicitSearchCount = Statistics.newCounter ("#implicit searches", "typer") - val triedImplicits = Statistics.newSubCounter(" #tried", implicitSearchCount) val plausiblyCompatibleImplicits = Statistics.newSubCounter(" #plausibly compatible", implicitSearchCount) val matchingImplicits = Statistics.newSubCounter(" #matching", implicitSearchCount) diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 5deed4ffee..be3c027259 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -6,11 +6,10 @@ package scala.tools.nsc package typechecker -import scala.collection.{ mutable, immutable } +import scala.collection.immutable import scala.collection.mutable.ListBuffer import scala.util.control.ControlThrowable import symtab.Flags._ -import scala.annotation.tailrec /** This trait ... * @@ -30,8 +29,8 @@ trait Infer extends Checkable { private def assertNonCyclic(tvar: TypeVar) = assert(tvar.constr.inst != tvar, tvar.origin) - /** The formal parameter types corresponding to <code>formals</code>. - * If <code>formals</code> has a repeated last parameter, a list of + /** The formal parameter types corresponding to `formals`. + * If `formals` has a repeated last parameter, a list of * (nargs - params.length + 1) copies of its type is returned. * By-name types are replaced with their underlying type. * @@ -49,6 +48,24 @@ trait Infer extends Checkable { } else formals1 } + /** Sorts the alternatives according to the given comparison function. + * Returns a list containing the best alternative as well as any which + * the best fails to improve upon. + */ + private def bestAlternatives(alternatives: List[Symbol])(isBetter: (Symbol, Symbol) => Boolean): List[Symbol] = { + def improves(sym1: Symbol, sym2: Symbol) = ( + sym2 == NoSymbol + || sym2.isError + || sym2.hasAnnotation(BridgeClass) + || isBetter(sym1, sym2) + ) + + alternatives sortWith improves match { + case best :: rest if rest.nonEmpty => best :: rest.filterNot(alt => improves(best, alt)) + case bests => bests + } + } + /** Returns `(formals, formalsExpanded)` where `formalsExpanded` are the expected types * for the `nbSubPats` sub-patterns of an extractor pattern, of which the corresponding * unapply[Seq] call is assumed to have result type `resTp`. @@ -112,21 +129,7 @@ trait Infer extends Checkable { else (formals, formalsExpanded) } - def actualTypes(actuals: List[Type], nformals: Int): List[Type] = - if (nformals == 1 && !hasLength(actuals, 1)) - List(if (actuals.isEmpty) UnitClass.tpe else tupleType(actuals)) - else actuals - - def actualArgs(pos: Position, actuals: List[Tree], nformals: Int): List[Tree] = { - val inRange = nformals == 1 && !hasLength(actuals, 1) && actuals.lengthCompare(MaxTupleArity) <= 0 - if (inRange && !phase.erasedTypes) List(atPos(pos)(gen.mkTuple(actuals))) - else actuals - } - /** A fresh type variable with given type parameter as origin. - * - * @param tparam ... - * @return ... */ def freshVar(tparam: Symbol): TypeVar = TypeVar(tparam) @@ -149,14 +152,13 @@ trait Infer extends Checkable { case tv @ TypeVar(origin, constr) if !tv.untouchable => if (constr.inst == NoType) { throw new DeferredNoInstance(() => - "no unique instantiation of type variable " + origin + " could be found") + s"no unique instantiation of type variable $origin could be found") } else if (excludedVars(tv)) { throw new NoInstance("cyclic instantiation") } else { excludedVars += tv - val res = apply(constr.inst) - excludedVars -= tv - res + try apply(constr.inst) + finally excludedVars -= tv } case _ => mapOver(tp) @@ -164,9 +166,6 @@ trait Infer extends Checkable { } /** Is type fully defined, i.e. no embedded anytypes or wildcards in it? - * - * @param tp ... - * @return ... */ private[typechecker] def isFullyDefined(tp: Type): Boolean = tp match { case WildcardType | BoundedWildcardType(_) | NoType => @@ -270,7 +269,7 @@ trait Infer extends Checkable { def errorValue = if (context.reportErrors) context.owner.newErrorValue(name) else stdErrorValue def errorSym = if (tree.isType) errorClass else errorValue - if (tree.hasSymbol) + if (tree.hasSymbolField) tree setSymbol errorSym tree setType ErrorType @@ -296,8 +295,8 @@ trait Infer extends Checkable { /* -- Tests & Checks---------------------------------------------------- */ - /** Check that <code>sym</code> is defined and accessible as a member of - * tree <code>site</code> with type <code>pre</code> in current context. + /** Check that `sym` is defined and accessible as a member of + * tree `site` with type `pre` in current context. * * Note: pre is not refchecked -- moreover, refchecking the resulting tree may not refcheck pre, * since pre may not occur in its type (callers should wrap the result in a TypeTreeWithDeferredRefCheck) @@ -306,7 +305,6 @@ trait Infer extends Checkable { if (sym.isError) { tree setSymbol sym setType ErrorType } else { - val topClass = context.owner.enclosingTopLevelClass if (context.unit.exists) context.unit.depends += sym.enclosingTopLevelClass @@ -404,8 +402,19 @@ trait Infer extends Checkable { /** Like weakly compatible but don't apply any implicit conversions yet. * Used when comparing the result type of a method with its prototype. + * * [Martin] I think Infer is also created by Erasure, with the default * implementation of isCoercible + * [Paulp] (Assuming the above must refer to my comment on isCoercible) + * Nope, I examined every occurrence of Inferencer in trunk. It + * appears twice as a self-type, once at its definition, and once + * where it is instantiated in Typers. There are no others. + * + % ack -A0 -B0 --no-filename '\bInferencer\b' src + self: Inferencer => + self: Inferencer => + class Inferencer(context: Context) extends InferencerContextErrors with InferCheckable { + val infer = new Inferencer(context0) { */ def isConservativelyCompatible(tp: Type, pt: Type): Boolean = context.withImplicitsDisabled(isWeaklyCompatible(tp, pt)) @@ -439,14 +448,9 @@ trait Infer extends Checkable { } /** Return inferred type arguments of polymorphic expression, given - * its type parameters and result type and a prototype <code>pt</code>. + * its type parameters and result type and a prototype `pt`. * If no minimal type variables exist that make the - * instantiated type a subtype of <code>pt</code>, return null. - * - * @param tparams ... - * @param restpe ... - * @param pt ... - * @return ... + * instantiated type a subtype of `pt`, return null. */ private def exprTypeArgs(tparams: List[Symbol], restpe: Type, pt: Type, useWeaklyCompatible: Boolean = false): (List[Type], List[TypeVar]) = { val tvars = tparams map freshVar @@ -473,18 +477,12 @@ trait Infer extends Checkable { /** Return inferred proto-type arguments of function, given * its type and value parameters and result type, and a - * prototype <code>pt</code> for the function result. + * prototype `pt` for the function result. * Type arguments need to be either determined precisely by * the prototype, or they are maximized, if they occur only covariantly * in the value parameter list. * If instantiation of a type parameter fails, * take WildcardType for the proto-type argument. - * - * @param tparams ... - * @param formals ... - * @param restype ... - * @param pt ... - * @return ... */ def protoTypeArgs(tparams: List[Symbol], formals: List[Type], restpe: Type, pt: Type): List[Type] = { @@ -566,7 +564,7 @@ trait Infer extends Checkable { * * Rewrite for repeated param types: Map T* entries to Seq[T]. * @return map from tparams to inferred arg, if inference was successful, tparams that map to None are considered left undetermined - * type parameters that are inferred as `scala.Nothing` and that are not covariant in <code>restpe</code> are taken to be undetermined + * type parameters that are inferred as `scala.Nothing` and that are not covariant in `restpe` are taken to be undetermined */ def adjustTypeArgs(tparams: List[Symbol], tvars: List[TypeVar], targs: List[Type], restpe: Type = WildcardType): AdjustedTypeArgs.Result = { val buf = AdjustedTypeArgs.Result.newBuilder[Symbol, Option[Type]] @@ -577,14 +575,14 @@ trait Infer extends Checkable { && (restpe.isWildcard || (varianceInType(restpe)(tparam) & COVARIANT) == 0) // don't retract covariant occurrences ) - // checks opt.virtPatmat directly so one need not run under -Xexperimental to use virtpatmat + // checks !settings.XoldPatmat.value directly so one need not run under -Xexperimental to use virtpatmat buf += ((tparam, if (retract) None else Some( if (targ.typeSymbol == RepeatedParamClass) targ.baseType(SeqClass) else if (targ.typeSymbol == JavaRepeatedParamClass) targ.baseType(ArrayClass) // this infers Foo.type instead of "object Foo" (see also widenIfNecessary) - else if (targ.typeSymbol.isModuleClass || ((opt.experimental || opt.virtPatmat) && tvar.constr.avoidWiden)) targ + else if (targ.typeSymbol.isModuleClass || ((settings.Xexperimental.value || !settings.XoldPatmat.value) && tvar.constr.avoidWiden)) targ else targ.widen ) )) @@ -594,7 +592,7 @@ trait Infer extends Checkable { /** Return inferred type arguments, given type parameters, formal parameters, * argument types, result type and expected result type. - * If this is not possible, throw a <code>NoInstance</code> exception. + * If this is not possible, throw a `NoInstance` exception. * Undetermined type arguments are represented by `definitions.NothingClass.tpe`. * No check that inferred parameters conform to their bounds is made here. * @@ -651,9 +649,57 @@ trait Infer extends Checkable { tvars, tparams, tparams map varianceInTypes(formals), false, lubDepth(formals) max lubDepth(argtpes) ) + // Can warn about inferring Any/AnyVal as long as they don't appear + // explicitly anywhere amongst the formal, argument, result, or expected type. + def canWarnAboutAny = !(pt :: restpe :: formals ::: argtpes exists (t => (t contains AnyClass) || (t contains AnyValClass))) + def argumentPosition(idx: Int): Position = context.tree match { + case x: ValOrDefDef => x.rhs match { + case Apply(fn, args) if idx < args.size => args(idx).pos + case _ => context.tree.pos + } + case _ => context.tree.pos + } + if (settings.warnInferAny.value && context.reportErrors && canWarnAboutAny) { + foreachWithIndex(targs) ((targ, idx) => + targ.typeSymbol match { + case sym @ (AnyClass | AnyValClass) => + context.unit.warning(argumentPosition(idx), s"a type was inferred to be `${sym.name}`; this may indicate a programming error.") + case _ => + } + ) + } adjustTypeArgs(tparams, tvars, targs, restpe) } + /** One must step carefully when assessing applicability due to + * complications from varargs, tuple-conversion, named arguments. + * This method is used to filter out inapplicable methods, + * its behavior slightly configurable based on what stage of + * overloading resolution we're at. + * + * This method has boolean parameters, which is usually suboptimal + * but I didn't work out a better way. They don't have defaults, + * and the method's scope is limited. + */ + private[typechecker] def isApplicableBasedOnArity(tpe: Type, argsCount: Int, varargsStar: Boolean, tuplingAllowed: Boolean): Boolean = followApply(tpe) match { + case OverloadedType(pre, alts) => + alts exists (alt => isApplicableBasedOnArity(pre memberType alt, argsCount, varargsStar, tuplingAllowed)) + case _ => + val paramsCount = tpe.params.length + val simpleMatch = paramsCount == argsCount + val varargsTarget = isVarArgsList(tpe.params) + def varargsMatch = varargsTarget && (paramsCount - 1) <= argsCount + def tuplingMatch = tuplingAllowed && eligibleForTupleConversion(paramsCount, argsCount, varargsTarget) + + // A varargs star call, e.g. (x, y:_*) can only match a varargs method + // with the same number of parameters. See SI-5859 for an example of what + // would fail were this not enforced before we arrived at isApplicable. + if (varargsStar) + varargsTarget && simpleMatch + else + simpleMatch || varargsMatch || tuplingMatch + } + private[typechecker] def followApply(tp: Type): Type = tp match { case NullaryMethodType(restp) => val restp1 = followApply(restp) @@ -670,14 +716,6 @@ trait Infer extends Checkable { else OverloadedType(tp, appmeth.alternatives) } - def hasExactlyNumParams(tp: Type, n: Int): Boolean = tp match { - case OverloadedType(pre, alts) => - alts exists (alt => hasExactlyNumParams(pre.memberType(alt), n)) - case _ => - val len = tp.params.length - len == n || isVarArgsList(tp.params) && len <= n + 1 - } - /** * Verifies whether the named application is valid. The logic is very * similar to the one in NamesDefaults.removeNames. @@ -723,17 +761,54 @@ trait Infer extends Checkable { (argtpes1, argPos, namesOK) } - /** don't do a () to (()) conversion for methods whose second parameter - * is a varargs. This is a fairly kludgey way to address #3224. - * We'll probably find a better way to do this by identifying - * tupled and n-ary methods, but thiws is something for a future major revision. + /** True if the given parameter list can accept a tupled argument list, + * and the argument list can be tupled (based on its length.) + */ + def eligibleForTupleConversion(paramsCount: Int, argsCount: Int, varargsTarget: Boolean): Boolean = { + def canSendTuple = argsCount match { + case 0 => !varargsTarget // avoid () to (()) conversion - SI-3224 + case 1 => false // can't tuple a single argument + case n => n <= MaxTupleArity // <= 22 arguments + } + def canReceiveTuple = paramsCount match { + case 1 => true + case 2 => varargsTarget + case _ => false + } + canSendTuple && canReceiveTuple + } + def eligibleForTupleConversion(formals: List[Type], argsCount: Int): Boolean = formals match { + case p :: Nil => eligibleForTupleConversion(1, argsCount, varargsTarget = isScalaRepeatedParamType(p)) + case _ :: p :: Nil if isScalaRepeatedParamType(p) => eligibleForTupleConversion(2, argsCount, varargsTarget = true) + case _ => false + } + + /** The type of an argument list after being coerced to a tuple. + * @pre: the argument list is eligible for tuple conversion. */ - def isUnitForVarArgs(args: List[AnyRef], params: List[Symbol]): Boolean = - args.isEmpty && hasLength(params, 2) && isVarArgsList(params) + private def typeAfterTupleConversion(argtpes: List[Type]): Type = ( + if (argtpes.isEmpty) UnitClass.tpe // aka "Tuple0" + else tupleType(argtpes map { + case NamedType(name, tp) => UnitClass.tpe // not a named arg - only assignments here + case RepeatedType(tp) => tp // but probably shouldn't be tupling a call containing :_* + case tp => tp + }) + ) - /** Is there an instantiation of free type variables <code>undetparams</code> - * such that function type <code>ftpe</code> is applicable to - * <code>argtpes</code> and its result conform to <code>pt</code>? + /** If the argument list needs to be tupled for the parameter list, + * a list containing the type of the tuple. Otherwise, the original + * argument list. + */ + def tupleIfNecessary(formals: List[Type], argtpes: List[Type]): List[Type] = { + if (eligibleForTupleConversion(formals, argtpes.size)) + typeAfterTupleConversion(argtpes) :: Nil + else + argtpes + } + + /** Is there an instantiation of free type variables `undetparams` + * such that function type `ftpe` is applicable to + * `argtpes` and its result conform to `pt`? * * @param undetparams ... * @param ftpe the type of the function (often a MethodType) @@ -748,23 +823,16 @@ trait Infer extends Checkable { argtpes0: List[Type], pt: Type): Boolean = ftpe match { case OverloadedType(pre, alts) => - alts exists (alt => isApplicable(undetparams, pre.memberType(alt), argtpes0, pt)) + alts exists (alt => isApplicable(undetparams, pre memberType alt, argtpes0, pt)) case ExistentialType(tparams, qtpe) => isApplicable(undetparams, qtpe, argtpes0, pt) case mt @ MethodType(params, _) => - val formals = formalTypes(mt.paramTypes, argtpes0.length, removeByName = false) - - def tryTupleApply: Boolean = { - // if 1 formal, 1 argtpe (a tuple), otherwise unmodified argtpes0 - val tupleArgTpes = actualTypes(argtpes0 map { - // no assignment is treated as named argument here - case NamedType(name, tp) => UnitClass.tpe - case tp => tp - }, formals.length) - - !sameLength(argtpes0, tupleArgTpes) && - !isUnitForVarArgs(argtpes0, params) && - isApplicable(undetparams, ftpe, tupleArgTpes, pt) + val argslen = argtpes0.length + val formals = formalTypes(mt.paramTypes, argslen, removeByName = false) + + def tryTupleApply = { + val tupled = tupleIfNecessary(mt.paramTypes, argtpes0) + (tupled ne argtpes0) && isApplicable(undetparams, ftpe, tupled, pt) } def typesCompatible(argtpes: List[Type]) = { val restpe = ftpe.resultType(argtpes) @@ -786,17 +854,16 @@ trait Infer extends Checkable { val lencmp = compareLengths(argtpes0, formals) if (lencmp > 0) tryTupleApply else if (lencmp == 0) { - if (!argtpes0.exists(_.isInstanceOf[NamedType])) { - // fast track if no named arguments are used + // fast track if no named arguments are used + if (!containsNamedType(argtpes0)) typesCompatible(argtpes0) - } else { // named arguments are used val (argtpes1, argPos, namesOK) = checkNames(argtpes0, params) // when using named application, the vararg param has to be specified exactly once - ( namesOK && (isIdentity(argPos) || sameLength(formals, params)) && - // nb. arguments and names are OK, check if types are compatible - typesCompatible(reorderArgs(argtpes1, argPos)) + ( namesOK + && (isIdentity(argPos) || sameLength(formals, params)) + && typesCompatible(reorderArgs(argtpes1, argPos)) // nb. arguments and names are OK, check if types are compatible ) } } @@ -840,17 +907,13 @@ trait Infer extends Checkable { } else res1 } - /** Is type <code>ftpe1</code> strictly more specific than type <code>ftpe2</code> + /** Is type `ftpe1` strictly more specific than type `ftpe2` * when both are alternatives in an overloaded function? * @see SLS (sec:overloading-resolution) - * - * @param ftpe1 ... - * @param ftpe2 ... - * @return ... */ def isAsSpecific(ftpe1: Type, ftpe2: Type): Boolean = ftpe1 match { case OverloadedType(pre, alts) => - alts exists (alt => isAsSpecific(pre.memberType(alt), ftpe2)) + alts exists (alt => isAsSpecific(pre memberType alt, ftpe2)) case et: ExistentialType => isAsSpecific(ftpe1.skolemizeExistential, ftpe2) //et.withTypeVars(isAsSpecific(_, ftpe2)) @@ -877,7 +940,7 @@ trait Infer extends Checkable { case _ => ftpe2 match { case OverloadedType(pre, alts) => - alts forall (alt => isAsSpecific(ftpe1, pre.memberType(alt))) + alts forall (alt => isAsSpecific(ftpe1, pre memberType alt)) case et: ExistentialType => et.withTypeVars(isAsSpecific(ftpe1, _)) case mt: MethodType => @@ -1089,25 +1152,20 @@ trait Infer extends Checkable { /** Substitute free type variables `undetparams` of polymorphic argument * expression `tree` to `targs`, Error if `targs` is null. - * - * @param tree ... - * @param undetparams ... - * @param targs ... - * @param pt ... */ - private def substExpr(tree: Tree, undetparams: List[Symbol], - targs: List[Type], pt: Type) { + private def substExpr(tree: Tree, undetparams: List[Symbol], targs: List[Type], pt: Type) { if (targs eq null) { if (!tree.tpe.isErroneous && !pt.isErroneous) PolymorphicExpressionInstantiationError(tree, undetparams, pt) - } else { + } + else { new TreeTypeSubstituter(undetparams, targs).traverse(tree) notifyUndetparamsInferred(undetparams, targs) } } - /** Substitute free type variables <code>undetparams</code> of application - * <code>fn(args)</code>, given prototype <code>pt</code>. + /** Substitute free type variables `undetparams` of application + * `fn(args)`, given prototype `pt`. * * @param fn fn: the function that needs to be instantiated. * @param undetparams the parameters that need to be determined @@ -1120,10 +1178,10 @@ trait Infer extends Checkable { args: List[Tree], pt0: Type): List[Symbol] = fn.tpe match { case mt @ MethodType(params0, _) => try { - val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0 - val formals = formalTypes(mt.paramTypes, args.length) - val argtpes = actualTypes(args map (x => elimAnonymousClass(x.tpe.deconst)), formals.length) - val restpe = fn.tpe.resultType(argtpes) + val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0 + val formals = formalTypes(mt.paramTypes, args.length) + val argtpes = tupleIfNecessary(formals, args map (x => elimAnonymousClass(x.tpe.deconst))) + val restpe = fn.tpe.resultType(argtpes) val AdjustedTypeArgs.AllArgsAndUndets(okparams, okargs, allargs, leftUndet) = methTypeArgs(undetparams, formals, restpe, argtpes, pt) @@ -1160,8 +1218,8 @@ trait Infer extends Checkable { def widen(tp: Type): Type = abstractTypesToBounds(tp) - /** Substitute free type variables <code>undetparams</code> of type constructor - * <code>tree</code> in pattern, given prototype <code>pt</code>. + /** Substitute free type variables `undetparams` of type constructor + * `tree` in pattern, given prototype `pt`. * * @param tree the constuctor that needs to be instantiated * @param undetparams the undetermined type parameters @@ -1228,17 +1286,20 @@ trait Infer extends Checkable { } } else None - (inferFor(pt) orElse inferForApproxPt) map { targs => - new TreeTypeSubstituter(undetparams, targs).traverse(tree) - notifyUndetparamsInferred(undetparams, targs) - } getOrElse { - debugwarn("failed inferConstructorInstance for "+ tree +" : "+ tree.tpe +" under "+ undetparams +" pt = "+ pt +(if(isFullyDefined(pt)) " (fully defined)" else " (not fully defined)")) - // if (settings.explaintypes.value) explainTypes(resTp.instantiateTypeParams(undetparams, tvars), pt) - ConstrInstantiationError(tree, resTp, pt) + val inferred = inferFor(pt) orElse inferForApproxPt + + inferred match { + case Some(targs) => + new TreeTypeSubstituter(undetparams, targs).traverse(tree) + notifyUndetparamsInferred(undetparams, targs) + case _ => + def full = if (isFullyDefined(pt)) "(fully defined)" else "(not fully defined)" + devWarning(s"failed inferConstructorInstance for $tree: ${tree.tpe} undet=$undetparams, pt=$pt $full") + // if (settings.explaintypes.value) explainTypes(resTp.instantiateTypeParams(undetparams, tvars), pt) + ConstrInstantiationError(tree, resTp, pt) } } - def instBounds(tvar: TypeVar): (Type, Type) = { val tparam = tvar.origin.typeSymbol val instType = toOrigin(tvar.constr.inst) @@ -1286,51 +1347,6 @@ trait Infer extends Checkable { } } - /** Does `tp` contain any types that cannot be checked at run-time (i.e., after erasure, will isInstanceOf[erased(tp)] imply conceptualIsInstanceOf[tp]?) - * we should find a way to ask erasure: hey, is `tp` going to make it through you with all of its isInstanceOf resolving powers intact? - * TODO: at the very least, reduce duplication wrt checkCheckable - */ - def containsUnchecked(tp: Type): Boolean = { - def check(tp: Type, bound: List[Symbol]): Boolean = { - def isSurroundingTypeParam(sym: Symbol) = { - val e = context.scope.lookupEntry(sym.name) - ( (e ne null) - && (e.sym == sym ) - && !e.sym.isTypeParameterOrSkolem - && (e.owner == context.scope) - ) - } - def isLocalBinding(sym: Symbol) = ( - sym.isAbstractType && ( - (bound contains sym) - || (sym.name == tpnme.WILDCARD) - || isSurroundingTypeParam(sym) - ) - ) - tp.normalize match { - case SingleType(pre, _) => - check(pre, bound) - case TypeRef(_, ArrayClass, arg :: _) => - check(arg, bound) - case tp @ TypeRef(pre, sym, args) => - ( (sym.isAbstractType && !isLocalBinding(sym)) - || (args exists (x => !isLocalBinding(x.typeSymbol))) - || check(pre, bound) - ) - // case RefinedType(_, decls) if decls.nonEmpty => - // patternWarning(tp, "refinement ") - case RefinedType(parents, _) => - parents exists (p => check(p, bound)) - case ExistentialType(quantified, tp1) => - check(tp1, bound ::: quantified) - case _ => - false - } - } - check(tp, Nil) - } - - /** Type intersection of simple type tp1 with general type tp2. * The result eliminates some redundancies. */ @@ -1469,52 +1485,30 @@ trait Infer extends Checkable { } */ - /** Assign <code>tree</code> the symbol and type of the alternative which - * matches prototype <code>pt</code>, if it exists. + /** Assign `tree` the symbol and type of the alternative which + * matches prototype `pt`, if it exists. * If several alternatives match `pt`, take parameterless one. * If no alternative matches `pt`, take the parameterless one anyway. */ def inferExprAlternative(tree: Tree, pt: Type) = tree.tpe match { case OverloadedType(pre, alts) => tryTwice { isSecondTry => - val alts0 = alts filter (alt => isWeaklyCompatible(pre.memberType(alt), pt)) - val noAlternatives = alts0.isEmpty - val alts1 = if (noAlternatives) alts else alts0 - - //println("trying "+alts1+(alts1 map (_.tpe))+(alts1 map (_.locationString))+" for "+pt) - def improves(sym1: Symbol, sym2: Symbol): Boolean = - sym2 == NoSymbol || sym2.hasAnnotation(BridgeClass) || - { val tp1 = pre.memberType(sym1) - val tp2 = pre.memberType(sym2) - (tp2 == ErrorType || - !global.typer.infer.isWeaklyCompatible(tp2, pt) && global.typer.infer.isWeaklyCompatible(tp1, pt) || - isStrictlyMoreSpecific(tp1, tp2, sym1, sym2)) } + val alts0 = alts filter (alt => isWeaklyCompatible(pre.memberType(alt), pt)) + val alts1 = if (alts0.isEmpty) alts else alts0 - val best = ((NoSymbol: Symbol) /: alts1) ((best, alt) => - if (improves(alt, best)) alt else best) + val bests = bestAlternatives(alts1) { (sym1, sym2) => + val tp1 = pre.memberType(sym1) + val tp2 = pre.memberType(sym2) - val competing = alts1 dropWhile (alt => best == alt || improves(best, alt)) - - if (best == NoSymbol) { - if (settings.debug.value) { - tree match { - case Select(qual, _) => - Console.println("qual: " + qual + ":" + qual.tpe + - " with decls " + qual.tpe.decls + - " with members " + qual.tpe.members + - " with members " + qual.tpe.member(newTermName("$minus"))) - case _ => - } - } - // todo: missing test case - NoBestExprAlternativeError(tree, pt, isSecondTry) - } else if (!competing.isEmpty) { - if (noAlternatives) NoBestExprAlternativeError(tree, pt, isSecondTry) - else if (!pt.isErroneous) AmbiguousExprAlternativeError(tree, pre, best, competing.head, pt, isSecondTry) - } else { -// val applicable = alts1 filter (alt => -// global.typer.infer.isWeaklyCompatible(pre.memberType(alt), pt)) -// checkNotShadowed(tree.pos, pre, best, applicable) - tree.setSymbol(best).setType(pre.memberType(best)) + ( tp2 == ErrorType + || (!isWeaklyCompatible(tp2, pt) && isWeaklyCompatible(tp1, pt)) + || isStrictlyMoreSpecific(tp1, tp2, sym1, sym2) + ) + } + // todo: missing test case for bests.isEmpty + bests match { + case best :: Nil => tree setSymbol best setType (pre memberType best) + case best :: competing :: _ if alts0.nonEmpty => if (!pt.isErroneous) AmbiguousExprAlternativeError(tree, pre, best, competing, pt, isSecondTry) + case _ => if (bests.isEmpty || alts0.isEmpty) NoBestExprAlternativeError(tree, pt, isSecondTry) } } } @@ -1533,48 +1527,47 @@ trait Infer extends Checkable { private def paramMatchesName(param: Symbol, name: Name) = param.name == name || param.deprecatedParamName.exists(_ == name) - // Check the first parameter list the same way. - private def methodMatchesName(method: Symbol, name: Name) = method.paramss match { - case ps :: _ => ps exists (p => paramMatchesName(p, name)) - case _ => false + private def containsNamedType(argtpes: List[Type]): Boolean = argtpes match { + case Nil => false + case NamedType(_, _) :: _ => true + case _ :: rest => containsNamedType(rest) } - - private def resolveOverloadedMethod(argtpes: List[Type], eligible: List[Symbol]) = { + private def namesOfNamedArguments(argtpes: List[Type]) = + argtpes collect { case NamedType(name, _) => name } + + /** Given a list of argument types and eligible method overloads, whittle the + * list down to the methods which should be considered for specificity + * testing, taking into account here: + * - named arguments at the call site (keep only methods with name-matching parameters) + * - if multiple methods are eligible, drop any methods which take default arguments + * - drop any where arity cannot match under any conditions (allowing for + * overloaded applies, varargs, and tupling conversions) + * This method is conservative; it can tolerate some varieties of false positive, + * but no false negatives. + * + * @param eligible the overloaded method symbols + * @param argtpes the argument types at the call site + * @param varargsStar true if the call site has a `: _*` attached to the last argument + */ + private def overloadsToConsiderBySpecificity(eligible: List[Symbol], argtpes: List[Type], varargsStar: Boolean): List[Symbol] = { // If there are any foo=bar style arguments, and any of the overloaded // methods has a parameter named `foo`, then only those methods are considered. - val namesOfArgs = argtpes collect { case NamedType(name, _) => name } - val namesMatch = ( - if (namesOfArgs.isEmpty) Nil - else eligible filter { m => - namesOfArgs forall { name => - methodMatchesName(m, name) - } - } - ) - - if (namesMatch.nonEmpty) namesMatch - else if (eligible.isEmpty || eligible.tail.isEmpty) eligible - else eligible filter { alt => - // for functional values, the `apply` method might be overloaded - val mtypes = followApply(alt.tpe) match { - case OverloadedType(_, alts) => alts map (_.tpe) - case t => t :: Nil - } - // Drop those that use a default; keep those that use vararg/tupling conversion. - mtypes exists (t => - !t.typeSymbol.hasDefaultFlag && { - compareLengths(t.params, argtpes) < 0 || // tupling (*) - hasExactlyNumParams(t, argtpes.length) // same nb or vararg - } - ) - // (*) more arguments than parameters, but still applicable: tupling conversion works. - // todo: should not return "false" when paramTypes = (Unit) no argument is given - // (tupling would work) + val namesMatch = namesOfNamedArguments(argtpes) match { + case Nil => Nil + case names => eligible filter (m => names forall (name => m.info.params exists (p => paramMatchesName(p, name)))) } + if (namesMatch.nonEmpty) + namesMatch + else if (eligible.isEmpty || eligible.tail.isEmpty) + eligible + else + eligible filter (alt => + !alt.hasDefault && isApplicableBasedOnArity(alt.tpe, argtpes.length, varargsStar, tuplingAllowed = true) + ) } - /** Assign <code>tree</code> the type of an alternative which is applicable - * to <code>argtpes</code>, and whose result type is compatible with `pt`. + /** Assign `tree` the type of an alternative which is applicable + * to `argtpes`, and whose result type is compatible with `pt`. * If several applicable alternatives exist, drop the alternatives which use * default arguments, then select the most specialized one. * If no applicable alternative exists, and pt != WildcardType, try again @@ -1586,49 +1579,42 @@ trait Infer extends Checkable { * of some NamedType does not exist in an alternative's parameter names, * the type is replaces by `Unit`, i.e. the argument is treated as an * assignment expression. + * + * @pre tree.tpe is an OverloadedType. */ - def inferMethodAlternative(tree: Tree, undetparams: List[Symbol], - argtpes: List[Type], pt0: Type, varArgsOnly: Boolean = false, lastInferAttempt: Boolean = true): Unit = tree.tpe match { - case OverloadedType(pre, alts) => - val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0 - tryTwice { isSecondTry => - debuglog("infer method alt "+ tree.symbol +" with alternatives "+ - (alts map pre.memberType) +", argtpes = "+ argtpes +", pt = "+ pt) - - val applicable = resolveOverloadedMethod(argtpes, { - alts filter { alt => - inSilentMode(context)(isApplicable(undetparams, followApply(pre.memberType(alt)), argtpes, pt)) && - (!varArgsOnly || isVarArgsList(alt.tpe.params)) - } - }) - - def improves(sym1: Symbol, sym2: Symbol) = { - // util.trace("improve "+sym1+sym1.locationString+" on "+sym2+sym2.locationString) - sym2 == NoSymbol || sym2.isError || sym2.hasAnnotation(BridgeClass) || - isStrictlyMoreSpecific(followApply(pre.memberType(sym1)), - followApply(pre.memberType(sym2)), sym1, sym2) - } - - val best = ((NoSymbol: Symbol) /: applicable) ((best, alt) => - if (improves(alt, best)) alt else best) - val competing = applicable.dropWhile(alt => best == alt || improves(best, alt)) - if (best == NoSymbol) { - if (pt == WildcardType) NoBestMethodAlternativeError(tree, argtpes, pt, isSecondTry && lastInferAttempt) - else inferMethodAlternative(tree, undetparams, argtpes, WildcardType, lastInferAttempt = isSecondTry) - } else if (!competing.isEmpty) { - AmbiguousMethodAlternativeError(tree, pre, best, competing.head, argtpes, pt, isSecondTry && lastInferAttempt) - } else { -// checkNotShadowed(tree.pos, pre, best, applicable) - tree.setSymbol(best).setType(pre.memberType(best)) - } + def inferMethodAlternative(tree: Tree, undetparams: List[Symbol], argtpes0: List[Type], pt0: Type): Unit = { + val OverloadedType(pre, alts) = tree.tpe + var varargsStar = false + val argtpes = argtpes0 mapConserve { + case RepeatedType(tp) => varargsStar = true ; tp + case tp => tp + } + def followType(sym: Symbol) = followApply(pre memberType sym) + def bestForExpectedType(pt: Type, isLastTry: Boolean): Unit = { + val applicable0 = alts filter (alt => inSilentMode(context)(isApplicable(undetparams, followType(alt), argtpes, pt))) + val applicable = overloadsToConsiderBySpecificity(applicable0, argtpes, varargsStar) + val ranked = bestAlternatives(applicable)((sym1, sym2) => + isStrictlyMoreSpecific(followType(sym1), followType(sym2), sym1, sym2) + ) + ranked match { + case best :: competing :: _ => AmbiguousMethodAlternativeError(tree, pre, best, competing, argtpes, pt, isLastTry) // ambiguous + case best :: Nil => tree setSymbol best setType (pre memberType best) // success + case Nil if pt eq WildcardType => NoBestMethodAlternativeError(tree, argtpes, pt, isLastTry) // failed + case Nil => bestForExpectedType(WildcardType, isLastTry) // failed, but retry with WildcardType } - case _ => + } + // This potentially makes up to four attempts: tryTwice may execute + // with and without views enabled, and bestForExpectedType will try again + // with pt = WildcardType if it fails with pt != WildcardType. + tryTwice { isLastTry => + val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0 + debuglog(s"infer method alt ${tree.symbol} with alternatives ${alts map pre.memberType} argtpes=$argtpes pt=$pt") + bestForExpectedType(pt, isLastTry) + } } /** Try inference twice, once without views and once with views, * unless views are already disabled. - * - * @param infer ... */ def tryTwice(infer: Boolean => Unit): Unit = { if (context.implicitsEnabled) { @@ -1663,12 +1649,9 @@ trait Infer extends Checkable { else infer(true) } - /** Assign <code>tree</code> the type of all polymorphic alternatives - * with <code>nparams</code> as the number of type parameters, if it exists. + /** Assign `tree` the type of all polymorphic alternatives + * with `nparams` as the number of type parameters, if it exists. * If no such polymorphic alternative exist, error. - * - * @param tree ... - * @param nparams ... */ def inferPolyAlternatives(tree: Tree, argtypes: List[Type]): Unit = { val OverloadedType(pre, alts) = tree.tpe diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index b20a9ea626..e40d978e6d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -3,15 +3,10 @@ package typechecker import symtab.Flags._ import scala.tools.nsc.util._ -import scala.tools.nsc.util.ClassPath._ import scala.reflect.runtime.ReflectionUtils import scala.collection.mutable.ListBuffer -import scala.compat.Platform.EOL import scala.reflect.internal.util.Statistics import scala.reflect.macros.util._ -import java.lang.{Class => jClass} -import java.lang.reflect.{Array => jArray, Method => jMethod} -import scala.reflect.internal.util.Collections._ import scala.util.control.ControlThrowable import scala.reflect.macros.runtime.AbortMacroException @@ -293,53 +288,51 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { private def macroImplSig(macroDef: Symbol, tparams: List[TypeDef], vparamss: List[List[ValDef]], retTpe: Type): (List[List[Symbol]], Type) = { // had to move method's body to an object because of the recursive dependencies between sigma and param object SigGenerator { - def sigma(tpe: Type): Type = { - class SigmaTypeMap extends TypeMap { - def apply(tp: Type): Type = tp match { - case TypeRef(pre, sym, args) => - val pre1 = pre match { - case ThisType(sym) if sym == macroDef.owner => - SingleType(SingleType(SingleType(NoPrefix, ctxParam), MacroContextPrefix), ExprValue) - case SingleType(NoPrefix, sym) => - mfind(vparamss)(_.symbol == sym) match { - case Some(macroDefParam) => SingleType(SingleType(NoPrefix, param(macroDefParam)), ExprValue) - case _ => pre - } - case _ => - pre - } - TypeRef(pre1, sym, args map mapOver) - case _ => - mapOver(tp) - } + def WeakTagClass = getMember(MacroContextClass, tpnme.WeakTypeTag) + def ExprClass = getMember(MacroContextClass, tpnme.Expr) + val cache = scala.collection.mutable.Map[Symbol, Symbol]() + val ctxParam = makeParam(nme.macroContext, macroDef.pos, MacroContextClass.tpe, SYNTHETIC) + val paramss = List(ctxParam) :: mmap(vparamss)(param) + val implReturnType = typeRef(singleType(NoPrefix, ctxParam), ExprClass, List(sigma(retTpe))) + + object SigmaTypeMap extends TypeMap { + def mapPrefix(pre: Type) = pre match { + case ThisType(sym) if sym == macroDef.owner => + singleType(singleType(singleType(NoPrefix, ctxParam), MacroContextPrefix), ExprValue) + case SingleType(NoPrefix, sym) => + mfind(vparamss)(_.symbol == sym).fold(pre)(p => singleType(singleType(NoPrefix, param(p)), ExprValue)) + case _ => + mapOver(pre) + } + def apply(tp: Type): Type = tp match { + case TypeRef(pre, sym, args) => + val pre1 = mapPrefix(pre) + val args1 = mapOverArgs(args, sym.typeParams) + if ((pre eq pre1) && (args eq args1)) tp + else typeRef(pre1, sym, args1) + case _ => + mapOver(tp) } - - new SigmaTypeMap() apply tpe } + def sigma(tpe: Type): Type = SigmaTypeMap(tpe) - def makeParam(name: Name, pos: Position, tpe: Type, flags: Long = 0L) = + def makeParam(name: Name, pos: Position, tpe: Type, flags: Long) = macroDef.newValueParameter(name, pos, flags) setInfo tpe - val ctxParam = makeParam(nme.macroContext, macroDef.pos, MacroContextClass.tpe, SYNTHETIC) - def implType(isType: Boolean, origTpe: Type): Type = + def implType(isType: Boolean, origTpe: Type): Type = { + def tsym = if (isType) WeakTagClass else ExprClass + def targ = origTpe.typeArgs.headOption getOrElse NoType + if (isRepeatedParamType(origTpe)) - appliedType( - RepeatedParamClass.typeConstructor, - List(implType(isType, sigma(origTpe.typeArgs.head)))) - else { - val tsym = getMember(MacroContextClass, if (isType) tpnme.WeakTypeTag else tpnme.Expr) + scalaRepeatedType(implType(isType, sigma(targ))) + else typeRef(singleType(NoPrefix, ctxParam), tsym, List(sigma(origTpe))) - } - val paramCache = scala.collection.mutable.Map[Symbol, Symbol]() - def param(tree: Tree): Symbol = - paramCache.getOrElseUpdate(tree.symbol, { + } + def param(tree: Tree): Symbol = ( + cache.getOrElseUpdate(tree.symbol, { val sym = tree.symbol - val sigParam = makeParam(sym.name, sym.pos, implType(sym.isType, sym.tpe)) - if (sym.isSynthetic) sigParam.flags |= SYNTHETIC - sigParam + makeParam(sym.name, sym.pos, implType(sym.isType, sym.tpe), sym getFlag SYNTHETIC) }) - - val paramss = List(ctxParam) :: mmap(vparamss)(param) - val implRetTpe = typeRef(singleType(NoPrefix, ctxParam), getMember(MacroContextClass, tpnme.Expr), List(sigma(retTpe))) + ) } import SigGenerator._ @@ -347,7 +340,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { macroTraceVerbose("tparams are: ")(tparams) macroTraceVerbose("vparamss are: ")(vparamss) macroTraceVerbose("retTpe is: ")(retTpe) - macroTraceVerbose("macroImplSig is: ")((paramss, implRetTpe)) + macroTraceVerbose("macroImplSig is: ")((paramss, implReturnType)) } /** Verifies that the body of a macro def typechecks to a reference to a static public non-overloaded method, @@ -720,16 +713,15 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { /** Does the same as `macroExpand`, but without typechecking the expansion * Meant for internal use within the macro infrastructure, don't use it elsewhere. */ - private def macroExpand1(typer: Typer, expandee: Tree): MacroExpansionResult = + private def macroExpand1(typer: Typer, expandee: Tree): MacroExpansionResult = { // verbose printing might cause recursive macro expansions, so I'm shutting it down here withInfoLevel(nodePrinters.InfoLevel.Quiet) { if (expandee.symbol.isErroneous || (expandee exists (_.isErroneous))) { val reason = if (expandee.symbol.isErroneous) "not found or incompatible macro implementation" else "erroneous arguments" macroTraceVerbose("cancelled macro expansion because of %s: ".format(reason))(expandee) - return Cancel(typer.infer.setError(expandee)) + Cancel(typer.infer.setError(expandee)) } - - try { + else try { val runtime = macroRuntime(expandee.symbol) if (runtime != null) macroExpandWithRuntime(typer, expandee, runtime) else macroExpandWithoutRuntime(typer, expandee) @@ -737,6 +729,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { case typer.TyperErrorGen.MacroExpansionException => Failure(expandee) } } + } /** Expands a macro when a runtime (i.e. the macro implementation) can be successfully loaded * Meant for internal use within the macro infrastructure, don't use it elsewhere. diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index acc4f7ff67..3ac5d388d3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -6,7 +6,6 @@ package scala.tools.nsc package typechecker import symtab.Flags._ -import scala.collection.{ mutable, immutable } import scala.reflect.internal.util.StringOps.{ ojoin } import scala.reflect.ClassTag import scala.reflect.runtime.{ universe => ru } @@ -30,61 +29,23 @@ trait MethodSynthesis { if (sym.isLazy) ValDef(sym, body) else DefDef(sym, body) - def applyTypeInternal(tags: List[TT[_]]): Type = { - val symbols = tags map compilerSymbolFromTag - val container :: args = symbols - val tparams = container.typeConstructor.typeParams - - // Conservative at present - if manifests were more usable this could do a lot more. - // [Eugene to Paul] all right, they are now. what do you have in mind? - require(symbols forall (_ ne NoSymbol), "Must find all tags: " + symbols) - require(container.owner.isPackageClass, "Container must be a top-level class in a package: " + container) - require(tparams.size == args.size, "Arguments must match type constructor arity: " + tparams + ", " + args) - - appliedType(container, args map (_.tpe): _*) - } - - def companionType[T](implicit ct: CT[T]) = - rootMirror.getRequiredModule(ct.runtimeClass.getName).tpe - - // Use these like `applyType[List, Int]` or `applyType[Map, Int, String]` - def applyType[CC](implicit t1: TT[CC]): Type = - applyTypeInternal(List(t1)) - - def applyType[CC[X1], X1](implicit t1: TT[CC[_]], t2: TT[X1]): Type = - applyTypeInternal(List(t1, t2)) - - def applyType[CC[X1, X2], X1, X2](implicit t1: TT[CC[_,_]], t2: TT[X1], t3: TT[X2]): Type = - applyTypeInternal(List(t1, t2, t3)) - - def applyType[CC[X1, X2, X3], X1, X2, X3](implicit t1: TT[CC[_,_,_]], t2: TT[X1], t3: TT[X2], t4: TT[X3]): Type = - applyTypeInternal(List(t1, t2, t3, t4)) - - def newMethodType[F](owner: Symbol)(implicit t: TT[F]): Type = { - val fnSymbol = compilerSymbolFromTag(t) - val formals = compilerTypeFromTag(t).typeArguments - assert(fnSymbol isSubClass FunctionClass(formals.size - 1), (owner, t)) - val params = owner newSyntheticValueParams formals - MethodType(params, formals.last) - } - - /** The annotations amongst those found on the original symbol which - * should be propagated to this kind of accessor. - */ - def deriveAnnotations(initial: List[AnnotationInfo], category: Symbol, keepClean: Boolean): List[AnnotationInfo] = { - initial filter { ann => - // There are no meta-annotation arguments attached to `ann` - if (ann.metaAnnotations.isEmpty) { - // A meta-annotation matching `annotKind` exists on `ann`'s definition. - (ann.defaultTargets contains category) || - // `ann`'s definition has no meta-annotations, and `keepClean` is true. - (ann.defaultTargets.isEmpty && keepClean) - } - // There are meta-annotation arguments, and one of them matches `annotKind` - else ann.metaAnnotations exists (_ matches category) + /** The annotations amongst those found on the original symbol which + * should be propagated to this kind of accessor. + */ + def deriveAnnotations(initial: List[AnnotationInfo], category: Symbol, keepClean: Boolean): List[AnnotationInfo] = { + initial filter { ann => + // There are no meta-annotation arguments attached to `ann` + if (ann.metaAnnotations.isEmpty) { + // A meta-annotation matching `annotKind` exists on `ann`'s definition. + (ann.defaultTargets contains category) || + // `ann`'s definition has no meta-annotations, and `keepClean` is true. + (ann.defaultTargets.isEmpty && keepClean) } + // There are meta-annotation arguments, and one of them matches `annotKind` + else ann.metaAnnotations exists (_ matches category) } - } + } + } import synthesisUtil._ class ClassMethodSynthesis(val clazz: Symbol, localTyper: Typer) { @@ -119,22 +80,9 @@ trait MethodSynthesis { finishMethod(clazz.info.decls enter m, f) } - private def cloneInternal(original: Symbol, f: Symbol => Tree): Tree = - cloneInternal(original, f, original.name) - def clazzMember(name: Name) = clazz.info nonPrivateMember name def typeInClazz(sym: Symbol) = clazz.thisType memberType sym - /** Function argument takes the newly created method symbol of - * the same type as `name` in clazz, and returns the tree to be - * added to the template. - */ - def overrideMethod(name: Name)(f: Symbol => Tree): Tree = - overrideMethod(clazzMember(name))(f) - - def overrideMethod(original: Symbol)(f: Symbol => Tree): Tree = - cloneInternal(original, sym => f(sym setFlag OVERRIDE)) - def deriveMethod(original: Symbol, nameFn: Name => Name)(f: Symbol => Tree): Tree = cloneInternal(original, f, nameFn(original.name)) @@ -312,7 +260,6 @@ trait MethodSynthesis { // Final methods to make the rest easier to reason about. final def mods = tree.mods final def basisSym = tree.symbol - final def derivedFlags: Long = basisSym.flags & flagsMask | flagsExtra } trait DerivedFromClassDef extends DerivedFromMemberDef { @@ -457,7 +404,7 @@ trait MethodSynthesis { case class LazyValGetter(tree: ValDef) extends BaseGetter(tree) { class ChangeOwnerAndModuleClassTraverser(oldowner: Symbol, newowner: Symbol) extends ChangeOwnerTraverser(oldowner, newowner) { - + override def traverse(tree: Tree) { tree match { case _: DefTree => change(tree.symbol.moduleClass) @@ -557,7 +504,7 @@ trait MethodSynthesis { // No Symbols available. private def beanAccessorsFromNames(tree: ValDef) = { - val ValDef(mods, name, tpt, _) = tree + val ValDef(mods, _, _, _) = tree val hasBP = mods hasAnnotationNamed tpnme.BeanPropertyAnnot val hasBoolBP = mods hasAnnotationNamed tpnme.BooleanBeanPropertyAnnot diff --git a/src/compiler/scala/tools/nsc/typechecker/Modes.scala b/src/compiler/scala/tools/nsc/typechecker/Modes.scala index d650762ac1..e1ee3c482a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Modes.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Modes.scala @@ -109,6 +109,7 @@ trait Modes { final def inFunMode(mode: Int) = (mode & FUNmode) != 0 final def inPolyMode(mode: Int) = (mode & POLYmode) != 0 final def inPatternMode(mode: Int) = (mode & PATTERNmode) != 0 + final def inPatternNotFunMode(mode: Int) = inPatternMode(mode) && !inFunMode(mode) final def inExprModeOr(mode: Int, others: Int) = (mode & (EXPRmode | others)) != 0 final def inExprModeButNot(mode: Int, prohibited: Int) = (mode & (EXPRmode | prohibited)) == EXPRmode diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 36edd46f25..79fc0e0081 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -8,9 +8,7 @@ package typechecker import scala.collection.mutable import scala.annotation.tailrec -import scala.ref.WeakReference import symtab.Flags._ -import scala.tools.nsc.io.AbstractFile /** This trait declares methods to create symbols and to enter them into scopes. * @@ -159,6 +157,9 @@ trait Namers extends MethodSynthesis { else innerNamer } + // FIXME - this logic needs to be thoroughly explained + // and justified. I know it's wrong with repect to package + // objects, but I think it's also wrong in other ways. protected def conflict(newS: Symbol, oldS: Symbol) = ( ( !oldS.isSourceMethod || nme.isSetterName(newS.name) @@ -186,6 +187,19 @@ trait Namers extends MethodSynthesis { /** Enter symbol into given scope and return symbol itself */ def enterInScope(sym: Symbol, scope: Scope): Symbol = { + // FIXME - this is broken in a number of ways. + // + // 1) If "sym" allows overloading, that is not itself sufficient to skip + // the check, because "prev.sym" also must allow overloading. + // + // 2) There is nothing which reconciles a package's scope with + // the package object's scope. This is the source of many bugs + // with e.g. defining a case class in a package object. When + // compiling against classes, the class symbol is created in the + // package and in the package object, and the conflict is undetected. + // There is also a non-deterministic outcome for situations like + // an object with the same name as a method in the package object. + // allow for overloaded methods if (!allowsOverload(sym)) { val prev = scope.lookupEntry(sym.name) @@ -321,11 +335,10 @@ trait Namers extends MethodSynthesis { } private def enterClassSymbol(tree: ClassDef, clazz: ClassSymbol): Symbol = { - val file = contextFile if (clazz.sourceFile != null && clazz.sourceFile != contextFile) - debugwarn("!!! Source mismatch in " + clazz + ": " + clazz.sourceFile + " vs. " + contextFile) + devWarning(s"Source file mismatch in $clazz: ${clazz.sourceFile} vs. $contextFile") - clazz.sourceFile = contextFile + clazz.associatedFile = contextFile if (clazz.sourceFile != null) { assert(currentRun.canRedefine(clazz) || clazz.sourceFile == currentRun.symSource(clazz), clazz.sourceFile) currentRun.symSource(clazz) = clazz.sourceFile @@ -365,8 +378,8 @@ trait Namers extends MethodSynthesis { if (sym eq NoSymbol) return val ctx = if (context.owner.isPackageObjectClass) context.outer else context - val module = if (sym.isModule) sym else ctx.scope lookup tree.name.toTermName - val clazz = if (sym.isClass) sym else ctx.scope lookup tree.name.toTypeName + val module = if (sym.isModule) sym else ctx.scope lookupModule tree.name + val clazz = if (sym.isClass) sym else ctx.scope lookupClass tree.name val fails = ( module.isModule && clazz.isClass @@ -413,7 +426,7 @@ trait Namers extends MethodSynthesis { setPrivateWithin(tree, m.moduleClass) } if (m.owner.isPackageClass && !m.isPackage) { - m.moduleClass.sourceFile = contextFile + m.moduleClass.associatedFile = contextFile currentRun.symSource(m) = m.moduleClass.sourceFile registerTopLevelSym(m) } @@ -596,7 +609,7 @@ trait Namers extends MethodSynthesis { // via "x$lzy" as can be seen in test #3927. val sym = ( if (owner.isClass) createFieldSymbol(tree) - else owner.newValue(tree.name append nme.LAZY_LOCAL, tree.pos, tree.mods.flags & ~IMPLICIT) + else owner.newValue(tree.name append nme.LAZY_LOCAL, tree.pos, (tree.mods.flags | ARTIFACT) & ~IMPLICIT) ) enterValSymbol(tree, sym setFlag MUTABLE setLazyAccessor lazyAccessor) } @@ -617,7 +630,7 @@ trait Namers extends MethodSynthesis { case DefDef(_, nme.CONSTRUCTOR, _, _, _, _) => assignAndEnterFinishedSymbol(tree) case DefDef(mods, name, tparams, _, _, _) => - val bridgeFlag = if (mods hasAnnotationNamed tpnme.bridgeAnnot) BRIDGE else 0 + val bridgeFlag = if (mods hasAnnotationNamed tpnme.bridgeAnnot) BRIDGE | ARTIFACT else 0 val sym = assignAndEnterSymbol(tree) setFlag bridgeFlag if (name == nme.copy && sym.isSynthetic) @@ -627,7 +640,7 @@ trait Namers extends MethodSynthesis { } def enterClassDef(tree: ClassDef) { - val ClassDef(mods, name, tparams, impl) = tree + val ClassDef(mods, _, _, impl) = tree val primaryConstructorArity = treeInfo.firstConstructorArgs(impl.body).size tree.symbol = enterClassSymbol(tree) tree.symbol setInfo completerOf(tree) @@ -691,41 +704,55 @@ trait Namers extends MethodSynthesis { // --- Lazy Type Assignment -------------------------------------------------- - def initializeLowerBounds(tp: Type): Type = { + def findCyclicalLowerBound(tp: Type): Symbol = { tp match { case TypeBounds(lo, _) => // check that lower bound is not an F-bound - for (TypeRef(_, sym, _) <- lo) - sym.initialize + // but carefully: class Foo[T <: Bar[_ >: T]] should be allowed + for (tp1 @ TypeRef(_, sym, _) <- lo) { + if (settings.breakCycles.value) { + if (!sym.maybeInitialize) { + log(s"Cycle inspecting $lo for possible f-bounds: ${sym.fullLocationString}") + return sym + } + } + else sym.initialize + } case _ => } - tp + NoSymbol } def monoTypeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym => + // this early test is there to avoid infinite baseTypes when + // adding setters and getters --> bug798 + // It is a def in an attempt to provide some insulation against + // uninitialized symbols misleading us. It is not a certainty + // this accomplishes anything, but performance is a non-consideration + // on these flag checks so it can't hurt. + def needsCycleCheck = sym.isNonClassType && !sym.isParameter && !sym.isExistential logAndValidate(sym) { - val tp = initializeLowerBounds(typeSig(tree)) + val tp = typeSig(tree) + + findCyclicalLowerBound(tp) andAlso { sym => + if (needsCycleCheck) { + // neg/t1224: trait C[T] ; trait A { type T >: C[T] <: C[C[T]] } + // To avoid an infinite loop on the above, we cannot break all cycles + log(s"Reinitializing info of $sym to catch any genuine cycles") + sym reset sym.info + sym.initialize + } + } sym setInfo { if (sym.isJavaDefined) RestrictJavaArraysMap(tp) else tp } - // this early test is there to avoid infinite baseTypes when - // adding setters and getters --> bug798 - val needsCycleCheck = (sym.isAliasType || sym.isAbstractType) && !sym.isParameter - if (needsCycleCheck && !typer.checkNonCyclic(tree.pos, tp)) - sym setInfo ErrorType + if (needsCycleCheck) { + log(s"Needs cycle check: ${sym.debugLocationString}") + if (!typer.checkNonCyclic(tree.pos, tp)) + sym setInfo ErrorType + } } - // tree match { - // case ClassDef(_, _, _, impl) => - // val parentsOK = ( - // treeInfo.isInterface(sym, impl.body) - // || (sym eq ArrayClass) - // || (sym isSubClass AnyValClass) - // ) - // if (!parentsOK) - // ensureParent(sym, AnyRefClass) - // case _ => () - // } } def moduleClassTypeCompleter(tree: ModuleDef) = { @@ -784,7 +811,7 @@ trait Namers extends MethodSynthesis { false } - val tpe1 = dropRepeatedParamType(tpe.deconst) + val tpe1 = dropIllegalStarTypes(tpe.deconst) val tpe2 = tpe1.widen // This infers Foo.type instead of "object Foo" @@ -832,7 +859,7 @@ trait Namers extends MethodSynthesis { val sym = ( if (hasType || hasName) { - owner.typeOfThis = if (hasType) selfTypeCompleter(tpt) else owner.tpe + owner.typeOfThis = if (hasType) selfTypeCompleter(tpt) else owner.tpe_* val selfSym = owner.thisSym setPos self.pos if (hasName) selfSym setName name else selfSym } @@ -882,11 +909,10 @@ trait Namers extends MethodSynthesis { val modClass = companionSymbolOf(clazz, context).moduleClass modClass.attachments.get[ClassForCaseCompanionAttachment] foreach { cma => val cdef = cma.caseClass - def hasCopy(decls: Scope) = (decls lookup nme.copy) != NoSymbol + def hasCopy = (decls containsName nme.copy) || parents.exists(_ member nme.copy exists) + // SI-5956 needs (cdef.symbol == clazz): there can be multiple class symbols with the same name - if (cdef.symbol == clazz && !hasCopy(decls) && - !parents.exists(p => hasCopy(p.typeSymbol.info.decls)) && - !parents.flatMap(_.baseClasses).distinct.exists(bc => hasCopy(bc.info.decls))) + if (cdef.symbol == clazz && !hasCopy) addCopyMethod(cdef, templateNamer) } } @@ -918,7 +944,7 @@ trait Namers extends MethodSynthesis { // DEPMETTODO: do we need to skolemize value parameter symbols? if (tpt.isEmpty && meth.name == nme.CONSTRUCTOR) { - tpt defineType context.enclClass.owner.tpe + tpt defineType context.enclClass.owner.tpe_* tpt setPos meth.pos.focus } var resultPt = if (tpt.isEmpty) WildcardType else typer.typedType(tpt).tpe @@ -1170,9 +1196,9 @@ trait Namers extends MethodSynthesis { // same local block several times (which can happen in interactive mode) we might // otherwise not find the default symbol, because the second time it the method // symbol will be re-entered in the scope but the default parameter will not. - val att = meth.attachments.get[DefaultsOfLocalMethodAttachment] match { + meth.attachments.get[DefaultsOfLocalMethodAttachment] match { case Some(att) => att.defaultGetters += default - case None => meth.updateAttachment(new DefaultsOfLocalMethodAttachment(default)) + case None => meth.updateAttachment(new DefaultsOfLocalMethodAttachment(default)) } } } else if (baseHasDefault) { @@ -1259,8 +1285,8 @@ trait Namers extends MethodSynthesis { if (!annotated.isInitialized) tree match { case defn: MemberDef => val ainfos = defn.mods.annotations filterNot (_ eq null) map { ann => - // need to be lazy, #1782. beforeTyper to allow inferView in annotation args, SI-5892. - AnnotationInfo lazily beforeTyper(typer typedAnnotation ann) + // need to be lazy, #1782. enteringTyper to allow inferView in annotation args, SI-5892. + AnnotationInfo lazily enteringTyper(typer typedAnnotation ann) } if (ainfos.nonEmpty) { annotated setAnnotations ainfos @@ -1362,12 +1388,6 @@ trait Namers extends MethodSynthesis { tpe } - def ensureParent(clazz: Symbol, parent: Symbol) = { - val info0 = clazz.info - val info1 = includeParent(info0, parent) - if (info0 ne info1) clazz setInfo info1 - } - class LogTransitions[S](onEnter: S => String, onExit: S => String) { val enabled = settings.debug.value @inline final def apply[T](entity: S)(body: => T): T = { diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index be218fcb02..14c8d85836 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -8,7 +8,6 @@ package typechecker import symtab.Flags._ import scala.collection.mutable -import scala.ref.WeakReference import scala.reflect.ClassTag /** @@ -42,8 +41,6 @@ trait NamesDefaults { self: Analyzer => blockTyper: Typer ) { } - val noApplyInfo = NamedApplyInfo(None, Nil, Nil, null) - def nameOf(arg: Tree) = arg match { case AssignOrNamedArg(Ident(name), rhs) => Some(name) case _ => None @@ -164,14 +161,14 @@ trait NamesDefaults { self: Analyzer => // never used for constructor calls, they always have a stable qualifier def blockWithQualifier(qual: Tree, selected: Name) = { - val sym = blockTyper.context.owner.newValue(unit.freshTermName("qual$"), qual.pos) setInfo qual.tpe + val sym = blockTyper.context.owner.newValue(unit.freshTermName("qual$"), qual.pos, newFlags = ARTIFACT) setInfo qual.tpe blockTyper.context.scope enter sym val vd = atPos(sym.pos)(ValDef(sym, qual) setType NoType) // it stays in Vegas: SI-5720, SI-5727 qual changeOwner (blockTyper.context.owner -> sym) val newQual = atPos(qual.pos.focus)(blockTyper.typedQualifier(Ident(sym.name))) - var baseFunTransformed = atPos(baseFun.pos.makeTransparent) { + val baseFunTransformed = atPos(baseFun.pos.makeTransparent) { // setSymbol below is important because the 'selected' function might be overloaded. by // assigning the correct method symbol, typedSelect will just assign the type. the reason // to still call 'typed' is to correctly infer singleton types, SI-5259. @@ -281,7 +278,7 @@ trait NamesDefaults { self: Analyzer => } else arg.tpe ).widen // have to widen or types inferred from literal defaults will be singletons - val s = context.owner.newValue(unit.freshTermName("x$"), arg.pos) setInfo ( + val s = context.owner.newValue(unit.freshTermName("x$"), arg.pos, newFlags = ARTIFACT) setInfo ( if (byName) functionType(Nil, argTpe) else argTpe ) (context.scope.enter(s), byName, repeated) @@ -319,7 +316,7 @@ trait NamesDefaults { self: Analyzer => assert(isNamedApplyBlock(transformedFun), transformedFun) val NamedApplyInfo(qual, targs, vargss, blockTyper) = context.namedApplyBlockInfo.get._2 - val existingBlock @ Block(stats, funOnly) = transformedFun + val Block(stats, funOnly) = transformedFun // type the application without names; put the arguments in definition-site order val typedApp = doTypedApply(tree, funOnly, reorderArgs(namelessArgs, argPos), mode, pt) diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala index 834c64aaae..42c34526d7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala @@ -37,13 +37,11 @@ import scala.reflect.internal.Types * - recover exhaustivity/unreachability of user-defined extractors by partitioning the types they match on using an HList or similar type-level structure */ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL { // self: Analyzer => - import Statistics._ import PatternMatchingStats._ val global: Global // need to repeat here because otherwise last mixin defines global as // SymbolTable. If we had DOT this would not be an issue import global._ // the global environment - import definitions._ // standard classes and methods val phaseName: String = "patmat" @@ -70,7 +68,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL } def newTransformer(unit: CompilationUnit): Transformer = - if (opt.virtPatmat) new MatchTransformer(unit) + if (!settings.XoldPatmat.value) new MatchTransformer(unit) else noopTransformer // duplicated from CPSUtils (avoid dependency from compiler -> cps plugin...) @@ -192,7 +190,6 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL trait MatchTranslation extends MatchMonadInterface { self: TreeMakers with CodegenCore => import typer.{typed, context, silent, reallyExists} - // import typer.infer.containsUnchecked // Why is it so difficult to say "here's a name and a context, give me any // matching symbol in scope" ? I am sure this code is wrong, but attempts to @@ -274,7 +271,9 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // we don't transform after uncurry // (that would require more sophistication when generating trees, // and the only place that emits Matches after typers is for exception handling anyway) - if(phase.id >= currentRun.uncurryPhase.id) debugwarn("running translateMatch at "+ phase +" on "+ selector +" match "+ cases) + if (phase.id >= currentRun.uncurryPhase.id) + devWarning(s"running translateMatch past uncurry (at $phase) on $selector match $cases") + patmatDebug("translating "+ cases.mkString("{", "\n", "}")) val start = if (Statistics.canEnable) Statistics.startTimer(patmatNanos) else null @@ -294,8 +293,6 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // pt is the skolemized version val pt = repeatedToSeq(ptUnCPS) - // val packedPt = repeatedToSeq(typer.packedType(match_, context.owner)) - // the alternative to attaching the default case override would be to simply // append the default to the list of cases and suppress the unreachable case error that may arise (once we detect that...) val matchFailGenOverride = match_.attachments.get[DefaultOverrideMatchAttachment].map{case DefaultOverrideMatchAttachment(default) => ((scrut: Tree) => default)} @@ -560,54 +557,55 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL def fromCaseClass(fun: Tree, args: List[Tree]): Option[ExtractorCall] = Some(new ExtractorCallProd(fun, args)) // THE PRINCIPLED SLOW PATH -- NOT USED + // !!! Use it, test it, or delete it, else it is unlikely to be an asset. // generate a call to the (synthetically generated) extractor of a case class // NOTE: it's an apply, not a select, since in general an extractor call may have multiple argument lists (including an implicit one) // that we need to preserve, so we supply the scrutinee as Ident(nme.SELECTOR_DUMMY), // and replace that dummy by a reference to the actual binder in translateExtractorPattern - def fromCaseClassUnapply(fun: Tree, args: List[Tree]): Option[ExtractorCall] = { - // TODO: can we rework the typer so we don't have to do all this twice? - // undo rewrite performed in (5) of adapt - val orig = fun match {case tpt: TypeTree => tpt.original case _ => fun} - val origSym = orig.symbol - val extractor = unapplyMember(origSym.filter(sym => reallyExists(unapplyMember(sym.tpe))).tpe) - - if((fun.tpe eq null) || fun.tpe.isError || (extractor eq NoSymbol)) { - None - } else { - // this is a tricky balance: pos/t602.scala, pos/sudoku.scala, run/virtpatmat_alts.scala must all be happy - // bypass typing at own risk: val extractorCall = Select(orig, extractor) setType caseClassApplyToUnapplyTp(fun.tpe) - // can't always infer type arguments (pos/t602): - /* case class Span[K <: Ordered[K]](low: Option[K]) { - override def equals(x: Any): Boolean = x match { - case Span((low0 @ _)) if low0 equals low => true - } - }*/ - // so... leave undetermined type params floating around if we have to - // (if we don't infer types, uninstantiated type params show up later: pos/sudoku.scala) - // (see also run/virtpatmat_alts.scala) - val savedUndets = context.undetparams - val extractorCall = try { - context.undetparams = Nil - silent(_.typed(Apply(Select(orig, extractor), List(Ident(nme.SELECTOR_DUMMY) setType fun.tpe.finalResultType)), EXPRmode, WildcardType), reportAmbiguousErrors = false) match { - case SilentResultValue(extractorCall) => extractorCall // if !extractorCall.containsError() - case _ => - // this fails to resolve overloading properly... - // Apply(typedOperator(Select(orig, extractor)), List(Ident(nme.SELECTOR_DUMMY))) // no need to set the type of the dummy arg, it will be replaced anyway - - // patmatDebug("funtpe after = "+ fun.tpe.finalResultType) - // patmatDebug("orig: "+(orig, orig.tpe)) - val tgt = typed(orig, EXPRmode | QUALmode | POLYmode, HasMember(extractor.name)) // can't specify fun.tpe.finalResultType as the type for the extractor's arg, - // as it may have been inferred incorrectly (see t602, where it's com.mosol.sl.Span[Any], instead of com.mosol.sl.Span[?K]) - // patmatDebug("tgt = "+ (tgt, tgt.tpe)) - val oper = typed(Select(tgt, extractor.name), EXPRmode | FUNmode | POLYmode | TAPPmode, WildcardType) - // patmatDebug("oper: "+ (oper, oper.tpe)) - Apply(oper, List(Ident(nme.SELECTOR_DUMMY))) // no need to set the type of the dummy arg, it will be replaced anyway - } - } finally context.undetparams = savedUndets - - Some(this(extractorCall, args)) // TODO: simplify spliceApply? - } - } + // def fromCaseClassUnapply(fun: Tree, args: List[Tree]): Option[ExtractorCall] = { + // // TODO: can we rework the typer so we don't have to do all this twice? + // // undo rewrite performed in (5) of adapt + // val orig = fun match {case tpt: TypeTree => tpt.original case _ => fun} + // val origSym = orig.symbol + // val extractor = unapplyMember(origSym.filter(sym => reallyExists(unapplyMember(sym.tpe))).tpe) + + // if((fun.tpe eq null) || fun.tpe.isError || (extractor eq NoSymbol)) { + // None + // } else { + // // this is a tricky balance: pos/t602.scala, pos/sudoku.scala, run/virtpatmat_alts.scala must all be happy + // // bypass typing at own risk: val extractorCall = Select(orig, extractor) setType caseClassApplyToUnapplyTp(fun.tpe) + // // can't always infer type arguments (pos/t602): + // /* case class Span[K <: Ordered[K]](low: Option[K]) { + // override def equals(x: Any): Boolean = x match { + // case Span((low0 @ _)) if low0 equals low => true + // } + // }*/ + // // so... leave undetermined type params floating around if we have to + // // (if we don't infer types, uninstantiated type params show up later: pos/sudoku.scala) + // // (see also run/virtpatmat_alts.scala) + // val savedUndets = context.undetparams + // val extractorCall = try { + // context.undetparams = Nil + // silent(_.typed(Apply(Select(orig, extractor), List(Ident(nme.SELECTOR_DUMMY) setType fun.tpe.finalResultType)), EXPRmode, WildcardType), reportAmbiguousErrors = false) match { + // case SilentResultValue(extractorCall) => extractorCall // if !extractorCall.containsError() + // case _ => + // // this fails to resolve overloading properly... + // // Apply(typedOperator(Select(orig, extractor)), List(Ident(nme.SELECTOR_DUMMY))) // no need to set the type of the dummy arg, it will be replaced anyway + + // // patmatDebug("funtpe after = "+ fun.tpe.finalResultType) + // // patmatDebug("orig: "+(orig, orig.tpe)) + // val tgt = typed(orig, EXPRmode | QUALmode | POLYmode, HasMember(extractor.name)) // can't specify fun.tpe.finalResultType as the type for the extractor's arg, + // // as it may have been inferred incorrectly (see t602, where it's com.mosol.sl.Span[Any], instead of com.mosol.sl.Span[?K]) + // // patmatDebug("tgt = "+ (tgt, tgt.tpe)) + // val oper = typed(Select(tgt, extractor.name), EXPRmode | FUNmode | POLYmode | TAPPmode, WildcardType) + // // patmatDebug("oper: "+ (oper, oper.tpe)) + // Apply(oper, List(Ident(nme.SELECTOR_DUMMY))) // no need to set the type of the dummy arg, it will be replaced anyway + // } + // } finally context.undetparams = savedUndets + + // Some(this(extractorCall, args)) // TODO: simplify spliceApply? + // } + // } } abstract class ExtractorCall(val args: List[Tree]) { @@ -1426,10 +1424,8 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // local / context-free def _asInstanceOf(b: Symbol, tp: Type): Tree - def _asInstanceOf(t: Tree, tp: Type): Tree def _equals(checker: Tree, binder: Symbol): Tree def _isInstanceOf(b: Symbol, tp: Type): Tree - def and(a: Tree, b: Tree): Tree def drop(tgt: Tree)(n: Int): Tree def index(tgt: Tree)(i: Int): Tree def mkZero(tp: Type): Tree @@ -1443,7 +1439,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL def flatMap(prev: Tree, b: Symbol, next: Tree): Tree def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, next: Tree): Tree def flatMapGuard(cond: Tree, next: Tree): Tree - def ifThenElseZero(c: Tree, then: Tree): Tree = IF (c) THEN then ELSE zero + def ifThenElseZero(c: Tree, thenp: Tree): Tree = IF (c) THEN thenp ELSE zero protected def zero: Tree } @@ -1471,12 +1467,10 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL abstract class CommonCodegen extends AbsCodegen { import CODE._ def fun(arg: Symbol, body: Tree): Tree = Function(List(ValDef(arg)), body) - def genTypeApply(tfun: Tree, args: Type*): Tree = if(args contains NoType) tfun else TypeApply(tfun, args.toList map TypeTree) def tupleSel(binder: Symbol)(i: Int): Tree = (REF(binder) DOT nme.productAccessorName(i)) // make tree that accesses the i'th component of the tuple referenced by binder def index(tgt: Tree)(i: Int): Tree = tgt APPLY (LIT(i)) def drop(tgt: Tree)(n: Int): Tree = (tgt DOT vpmName.drop) (LIT(n)) def _equals(checker: Tree, binder: Symbol): Tree = checker MEMBER_== REF(binder) // NOTE: checker must be the target of the ==, that's the patmat semantics for ya - def and(a: Tree, b: Tree): Tree = a AND b // drop annotations generated by CPS plugin etc, since its annotationchecker rejects T @cps[U] <: Any // let's assume for now annotations don't affect casts, drop them there, and bring them back using the outer Typed tree @@ -1484,10 +1478,8 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL Typed(gen.mkAsInstanceOf(t, tp.withoutAnnotations, true, false), TypeTree() setType tp) // the force is needed mainly to deal with the GADT typing hack (we can't detect it otherwise as tp nor pt need contain an abstract type, we're just casting wildly) - def _asInstanceOf(t: Tree, tp: Type): Tree = if (t.tpe != NoType && t.isTyped && typesConform(t.tpe, tp)) t else mkCast(t, tp) def _asInstanceOf(b: Symbol, tp: Type): Tree = if (typesConform(b.info, tp)) REF(b) else mkCast(REF(b), tp) def _isInstanceOf(b: Symbol, tp: Type): Tree = gen.mkIsInstanceOf(REF(b), tp.withoutAnnotations, true, false) - // if (typesConform(b.info, tpX)) { patmatDebug("warning: emitted spurious isInstanceOf: "+(b, tp)); TRUE } // duplicated out of frustration with cast generation def mkZero(tp: Type): Tree = { @@ -1536,7 +1528,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // __match.zero protected def zero: Tree = _match(vpmName.zero) // __match.guard(`c`, `then`) - def guard(c: Tree, then: Tree): Tree = _match(vpmName.guard) APPLY (c, then) + def guard(c: Tree, thenp: Tree): Tree = _match(vpmName.guard) APPLY (c, thenp) //// methods in the monad instance -- used directly in translation // `prev`.flatMap(`b` => `next`) @@ -1829,9 +1821,9 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL def toString(x: AnyRef) = if (x eq null) "" else x.toString if (cols.isEmpty || cols.tails.isEmpty) cols map toString else { - val (colStrs, colLens) = cols map {c => val s = toString(c); (s, s.length)} unzip - val maxLen = max(colLens) - val avgLen = colLens.sum/colLens.length + val colLens = cols map (c => toString(c).length) + val maxLen = max(colLens) + val avgLen = colLens.sum/colLens.length val goalLen = maxLen min avgLen*2 def pad(s: String) = { val toAdd = ((goalLen - s.length) max 0) + 2 @@ -2065,7 +2057,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // throws an AnalysisBudget.Exception when the prop results in a CNF that's too big // TODO: be smarter/more efficient about this (http://lara.epfl.ch/w/sav09:tseitin_s_encoding) def eqFreePropToSolvable(p: Prop): Formula = { - def negationNormalFormNot(p: Prop, budget: Int = AnalysisBudget.max): Prop = + def negationNormalFormNot(p: Prop, budget: Int): Prop = if (budget <= 0) throw AnalysisBudget.exceeded else p match { case And(a, b) => Or(negationNormalFormNot(a, budget - 1), negationNormalFormNot(b, budget - 1)) @@ -2274,9 +2266,9 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL private[this] val id: Int = Var.nextId // private[this] var canModify: Option[Array[StackTraceElement]] = None - private[this] def ensureCanModify = {} //if (canModify.nonEmpty) patmatDebug("BUG!"+ this +" modified after having been observed: "+ canModify.get.mkString("\n")) + private[this] def ensureCanModify() = {} //if (canModify.nonEmpty) patmatDebug("BUG!"+ this +" modified after having been observed: "+ canModify.get.mkString("\n")) - private[this] def observed = {} //canModify = Some(Thread.currentThread.getStackTrace) + private[this] def observed() = {} //canModify = Some(Thread.currentThread.getStackTrace) // don't access until all potential equalities have been registered using registerEquality private[this] val symForEqualsTo = new scala.collection.mutable.HashMap[Const, Sym] @@ -2429,7 +2421,13 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL private lazy val equalitySyms = {observed; symForEqualsTo.values.toList} // don't call until all equalities have been registered and registerNull has been called (if needed) - def describe = toString + ": " + staticTp + domain.map(_.mkString(" ::= ", " | ", "// "+ symForEqualsTo.keys)).getOrElse(symForEqualsTo.keys.mkString(" ::= ", " | ", " | ...")) + " // = " + path + def describe = { + def domain_s = domain match { + case Some(d) => d mkString (" ::= ", " | ", "// "+ symForEqualsTo.keys) + case _ => symForEqualsTo.keys mkString (" ::= ", " | ", " | ...") + } + s"$this: ${staticTp}${domain_s} // = $path" + } override def toString = "V"+ id } @@ -2515,7 +2513,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // corresponds to a type test that does not imply any value-equality (well, except for outer checks, which we don't model yet) sealed class TypeConst(val tp: Type) extends Const { assert(!(tp =:= NullTp)) - private[this] val id: Int = Const.nextTypeId + /*private[this] val id: Int = */ Const.nextTypeId val wideTp = widenToClass(tp) def isValue = false @@ -2553,7 +2551,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL } val toString = - if (p.hasSymbol && p.symbol.isStable) p.symbol.name.toString // tp.toString + if (p.hasSymbolField && p.symbol.isStable) p.symbol.name.toString // tp.toString else p.toString //+"#"+ id Const.unique(narrowTp, new ValueConst(narrowTp, checkableType(wideTp), toString)) // must make wide type checkable so that it is comparable to types from TypeConst @@ -2563,7 +2561,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL sealed class ValueConst(val tp: Type, val wideTp: Type, override val toString: String) extends Const { // patmatDebug("VC"+(tp, wideTp, toString)) assert(!(tp =:= NullTp)) // TODO: assert(!tp.isStable) - private[this] val id: Int = Const.nextValueId + /*private[this] val id: Int = */Const.nextValueId def isValue = true } @@ -2789,7 +2787,6 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // when does the match fail? val matchFails = Not(\/(symbolicCases)) - val vars = gatherVariables(matchFails) // debug output: patmatDebug("analysing:") @@ -2887,8 +2884,6 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL v +"(="+ v.path +": "+ v.staticTpCheckable +") "+ assignment }.mkString("\n") - def modelString(model: Model) = varAssignmentString(modelToVarAssignment(model)) - // return constructor call when the model is a true counter example // (the variables don't take into account type information derived from other variables, // so, naively, you might try to construct a counter example like _ :: Nil(_ :: _, _ :: _), @@ -3546,7 +3541,6 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // for the catch-cases in a try/catch private object typeSwitchMaker extends SwitchMaker { val unchecked = false - def switchableTpe(tp: Type) = true val alternativesSupported = false // TODO: needs either back-end support of flattening of alternatives during typers val canJump = false @@ -3592,11 +3586,6 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL trait OptimizedCodegen extends CodegenCore with TypedSubstitution with OptimizedMatchMonadInterface { override def codegen: AbsCodegen = optimizedCodegen - // trait AbsOptimizedCodegen extends AbsCodegen { - // def flatMapCondStored(cond: Tree, condSym: Symbol, res: Tree, nextBinder: Symbol, next: Tree): Tree - // } - // def optimizedCodegen: AbsOptimizedCodegen - // when we know we're targetting Option, do some inlining the optimizer won't do // for example, `o.flatMap(f)` becomes `if(o == None) None else f(o.get)`, similarly for orElse and guard // this is a special instance of the advanced inlining optimization that takes a method call on diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 78ec6508ed..0ae225ccee 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -60,23 +60,8 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans super.transformInfo(sym, tp) } - val toJavaRepeatedParam = new TypeMap { - def apply(tp: Type) = tp match { - case TypeRef(pre, RepeatedParamClass, args) => - typeRef(pre, JavaRepeatedParamClass, args) - case _ => - mapOver(tp) - } - } - - val toScalaRepeatedParam = new TypeMap { - def apply(tp: Type): Type = tp match { - case TypeRef(pre, JavaRepeatedParamClass, args) => - typeRef(pre, RepeatedParamClass, args) - case _ => - mapOver(tp) - } - } + val toJavaRepeatedParam = new SubstSymMap(RepeatedParamClass -> JavaRepeatedParamClass) + val toScalaRepeatedParam = new SubstSymMap(JavaRepeatedParamClass -> RepeatedParamClass) def accessFlagsToString(sym: Symbol) = flagsToString( sym getFlag (PRIVATE | PROTECTED), @@ -145,7 +130,17 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } } } - if (settings.lint.value) { + + // Check for doomed attempt to overload applyDynamic + if (clazz isSubClass DynamicClass) { + clazz.info member nme.applyDynamic match { + case sym if sym.isOverloaded => unit.error(sym.pos, "implementation restriction: applyDynamic cannot be overloaded") + case _ => + } + } + + // This has become noisy with implicit classes. + if (settings.lint.value && settings.developer.value) { clazz.info.decls filter (x => x.isImplicit && x.typeParams.nonEmpty) foreach { sym => val alts = clazz.info.decl(sym.name).alternatives if (alts.size > 1) @@ -156,27 +151,22 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans // Override checking ------------------------------------------------------------ - def isJavaVarargsAncestor(clazz: Symbol) = ( - clazz.isClass - && clazz.isJavaDefined - && (clazz.info.nonPrivateDecls exists isJavaVarArgsMethod) - ) - /** Add bridges for vararg methods that extend Java vararg methods */ def addVarargBridges(clazz: Symbol): List[Tree] = { // This is quite expensive, so attempt to skip it completely. // Insist there at least be a java-defined ancestor which // defines a varargs method. TODO: Find a cheaper way to exclude. - if (clazz.thisType.baseClasses exists isJavaVarargsAncestor) { + if (inheritsJavaVarArgsMethod(clazz)) { log("Found java varargs ancestor in " + clazz.fullLocationString + ".") val self = clazz.thisType val bridges = new ListBuffer[Tree] def varargBridge(member: Symbol, bridgetpe: Type): Tree = { - log("Generating varargs bridge for " + member.fullLocationString + " of type " + bridgetpe) + log(s"Generating varargs bridge for ${member.fullLocationString} of type $bridgetpe") - val bridge = member.cloneSymbolImpl(clazz, member.flags | VBRIDGE) setPos clazz.pos + val newFlags = (member.flags | VBRIDGE | ARTIFACT) & ~PRIVATE + val bridge = member.cloneSymbolImpl(clazz, newFlags) setPos clazz.pos bridge.setInfo(bridgetpe.cloneInfo(bridge)) clazz.info.decls enter bridge @@ -189,26 +179,35 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans localTyper typed DefDef(bridge, body) } - // For all concrete non-private members that have a (Scala) repeated parameter: - // compute the corresponding method type `jtpe` with a Java repeated parameter + // For all concrete non-private members (but: see below) that have a (Scala) repeated + // parameter: compute the corresponding method type `jtpe` with a Java repeated parameter // if a method with type `jtpe` exists and that method is not a varargs bridge // then create a varargs bridge of type `jtpe` that forwards to the // member method with the Scala vararg type. - for (member <- clazz.info.nonPrivateMembers) { + // + // @PP: Can't call nonPrivateMembers because we will miss refinement members, + // which have been marked private. See SI-4729. + for (member <- nonTrivialMembers(clazz)) { + log(s"Considering $member for java varargs bridge in $clazz") if (!member.isDeferred && member.isMethod && hasRepeatedParam(member.info)) { val inherited = clazz.info.nonPrivateMemberAdmitting(member.name, VBRIDGE) + // Delaying calling memberType as long as possible if (inherited ne NoSymbol) { - val jtpe = toJavaRepeatedParam(self.memberType(member)) + val jtpe = toJavaRepeatedParam(self memberType member) // this is a bit tortuous: we look for non-private members or bridges // if we find a bridge everything is OK. If we find another member, // we need to create a bridge - if (inherited filter (sym => (self.memberType(sym) matches jtpe) && !(sym hasFlag VBRIDGE)) exists) + val inherited1 = inherited filter (sym => !(sym hasFlag VBRIDGE) && (self memberType sym matches jtpe)) + if (inherited1.exists) bridges += varargBridge(member, jtpe) } } } + if (bridges.size > 0) + log(s"Adding ${bridges.size} bridges for methods extending java varargs.") + bridges.toList } else Nil @@ -248,7 +247,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans case class MixinOverrideError(member: Symbol, msg: String) - var mixinOverrideErrors = new ListBuffer[MixinOverrideError]() + val mixinOverrideErrors = new ListBuffer[MixinOverrideError]() def printMixinOverrideErrors() { mixinOverrideErrors.toList match { @@ -556,13 +555,13 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans def uncurryAndErase(tp: Type) = erasure.erasure(sym)(uncurry.transformInfo(sym, tp)) val tp1 = uncurryAndErase(clazz.thisType.memberType(sym)) val tp2 = uncurryAndErase(clazz.thisType.memberType(other)) - afterErasure(tp1 matches tp2) + exitingErasure(tp1 matches tp2) }) def ignoreDeferred(member: Symbol) = ( (member.isAbstractType && !member.isFBounded) || ( member.isJavaDefined && - // the test requires afterErasure so shouldn't be + // the test requires exitingErasure so shouldn't be // done if the compiler has no erasure phase available (currentRun.erasurePhase == NoPhase || javaErasedOverridingSym(member) != NoSymbol) ) @@ -845,7 +844,6 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans // Variance Checking -------------------------------------------------------- - private val ContraVariance = -1 private val NoVariance = 0 private val CoVariance = 1 private val AnyVariance = 2 @@ -905,13 +903,14 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans * the type occurs itself at variance position given by `variance` */ def validateVariance(tp: Type, variance: Int): Unit = tp match { - case ErrorType => ; - case WildcardType => ; - case NoType => ; - case NoPrefix => ; - case ThisType(_) => ; - case ConstantType(_) => ; - // case DeBruijnIndex(_, _) => ; + case ErrorType => + case WildcardType => + case BoundedWildcardType(bounds) => + validateVariance(bounds, variance) + case NoType => + case NoPrefix => + case ThisType(_) => + case ConstantType(_) => case SingleType(pre, sym) => validateVariance(pre, variance) case TypeRef(pre, sym, args) => @@ -1062,6 +1061,12 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans def apply(tp: Type) = mapOver(tp).normalize } + def checkImplicitViewOptionApply(pos: Position, fn: Tree, args: List[Tree]): Unit = if (settings.lint.value) (fn, args) match { + case (tap@TypeApply(fun, targs), List(view: ApplyImplicitView)) if fun.symbol == Option_apply => + unit.warning(pos, s"Suspicious application of an implicit view (${view.fun}) in the argument to Option.apply.") // SI-6567 + case _ => + } + def checkSensible(pos: Position, fn: Tree, args: List[Tree]) = fn match { case Select(qual, name @ (nme.EQ | nme.NE | nme.eq | nme.ne)) if args.length == 1 => def isReferenceOp = name == nme.eq || name == nme.ne @@ -1118,8 +1123,6 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans def isMaybeAnyValue(s: Symbol) = isPrimitiveValueClass(unboxedValueClass(s)) || isMaybeValue(s) // used to short-circuit unrelatedTypes check if both sides are special def isSpecial(s: Symbol) = isMaybeAnyValue(s) || isAnyNumber(s) - // unused - def possibleNumericCount = onSyms(_ filter (x => isNumeric(x) || isMaybeValue(x)) size) val nullCount = onSyms(_ filter (_ == NullClass) size) def nonSensibleWarning(what: String, alwaysEqual: Boolean) = { @@ -1230,7 +1233,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans /* Convert a reference to a case factory of type `tpe` to a new of the class it produces. */ def toConstructor(pos: Position, tpe: Type): Tree = { - var rtpe = tpe.finalResultType + val rtpe = tpe.finalResultType assert(rtpe.typeSymbol hasFlag CASE, tpe); localTyper.typedOperator { atPos(pos) { @@ -1272,7 +1275,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans case vsym => ValDef(vsym) } } - def createStaticModuleAccessor() = afterRefchecks { + def createStaticModuleAccessor() = exitingRefchecks { val method = ( sym.owner.newMethod(sym.name.toTermName, sym.pos, (sym.flags | STABLE) & ~MODULE) setInfoAndEnter NullaryMethodType(sym.moduleClass.tpe) @@ -1283,7 +1286,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans vdef, localTyper.typedPos(tree.pos) { val vsym = vdef.symbol - afterRefchecks { + exitingRefchecks { val rhs = gen.newModule(sym, vsym.tpe) val body = if (sym.owner.isTrait) rhs else gen.mkAssignAndReturn(vsym, rhs) DefDef(sym, body.changeOwner(vsym -> sym)) @@ -1311,7 +1314,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } case ModuleDef(_, _, _) => eliminateModuleDefs(tree) case ValDef(_, _, _, _) => - val tree1 @ ValDef(_, _, _, rhs) = transform(tree) // important to do before forward reference check + val tree1 = transform(tree) // important to do before forward reference check if (tree1.symbol.isLazy) tree1 :: Nil else { val lazySym = tree.symbol.lazyAccessorOrSelf @@ -1465,8 +1468,11 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } private def isRepeatedParamArg(tree: Tree) = currentApplication match { case Apply(fn, args) => - !args.isEmpty && (args.last eq tree) && - fn.tpe.params.length == args.length && isRepeatedParamType(fn.tpe.params.last.tpe) + ( args.nonEmpty + && (args.last eq tree) + && (fn.tpe.params.length == args.length) + && isRepeatedParamType(fn.tpe.params.last.tpe) + ) case _ => false } @@ -1555,12 +1561,15 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans case Apply(fn, args) => // sensicality should be subsumed by the unreachability/exhaustivity/irrefutability analyses in the pattern matcher - if (!inPattern) checkSensible(tree.pos, fn, args) + if (!inPattern) { + checkImplicitViewOptionApply(tree.pos, fn, args) + checkSensible(tree.pos, fn, args) + } currentApplication = tree tree } private def transformSelect(tree: Select): Tree = { - val Select(qual, name) = tree + val Select(qual, _) = tree val sym = tree.symbol /** Note: if a symbol has both @deprecated and @migration annotations and both diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index fb8a111da1..0992cd7955 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -60,8 +60,8 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT val clazz = qual.symbol val supername = nme.superName(name) val superAcc = clazz.info.decl(supername).suchThat(_.alias == sym) orElse { - debuglog("add super acc " + sym + sym.locationString + " to `" + clazz);//debug - val acc = clazz.newMethod(supername, sel.pos, SUPERACCESSOR | PRIVATE) setAlias sym + debuglog(s"add super acc ${sym.fullLocationString} to $clazz") + val acc = clazz.newMethod(supername, sel.pos, SUPERACCESSOR | PRIVATE | ARTIFACT) setAlias sym val tpe = clazz.thisType memberType sym match { case t if sym.isModule && !sym.isMethod => NullaryMethodType(t) case t => t @@ -291,7 +291,8 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT && !sym.owner.isTrait && (sym.owner.enclosingPackageClass != currentClass.enclosingPackageClass) && (qual.symbol.info.member(sym.name) ne NoSymbol) - && !needsProtectedAccessor(sym, tree.pos)) + && !needsProtectedAccessor(sym, tree.pos) + ) if (shouldEnsureAccessor) { log("Ensuring accessor for call to protected " + sym.fullLocationString + " from " + currentClass) ensureAccessor(sel) @@ -387,7 +388,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT * typed. */ private def makeAccessor(tree: Select, targs: List[Tree]): Tree = { - val Select(qual, name) = tree + val Select(qual, _) = tree val sym = tree.symbol val clazz = hostForAccessorOf(sym, currentClass) @@ -412,7 +413,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT } val protAcc = clazz.info.decl(accName).suchThat(s => s == NoSymbol || s.tpe =:= accType(s)) orElse { - val newAcc = clazz.newMethod(nme.protName(sym.originalName), tree.pos) + val newAcc = clazz.newMethod(nme.protName(sym.originalName), tree.pos, newFlags = ARTIFACT) newAcc setInfoAndEnter accType(newAcc) val code = DefDef(newAcc, { @@ -423,7 +424,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT args.foldLeft(base)(Apply(_, _)) }) - debuglog("" + code) + debuglog("created protected accessor: " + code) storeAccessorDefinition(clazz, code) newAcc } @@ -435,7 +436,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT case _ => mkApply(TypeApply(selection, targs)) } } - debuglog("Replaced " + tree + " with " + res) + debuglog(s"Replaced $tree with $res") if (hasArgs) localTyper.typedOperator(res) else localTyper.typed(res) } @@ -474,7 +475,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT val accName = nme.protSetterName(field.originalName) val protectedAccessor = clazz.info decl accName orElse { - val protAcc = clazz.newMethod(accName, field.pos) + val protAcc = clazz.newMethod(accName, field.pos, newFlags = ARTIFACT) val paramTypes = List(clazz.typeOfThis, field.tpe) val params = protAcc newSyntheticValueParams paramTypes val accessorType = MethodType(params, UnitClass.tpe) @@ -506,9 +507,6 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT def accessibleThroughSubclassing = validCurrentOwner && clazz.thisSym.isSubClass(sym.owner) && !clazz.isTrait - def packageAccessBoundry(sym: Symbol) = - sym.accessBoundary(sym.enclosingPackageClass) - val isCandidate = ( sym.isProtected && sym.isJavaDefined diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 17e67e6429..07135c3af9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -6,9 +6,7 @@ package scala.tools.nsc package typechecker -import symtab.Flags import symtab.Flags._ -import scala.collection.mutable import scala.collection.mutable.ListBuffer /** Synthetic method implementations for case classes and case objects. @@ -97,7 +95,7 @@ trait SyntheticMethods extends ast.TreeDSL { // like Tags and Arrays which are not robust and infer things // which they shouldn't. val accessorLub = ( - if (opt.experimental) { + if (settings.Xexperimental.value) { global.weakLub(accessors map (_.tpe.finalResultType))._1 match { case RefinedType(parents, decls) if !decls.isEmpty => intersectionType(parents) case tp => tp @@ -124,20 +122,11 @@ trait SyntheticMethods extends ast.TreeDSL { (m0 ne meth) && !m0.isDeferred && !m0.isSynthetic && (m0.owner != AnyValClass) && (typeInClazz(m0) matches typeInClazz(meth)) } } - def readConstantValue[T](name: String, default: T = null.asInstanceOf[T]): T = { - clazzMember(newTermName(name)).info match { - case NullaryMethodType(ConstantType(Constant(value))) => value.asInstanceOf[T] - case _ => default - } - } def productIteratorMethod = { createMethod(nme.productIterator, iteratorOfType(accessorLub))(_ => gen.mkMethodCall(ScalaRunTimeModule, nme.typedProductIterator, List(accessorLub), List(mkThis)) ) } - def projectionMethod(accessor: Symbol, num: Int) = { - createMethod(nme.productAccessorName(num), accessor.tpe.resultType)(_ => REF(accessor)) - } /** Common code for productElement and (currently disabled) productElementName */ @@ -229,10 +218,15 @@ trait SyntheticMethods extends ast.TreeDSL { /** The _1, _2, etc. methods to implement ProductN, disabled * until we figure out how to introduce ProductN without cycles. */ - def productNMethods = { + /**** + def productNMethods = { val accs = accessors.toIndexedSeq 1 to arity map (num => productProj(arity, num) -> (() => projectionMethod(accs(num - 1), num))) } + def projectionMethod(accessor: Symbol, num: Int) = { + createMethod(nme.productAccessorName(num), accessor.tpe.resultType)(_ => REF(accessor)) + } + ****/ // methods for both classes and objects def productMethods = { @@ -370,7 +364,6 @@ trait SyntheticMethods extends ast.TreeDSL { def isRewrite(sym: Symbol) = sym.isCaseAccessorMethod && !sym.isPublic for (ddef @ DefDef(_, _, _, _, _, _) <- templ.body ; if isRewrite(ddef.symbol)) { - val original = ddef.symbol val newAcc = deriveMethod(ddef.symbol, name => context.unit.freshTermName(name + "$")) { newAcc => newAcc.makePublic newAcc resetFlag (ACCESSOR | PARAMACCESSOR) diff --git a/src/compiler/scala/tools/nsc/typechecker/Tags.scala b/src/compiler/scala/tools/nsc/typechecker/Tags.scala index d82fbd7c77..45aa1bcbdb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Tags.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Tags.scala @@ -10,7 +10,7 @@ trait Tags { trait Tag { self: Typer => - private def resolveTag(pos: Position, taggedTp: Type, allowMaterialization: Boolean) = beforeTyper { + private def resolveTag(pos: Position, taggedTp: Type, allowMaterialization: Boolean) = enteringTyper { def wrapper (tree: => Tree): Tree = if (allowMaterialization) (context.withMacrosEnabled[Tree](tree)) else (context.withMacrosDisabled[Tree](tree)) wrapper(inferImplicit( EmptyTree, diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala index 48a5a36b00..fb95c952d2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -6,7 +6,6 @@ package scala.tools.nsc package typechecker -import scala.tools.nsc.symtab.Flags._ import scala.collection.mutable import mutable.ListBuffer import util.returning @@ -143,13 +142,6 @@ abstract class TreeCheckers extends Analyzer { currentRun.units foreach (x => wrap(x)(check(x))) } - def printingTypings[T](body: => T): T = { - val saved = global.printTypings - global.printTypings = true - val result = body - global.printTypings = saved - result - } def runWithUnit[T](unit: CompilationUnit)(body: => Unit): Unit = { val unit0 = currentUnit currentRun.currentUnit = unit @@ -186,10 +178,6 @@ abstract class TreeCheckers extends Analyzer { errorFn(t1.pos, "trees differ\n old: " + treestr(t1) + "\n new: " + treestr(t2)) private def typesDiffer(tree: Tree, tp1: Type, tp2: Type) = errorFn(tree.pos, "types differ\n old: " + tp1 + "\n new: " + tp2 + "\n tree: " + tree) - private def ownersDiffer(tree: Tree, shouldBe: Symbol) = { - val sym = tree.symbol - errorFn(tree.pos, sym + " has wrong owner: " + ownerstr(sym.owner) + ", should be: " + ownerstr(shouldBe)) - } /** XXX Disabled reporting of position errors until there is less noise. */ private def noPos(t: Tree) = @@ -278,7 +266,7 @@ abstract class TreeCheckers extends Analyzer { def cond(s: Symbol) = !s.isTerm || s.isMethod || s == sym.owner if (sym.owner != currentOwner) { - val expected = currentOwner.ownerChain find (x => cond(x)) getOrElse fail("DefTree can't find owner: ") + val expected = currentOwner.ownerChain find (x => cond(x)) getOrElse { fail("DefTree can't find owner: ") ; NoSymbol } if (sym.owner != expected) fail(sm"""| | currentOwner chain: ${currentOwner.ownerChain take 3 mkString " -> "} diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 4233bde770..19f0b56e94 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -8,7 +8,6 @@ package typechecker import scala.collection.mutable import scala.collection.mutable.ListBuffer -import scala.util.control.ControlThrowable import scala.util.control.Exception.ultimately import symtab.Flags._ import PartialFunction._ @@ -37,15 +36,6 @@ trait TypeDiagnostics { import global._ import definitions._ - import global.typer.{ infer, context } - - /** The common situation of making sure nothing is erroneous could be - * nicer if Symbols, Types, and Trees all implemented some common interface - * in which isErroneous and similar would be placed. - */ - def noErroneousTypes(tps: Type*) = tps forall (x => !x.isErroneous) - def noErroneousSyms(syms: Symbol*) = syms forall (x => !x.isErroneous) - def noErroneousTrees(trees: Tree*) = trees forall (x => !x.isErroneous) /** For errors which are artifacts of the implementation: such messages * indicate that the restriction may be lifted in the future. @@ -58,7 +48,7 @@ trait TypeDiagnostics { /** A map of Positions to addendums - if an error involves a position in * the map, the addendum should also be printed. */ - private var addendums = perRunCaches.newMap[Position, () => String]() + private val addendums = perRunCaches.newMap[Position, () => String]() private var isTyperInPattern = false /** Devising new ways of communicating error info out of @@ -296,7 +286,6 @@ trait TypeDiagnostics { // distinguished from the other types in the same error message private val savedName = sym.name def restoreName() = sym.name = savedName - def isAltered = sym.name != savedName def modifyName(f: String => String) = sym setName newTypeName(f(sym.name.toString)) /** Prepend java.lang, scala., or Predef. if this type originated @@ -426,6 +415,120 @@ trait TypeDiagnostics { def permanentlyHiddenWarning(pos: Position, hidden: Name, defn: Symbol) = contextWarning(pos, "imported `%s' is permanently hidden by definition of %s".format(hidden, defn.fullLocationString)) + object checkUnused { + val ignoreNames = Set[TermName]("readResolve", "readObject", "writeObject", "writeReplace") + + class UnusedPrivates extends Traverser { + val defnTrees = ListBuffer[MemberDef]() + val targets = mutable.Set[Symbol]() + val setVars = mutable.Set[Symbol]() + val treeTypes = mutable.Set[Type]() + + def defnSymbols = defnTrees.toList map (_.symbol) + def localVars = defnSymbols filter (t => t.isLocal && t.isVar) + + def qualifiesTerm(sym: Symbol) = ( + (sym.isModule || sym.isMethod || sym.isPrivateLocal || sym.isLocal) + && !nme.isLocalName(sym.name) + && !sym.isParameter + && !sym.isParamAccessor // could improve this, but it's a pain + && !sym.isEarlyInitialized // lots of false positives in the way these are encoded + && !(sym.isGetter && sym.accessed.isEarlyInitialized) + ) + def qualifiesType(sym: Symbol) = !sym.isDefinedInPackage + def qualifies(sym: Symbol) = ( + (sym ne null) + && (sym.isTerm && qualifiesTerm(sym) || sym.isType && qualifiesType(sym)) + ) + + override def traverse(t: Tree): Unit = { + t match { + case t: MemberDef if qualifies(t.symbol) => defnTrees += t + case t: RefTree if t.symbol ne null => targets += t.symbol + case Assign(lhs, _) if lhs.symbol != null => setVars += lhs.symbol + case _ => + } + // Only record type references which don't originate within the + // definition of the class being referenced. + if (t.tpe ne null) { + for (tp <- t.tpe ; if !treeTypes(tp) && !currentOwner.ownerChain.contains(tp.typeSymbol)) { + tp match { + case NoType | NoPrefix => + case NullaryMethodType(_) => + case MethodType(_, _) => + case _ => + log(s"$tp referenced from $currentOwner") + treeTypes += tp + } + } + // e.g. val a = new Foo ; new a.Bar ; don't let a be reported as unused. + t.tpe.prefix foreach { + case SingleType(_, sym) => targets += sym + case _ => + } + } + super.traverse(t) + } + def isUnusedType(m: Symbol): Boolean = ( + m.isType + && !m.isTypeParameterOrSkolem // would be nice to improve this + && (m.isPrivate || m.isLocal) + && !(treeTypes.exists(tp => tp exists (t => t.typeSymbolDirect == m))) + ) + def isUnusedTerm(m: Symbol): Boolean = ( + (m.isTerm) + && (m.isPrivate || m.isLocal) + && !targets(m) + && !(m.name == nme.WILDCARD) // e.g. val _ = foo + && !ignoreNames(m.name) // serialization methods + && !isConstantType(m.info.resultType) // subject to constant inlining + && !treeTypes.exists(_ contains m) // e.g. val a = new Foo ; new a.Bar + ) + def unusedTypes = defnTrees.toList filter (t => isUnusedType(t.symbol)) + def unusedTerms = defnTrees.toList filter (v => isUnusedTerm(v.symbol)) + // local vars which are never set, except those already returned in unused + def unsetVars = localVars filter (v => !setVars(v) && !isUnusedTerm(v)) + } + + def apply(unit: CompilationUnit) = { + val p = new UnusedPrivates + p traverse unit.body + val unused = p.unusedTerms + unused foreach { defn: DefTree => + val sym = defn.symbol + val isDefaultGetter = sym.name containsName nme.DEFAULT_GETTER_STRING + val pos = ( + if (defn.pos.isDefined) defn.pos + else if (sym.pos.isDefined) sym.pos + else sym match { + case sym: TermSymbol => sym.referenced.pos + case _ => NoPosition + } + ) + val why = if (sym.isPrivate) "private" else "local" + val what = ( + if (isDefaultGetter) "default argument" + else if (sym.isConstructor) "constructor" + else if (sym.isVar || sym.isGetter && sym.accessed.isVar) "var" + else if (sym.isVal || sym.isGetter && sym.accessed.isVal) "val" + else if (sym.isSetter) "setter" + else if (sym.isMethod) "method" + else if (sym.isModule) "object" + else "term" + ) + unit.warning(pos, s"$why $what in ${sym.owner} is never used") + } + p.unsetVars foreach { v => + unit.warning(v.pos, s"local var ${v.name} in ${v.owner} is never set - it could be a val") + } + p.unusedTypes foreach { t => + val sym = t.symbol + val why = if (sym.isPrivate) "private" else "local" + unit.warning(t.pos, s"$why ${sym.fullLocationString} is never used") + } + } + } + object checkDead { private var expr: Symbol = NoSymbol diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 802b42f6c7..e534e36a0d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -53,22 +53,25 @@ trait Typers extends Modes with Adaptations with Tags { object UnTyper extends Traverser { override def traverse(tree: Tree) = { if (tree != EmptyTree) tree.tpe = null - if (tree.hasSymbol) tree.symbol = NoSymbol + if (tree.hasSymbolField) tree.symbol = NoSymbol super.traverse(tree) } } -/* needed for experimental version where early types can be type arguments - class EarlyMap(clazz: Symbol) extends TypeMap { - def apply(tp: Type): Type = tp match { - case TypeRef(NoPrefix, sym, List()) if (sym hasFlag PRESUPER) => - TypeRef(ThisType(clazz), sym, List()) - case _ => - mapOver(tp) + + sealed abstract class SilentResult[+T] { + @inline final def map[U](f: T => U): SilentResult[U] = this match { + case SilentResultValue(value) => SilentResultValue(f(value)) + case x: SilentTypeError => x + } + @inline final def filter(p: T => Boolean): SilentResult[T] = this match { + case SilentResultValue(value) if !p(value) => SilentTypeError(TypeErrorWrapper(new TypeError(NoPosition, "!p"))) + case _ => this + } + @inline final def orElse[T1 >: T](f: AbsTypeError => T1): T1 = this match { + case SilentResultValue(value) => value + case SilentTypeError(err) => f(err) } } -*/ - - sealed abstract class SilentResult[+T] case class SilentTypeError(err: AbsTypeError) extends SilentResult[Nothing] { } case class SilentResultValue[+T](value: T) extends SilentResult[T] { } @@ -91,7 +94,7 @@ trait Typers extends Modes with Adaptations with Tags { // - we may virtualize matches (if -Xexperimental and there's a suitable __match in scope) // - we synthesize PartialFunction implementations for `x => x match {...}` and `match {...}` when the expected type is PartialFunction // this is disabled by: -Xoldpatmat or interactive compilation (we run it for scaladoc due to SI-5933) - private def newPatternMatching = opt.virtPatmat && !forInteractive //&& !forScaladoc && (phase.id < currentRun.uncurryPhase.id) + private def newPatternMatching = !settings.XoldPatmat.value && !forInteractive //&& !forScaladoc && (phase.id < currentRun.uncurryPhase.id) abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation with Tag with TyperContextErrors { import context0.unit @@ -194,7 +197,7 @@ trait Typers extends Modes with Adaptations with Tags { case PolyType(_, _) => EmptyTree case _ => def wrapImplicit(from: Type): Tree = { - val result = inferImplicit(tree, functionType(from :: Nil, to), reportAmbiguous, true, context, saveErrors) + val result = inferImplicit(tree, functionType(from.withoutAnnotations :: Nil, to), reportAmbiguous, true, context, saveErrors) if (result.subst != EmptyTreeTypeSubstituter) { result.subst traverse tree notifyUndetparamsInferred(result.subst.from, result.subst.to) @@ -227,10 +230,7 @@ trait Typers extends Modes with Adaptations with Tags { case _ => tp } - /** Check that <code>tree</code> is a stable expression. - * - * @param tree ... - * @return ... + /** Check that `tree` is a stable expression. */ def checkStable(tree: Tree): Tree = ( if (treeInfo.isExprSafeToInline(tree)) tree @@ -242,7 +242,7 @@ trait Typers extends Modes with Adaptations with Tags { * of its symbol was not volatile? */ protected def isStableExceptVolatile(tree: Tree) = { - tree.hasSymbol && tree.symbol != NoSymbol && tree.tpe.isVolatile && + tree.hasSymbolField && tree.symbol != NoSymbol && tree.tpe.isVolatile && { val savedTpe = tree.symbol.info val savedSTABLE = tree.symbol getFlag STABLE tree.symbol setInfo AnyRefClass.tpe @@ -284,16 +284,11 @@ trait Typers extends Modes with Adaptations with Tags { ) } - /** Check that type <code>tp</code> is not a subtype of itself. - * - * @param pos ... - * @param tp ... - * @return <code>true</code> if <code>tp</code> is not a subtype of itself. + /** Check that type `tp` is not a subtype of itself. */ def checkNonCyclic(pos: Position, tp: Type): Boolean = { def checkNotLocked(sym: Symbol) = { - sym.initialize - sym.lockOK || { CyclicAliasingOrSubtypingError(pos, sym); false } + sym.initialize.lockOK || { CyclicAliasingOrSubtypingError(pos, sym); false } } tp match { case TypeRef(pre, sym, args) => @@ -304,12 +299,6 @@ trait Typers extends Modes with Adaptations with Tags { case SingleType(pre, sym) => checkNotLocked(sym) -/* - case TypeBounds(lo, hi) => - var ok = true - for (t <- lo) ok = ok & checkNonCyclic(pos, t) - ok -*/ case st: SubType => checkNonCyclic(pos, st.supertype) case ct: CompoundType => @@ -320,14 +309,14 @@ trait Typers extends Modes with Adaptations with Tags { } def checkNonCyclic(pos: Position, tp: Type, lockedSym: Symbol): Boolean = try { - if (!lockedSym.lock(CyclicReferenceError(pos, lockedSym))) false + if (!lockedSym.lock(CyclicReferenceError(pos, tp, lockedSym))) false else checkNonCyclic(pos, tp) } finally { lockedSym.unlock() } def checkNonCyclic(sym: Symbol) { - if (!checkNonCyclic(sym.pos, sym.tpe)) sym.setInfo(ErrorType) + if (!checkNonCyclic(sym.pos, sym.tpe_*)) sym.setInfo(ErrorType) } def checkNonCyclic(defn: Tree, tpt: Tree) { @@ -363,28 +352,13 @@ trait Typers extends Modes with Adaptations with Tags { private var scope: Scope = _ private var hiddenSymbols: List[Symbol] = _ - /** Check that type <code>tree</code> does not refer to private + /** Check that type `tree` does not refer to private * components unless itself is wrapped in something private - * (<code>owner</code> tells where the type occurs). - * - * @param owner ... - * @param tree ... - * @return ... + * (`owner` tells where the type occurs). */ def privates[T <: Tree](owner: Symbol, tree: T): T = check(owner, EmptyScope, WildcardType, tree) - /** Check that type <code>tree</code> does not refer to entities - * defined in scope <code>scope</code>. - * - * @param scope ... - * @param pt ... - * @param tree ... - * @return ... - */ - def locals[T <: Tree](scope: Scope, pt: Type, tree: T): T = - check(NoSymbol, scope, pt, tree) - private def check[T <: Tree](owner: Symbol, scope: Scope, pt: Type, tree: T): T = { this.owner = owner this.scope = scope @@ -460,7 +434,7 @@ trait Typers extends Modes with Adaptations with Tags { } /** The qualifying class - * of a this or super with prefix <code>qual</code>. + * of a this or super with prefix `qual`. * packageOk is equal false when qualifying class symbol */ def qualifyingClass(tree: Tree, qual: Name, packageOK: Boolean) = @@ -546,7 +520,7 @@ trait Typers extends Modes with Adaptations with Tags { } } - /** Does the context of tree <code>tree</code> require a stable type? + /** Does the context of tree `tree` require a stable type? */ private def isStableContext(tree: Tree, mode: Int, pt: Type) = isNarrowable(tree.tpe) && ((mode & (EXPRmode | LHSmode)) == EXPRmode) && @@ -565,11 +539,13 @@ trait Typers extends Modes with Adaptations with Tags { * @return modified tree and new prefix type */ private def makeAccessible(tree: Tree, sym: Symbol, pre: Type, site: Tree): (Tree, Type) = - if (isInPackageObject(sym, pre.typeSymbol)) { + if (context.isInPackageObject(sym, pre.typeSymbol)) { if (pre.typeSymbol == ScalaPackageClass && sym.isTerm) { // short cut some aliases. It seems pattern matching needs this // to notice exhaustiveness and to generate good code when // List extractors are mixed with :: patterns. See Test5 in lists.scala. + // + // TODO SI-6609 Eliminate this special case once the old pattern matcher is removed. def dealias(sym: Symbol) = (atPos(tree.pos.makeTransparent) {gen.mkAttributedRef(sym)} setPos tree.pos, sym.owner.thisType) sym.name match { @@ -598,26 +574,6 @@ trait Typers extends Modes with Adaptations with Tags { (checkAccessible(tree, sym, pre, site), pre) } - /** Is `sym` defined in package object of package `pkg`? - */ - private def isInPackageObject(sym: Symbol, pkg: Symbol) = { - def isInPkgObj(sym: Symbol) = - !sym.owner.isPackage && { - sym.owner.isPackageObjectClass && - sym.owner.owner == pkg || - pkg.isInitialized && { - // need to be careful here to not get a cyclic reference during bootstrap - val pkgobj = pkg.info.member(nme.PACKAGEkw) - pkgobj.isInitialized && - (pkgobj.info.member(sym.name).alternatives contains sym) - } - } - pkg.isPackageClass && { - if (sym.isOverloaded) sym.alternatives forall isInPkgObj - else isInPkgObj(sym) - } - } - /** Post-process an identifier or selection node, performing the following: * 1. Check that non-function pattern expressions are stable * 2. Check that packages and static modules are not used as values @@ -632,7 +588,7 @@ trait Typers extends Modes with Adaptations with Tags { def fail() = NotAValueError(tree, sym) if (tree.isErrorTyped) tree - else if ((mode & (PATTERNmode | FUNmode)) == PATTERNmode && tree.isTerm) { // (1) + else if (inPatternNotFunMode(mode) && tree.isTerm) { // (1) if (sym.isValue) { val tree1 = checkStable(tree) // A module reference in a pattern has type Foo.type, not "object Foo" @@ -666,12 +622,6 @@ trait Typers extends Modes with Adaptations with Tags { case _ => !phase.erasedTypes } - /** - * @param tree ... - * @param mode ... - * @param pt ... - * @return ... - */ def stabilizeFun(tree: Tree, mode: Int, pt: Type): Tree = { val sym = tree.symbol val pre = tree match { @@ -847,26 +797,27 @@ trait Typers extends Modes with Adaptations with Tags { // avoid throwing spurious DivergentImplicit errors if (context.hasErrors) - return setError(tree) - - withCondConstrTyper(treeInfo.isSelfOrSuperConstrCall(tree)){ typer1 => - if (original != EmptyTree && pt != WildcardType) - typer1.silent(tpr => { - val withImplicitArgs = tpr.applyImplicitArgs(tree) - if (tpr.context.hasErrors) tree // silent will wrap it in SilentTypeError anyway - else tpr.typed(withImplicitArgs, mode, pt) - }) match { - case SilentResultValue(result) => - result - case _ => + setError(tree) + else + withCondConstrTyper(treeInfo.isSelfOrSuperConstrCall(tree))(typer1 => + if (original != EmptyTree && pt != WildcardType) ( + typer1 silent { tpr => + val withImplicitArgs = tpr.applyImplicitArgs(tree) + if (tpr.context.hasErrors) tree // silent will wrap it in SilentTypeError anyway + else tpr.typed(withImplicitArgs, mode, pt) + } + orElse { _ => debuglog("fallback on implicits: " + tree + "/" + resetAllAttrs(original)) val tree1 = typed(resetAllAttrs(original), mode, WildcardType) + // Q: `typed` already calls `addAnnotations` and `adapt`. the only difference here is that + // we pass `EmptyTree` as the `original`. intended? added in 2009 (53d98e7d42) by martin. tree1.tpe = addAnnotations(tree1, tree1.tpe) if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, EmptyTree) - } - else - typer1.typed(typer1.applyImplicitArgs(tree), mode, pt) - } + } + ) + else + typer1.typed(typer1.applyImplicitArgs(tree), mode, pt) + ) } def instantiateToMethodType(mt: MethodType): Tree = { @@ -879,7 +830,6 @@ trait Typers extends Modes with Adaptations with Tags { debuglog("eta-expanding " + tree + ":" + tree.tpe + " to " + pt) checkParamsConvertible(tree, tree.tpe) val tree0 = etaExpand(context.unit, tree, this) - // println("eta "+tree+" ---> "+tree0+":"+tree0.tpe+" undet: "+context.undetparams+ " mode: "+Integer.toHexString(mode)) if (context.undetparams.nonEmpty) { // #2624: need to infer type arguments for eta expansion of a polymorphic method @@ -907,7 +857,7 @@ trait Typers extends Modes with Adaptations with Tags { // but this needs additional investigation, because it crashes t5228, gadts1 and maybe something else // tree setType tree.tpe.normalize tree - } else if (tree.hasSymbol && !tree.symbol.typeParams.isEmpty && !inHKMode(mode) && + } else if (tree.hasSymbolField && !tree.symbol.typeParams.isEmpty && !inHKMode(mode) && !(tree.symbol.isJavaDefined && context.unit.isJava)) { // (7) // @M When not typing a higher-kinded type ((mode & HKmode) == 0) // or raw type (tree.symbol.isJavaDefined && context.unit.isJava), types must be of kind *, @@ -915,7 +865,7 @@ trait Typers extends Modes with Adaptations with Tags { // @M TODO: why do kind-* tree's have symbols, while higher-kinded ones don't? MissingTypeParametersError(tree) } else if ( // (7.1) @M: check kind-arity - // @M: removed check for tree.hasSymbol and replace tree.symbol by tree.tpe.symbol (TypeTree's must also be checked here, and they don't directly have a symbol) + // @M: removed check for tree.hasSymbolField and replace tree.symbol by tree.tpe.symbol (TypeTree's must also be checked here, and they don't directly have a symbol) (inHKMode(mode)) && // @M: don't check tree.tpe.symbol.typeParams. check tree.tpe.typeParams!!! // (e.g., m[Int] --> tree.tpe.symbol.typeParams.length == 1, tree.tpe.typeParams.length == 0!) @@ -965,9 +915,11 @@ trait Typers extends Modes with Adaptations with Tags { def adaptConstrPattern(): Tree = { // (5) def hasUnapplyMember(tp: Type) = reallyExists(unapplyMember(tp)) val overloadedExtractorOfObject = tree.symbol filter (sym => hasUnapplyMember(sym.tpe)) - // if the tree's symbol's type does not define an extractor, maybe the tree's type does - // this is the case when we encounter an arbitrary tree as the target of an unapply call (rather than something that looks like a constructor call) - // (for now, this only happens due to wrapClassTagUnapply, but when we support parameterized extractors, it will become more common place) + // if the tree's symbol's type does not define an extractor, maybe the tree's type does. + // this is the case when we encounter an arbitrary tree as the target of an unapply call + // (rather than something that looks like a constructor call.) (for now, this only happens + // due to wrapClassTagUnapply, but when we support parameterized extractors, it will become + // more common place) val extractor = overloadedExtractorOfObject orElse unapplyMember(tree.tpe) if (extractor != NoSymbol) { // if we did some ad-hoc overloading resolution, update the tree's symbol @@ -1037,15 +989,21 @@ trait Typers extends Modes with Adaptations with Tags { def insertApply(): Tree = { assert(!inHKMode(mode), modeString(mode)) //@M - val qual = adaptToName(tree, nme.apply) match { - case id @ Ident(_) => - val pre = if (id.symbol.owner.isPackageClass) id.symbol.owner.thisType - else if (id.symbol.owner.isClass) - context.enclosingSubClassContext(id.symbol.owner).prefix - else NoPrefix - stabilize(id, pre, EXPRmode | QUALmode, WildcardType) - case sel @ Select(qualqual, _) => - stabilize(sel, qualqual.tpe, EXPRmode | QUALmode, WildcardType) + val adapted = adaptToName(tree, nme.apply) + def stabilize0(pre: Type): Tree = stabilize(adapted, pre, EXPRmode | QUALmode, WildcardType) + // TODO reconcile the overlap between Typers#stablize and TreeGen.stabilize + val qual = adapted match { + case This(_) => + gen.stabilize(adapted) + case Ident(_) => + val owner = adapted.symbol.owner + val pre = + if (owner.isPackageClass) owner.thisType + else if (owner.isClass) context.enclosingSubClassContext(owner).prefix + else NoPrefix + stabilize0(pre) + case Select(qualqual, _) => + stabilize0(qualqual.tpe) case other => other } @@ -1120,7 +1078,7 @@ trait Typers extends Modes with Adaptations with Tags { tree.symbol != null && tree.symbol.isTermMacro && // of a macro !tree.attachments.get[SuppressMacroExpansionAttachment.type].isDefined) macroExpand(this, tree, mode, pt) - else if ((mode & (PATTERNmode | FUNmode)) == (PATTERNmode | FUNmode)) + else if (inAllModes(mode, PATTERNmode | FUNmode)) adaptConstrPattern() else if (shouldInsertApply(tree)) insertApply() @@ -1200,9 +1158,9 @@ trait Typers extends Modes with Adaptations with Tags { val found = tree.tpe if (!found.isErroneous && !pt.isErroneous) { if ((!context.reportErrors && isPastTyper) || tree.attachments.get[MacroExpansionAttachment].isDefined) { - val (bound, req) = pt match { - case ExistentialType(qs, tpe) => (qs, tpe) - case _ => (Nil, pt) + val bound = pt match { + case ExistentialType(qs, _) => qs + case _ => Nil } val boundOrSkolems = bound ++ pt.skolemsExceptMethodTypeParams if (boundOrSkolems.nonEmpty) { @@ -1268,12 +1226,10 @@ trait Typers extends Modes with Adaptations with Tags { */ def instantiateExpectingUnit(tree: Tree, mode: Int): Tree = { val savedUndetparams = context.undetparams - silent(_.instantiate(tree, mode, UnitClass.tpe)) match { - case SilentResultValue(t) => t - case _ => - context.undetparams = savedUndetparams - val valueDiscard = atPos(tree.pos)(Block(List(instantiate(tree, mode, WildcardType)), Literal(Constant()))) - typed(valueDiscard, mode, UnitClass.tpe) + silent(_.instantiate(tree, mode, UnitClass.tpe)) orElse { _ => + context.undetparams = savedUndetparams + val valueDiscard = atPos(tree.pos)(Block(List(instantiate(tree, mode, WildcardType)), Literal(Constant()))) + typed(valueDiscard, mode, UnitClass.tpe) } } @@ -1330,16 +1286,12 @@ trait Typers extends Modes with Adaptations with Tags { def doAdapt(restpe: Type) = //util.trace("adaptToArgs "+qual+", name = "+name+", argtpes = "+(args map (_.tpe))+", pt = "+pt+" = ") adaptToMember(qual, HasMethodMatching(name, args map (_.tpe), restpe), reportAmbiguous, saveErrors) - if (pt != WildcardType) { - silent(_ => doAdapt(pt)) match { - case SilentResultValue(result) if result != qual => - result - case _ => - debuglog("fallback on implicits in adaptToArguments: "+qual+" . "+name) - doAdapt(WildcardType) - } - } else + + if (pt == WildcardType) doAdapt(pt) + else silent(_ => doAdapt(pt)) filter (_ != qual) orElse (_ => + logResult(s"fallback on implicits in adaptToArguments: $qual.$name")(doAdapt(WildcardType)) + ) } /** Try to apply an implicit conversion to `qual` so that it contains @@ -1347,27 +1299,24 @@ trait Typers extends Modes with Adaptations with Tags { * account using `adaptToArguments`. */ def adaptToMemberWithArgs(tree: Tree, qual: Tree, name: Name, mode: Int, reportAmbiguous: Boolean, saveErrors: Boolean): Tree = { - def onError(reportError: => Tree): Tree = { - context.tree match { - case Apply(tree1, args) if (tree1 eq tree) && args.nonEmpty => - silent(_.typedArgs(args, mode)) match { - case SilentResultValue(xs) => - val args = xs.asInstanceOf[List[Tree]] - if (args exists (_.isErrorTyped)) - reportError - else - adaptToArguments(qual, name, args, WildcardType, reportAmbiguous, saveErrors) - case _ => - reportError - } - case _ => - reportError - } - } - silent(_.adaptToMember(qual, HasMember(name), false)) match { - case SilentResultValue(res) => res - case SilentTypeError(err) => onError({if (reportAmbiguous) { context.issue(err) }; setError(tree)}) + def onError(reportError: => Tree): Tree = context.tree match { + case Apply(tree1, args) if (tree1 eq tree) && args.nonEmpty => + ( silent (_.typedArgs(args, mode)) + map (_.asInstanceOf[List[Tree]]) + filter (xs => !(xs exists (_.isErrorTyped))) + map (xs => adaptToArguments(qual, name, xs, WildcardType, reportAmbiguous, saveErrors)) + orElse ( _ => reportError) + ) + case _ => + reportError } + + silent(_.adaptToMember(qual, HasMember(name), false)) orElse (err => + onError { + if (reportAmbiguous) context issue err + setError(tree) + } + ) } /** Try to apply an implicit conversion to `qual` to that it contains a @@ -1508,10 +1457,10 @@ trait Typers extends Modes with Adaptations with Tags { // Determine // - supertparams: Missing type parameters from supertype // - supertpe: Given supertype, polymorphic in supertparams - val supertparams = if (supertpt.hasSymbol) supertpt.symbol.typeParams else List() + val supertparams = if (supertpt.hasSymbolField) supertpt.symbol.typeParams else List() var supertpe = supertpt.tpe if (!supertparams.isEmpty) - supertpe = PolyType(supertparams, appliedType(supertpe, supertparams map (_.tpeHK))) + supertpe = PolyType(supertparams, appliedType(supertpe.typeConstructor, supertparams map (_.tpeHK))) // A method to replace a super reference by a New in a supercall def transformSuperCall(scall: Tree): Tree = (scall: @unchecked) match { @@ -1531,7 +1480,6 @@ trait Typers extends Modes with Adaptations with Tags { val (stats, rest) = cstats span (x => !treeInfo.isSuperConstrCall(x)) (stats map (_.duplicate), if (rest.isEmpty) EmptyTree else rest.head.duplicate) } - val cstats1 = if (superCall == EmptyTree) preSuperStats else preSuperStats :+ superCall val cbody1 = treeCopy.Block(cbody, preSuperStats, superCall match { case Apply(_, _) if supertparams.nonEmpty => transformSuperCall(superCall) case _ => cunit.duplicate @@ -1558,7 +1506,7 @@ trait Typers extends Modes with Adaptations with Tags { val preSuperVals = treeInfo.preSuperFields(templ.body) if (preSuperVals.isEmpty && preSuperStats.nonEmpty) - debugwarn("Wanted to zip empty presuper val list with " + preSuperStats) + devWarning("Wanted to zip empty presuper val list with " + preSuperStats) else map2(preSuperStats, preSuperVals)((ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe) @@ -1566,16 +1514,6 @@ trait Typers extends Modes with Adaptations with Tags { if (!supertparams.isEmpty) MissingTypeArgumentsParentTpeError(supertpt) } -/* experimental: early types as type arguments - val hasEarlyTypes = templ.body exists (treeInfo.isEarlyTypeDef) - val earlyMap = new EarlyMap(clazz) - List.mapConserve(supertpt :: mixins){ tpt => - val tpt1 = checkNoEscaping.privates(clazz, tpt) - if (hasEarlyTypes) tpt1 else tpt1 setType earlyMap(tpt1.tpe) - } -*/ - - //Console.println("parents("+clazz") = "+supertpt :: mixins);//DEBUG // Certain parents are added in the parser before it is known whether // that class also declared them as parents. For instance, this is an @@ -1663,9 +1601,6 @@ trait Typers extends Modes with Adaptations with Tags { !selfType.isErroneous && !parent.tpe.isErroneous) { - //Console.println(context.owner);//DEBUG - //Console.println(context.owner.unsafeTypeParams);//DEBUG - //Console.println(List.fromArray(context.owner.info.closure));//DEBUG pending += ParentSelfTypeConformanceError(parent, selfType) if (settings.explaintypes.value) explainTypes(selfType, parent.tpe.typeOfThis) } @@ -1681,13 +1616,6 @@ trait Typers extends Modes with Adaptations with Tags { for (p <- parents) validateParentClass(p, superclazz) } -/* - if (settings.Xshowcls.value != "" && - settings.Xshowcls.value == context.owner.fullName) - println("INFO "+context.owner+ - ", baseclasses = "+(context.owner.info.baseClasses map (_.fullName))+ - ", lin = "+(context.owner.info.baseClasses map (context.owner.thisType.baseType))) -*/ pending.foreach(ErrorUtils.issueTypeError) } @@ -1711,12 +1639,7 @@ trait Typers extends Modes with Adaptations with Tags { } } - /** - * @param cdef ... - * @return ... - */ def typedClassDef(cdef: ClassDef): Tree = { -// attributes(cdef) val clazz = cdef.symbol val typedMods = typedModifiers(cdef.mods) assert(clazz != NoSymbol, cdef) @@ -1745,10 +1668,6 @@ trait Typers extends Modes with Adaptations with Tags { .setType(NoType) } - /** - * @param mdef ... - * @return ... - */ def typedModuleDef(mdef: ModuleDef): Tree = { // initialize all constructors of the linked class: the type completer (Namer.methodSig) // might add default getters to this object. example: "object T; class T(x: Int = 1)" @@ -1806,18 +1725,12 @@ trait Typers extends Modes with Adaptations with Tags { if (txt eq context) namer.enterSym(tree) else newNamer(txt).enterSym(tree) - /** - * @param templ ... - * @param parents1 ... - * <li> <!-- 2 --> - * Check that inner classes do not inherit from Annotation - * </li> - * @return ... + /** <!-- 2 --> Check that inner classes do not inherit from Annotation */ def typedTemplate(templ: Template, parents1: List[Tree]): Template = { val clazz = context.owner // complete lazy annotations - val annots = clazz.annotations + clazz.annotations if (templ.symbol == NoSymbol) templ setSymbol clazz.newLocalDummy(templ.pos) val self1 = templ.self match { @@ -1869,7 +1782,7 @@ trait Typers extends Modes with Adaptations with Tags { } } - treeCopy.Template(templ, parents1, self1, body1) setType clazz.tpe + treeCopy.Template(templ, parents1, self1, body1) setType clazz.tpe_* } /** Remove definition annotations from modifiers (they have been saved @@ -1887,27 +1800,19 @@ trait Typers extends Modes with Adaptations with Tags { def typedModifiers(mods: Modifiers): Modifiers = mods.copy(annotations = Nil) setPositions mods.positions - /** - * @param vdef ... - * @return ... - */ def typedValDef(vdef: ValDef): ValDef = { -// attributes(vdef) val sym = vdef.symbol.initialize val typer1 = constrTyperIf(sym.isParameter && sym.owner.isConstructor) val typedMods = typedModifiers(vdef.mods) // complete lazy annotations - val annots = sym.annotations - var tpt1 = checkNoEscaping.privates(sym, typer1.typedType(vdef.tpt)) + sym.annotations + val tpt1 = checkNoEscaping.privates(sym, typer1.typedType(vdef.tpt)) checkNonCyclic(vdef, tpt1) - if (sym.hasAnnotation(definitions.VolatileAttr)) { - if (!sym.isMutable) + if (sym.hasAnnotation(definitions.VolatileAttr) && !sym.isMutable) VolatileValueError(vdef) - else if (sym.isFinal) - FinalVolatileVarError(vdef) - } + val rhs1 = if (vdef.rhs.isEmpty) { if (sym.isVariable && sym.owner.isTerm && !sym.isLazy && !isPastTyper) @@ -1936,10 +1841,6 @@ trait Typers extends Modes with Adaptations with Tags { } /** Enter all aliases of local parameter accessors. - * - * @param clazz ... - * @param vparamss ... - * @param rhs ... */ def computeParamAliases(clazz: Symbol, vparamss: List[List[ValDef]], rhs: Tree) { debuglog(s"computing param aliases for $clazz:${clazz.primaryConstructor.tpe}:$rhs") @@ -2034,7 +1935,7 @@ trait Typers extends Modes with Adaptations with Tags { f(subTree) } - /** Check if a structurally defined method violates implementation restrictions. + /** Check if a structurally defined method violates implementation restrictions. * A method cannot be called if it is a non-private member of a refinement type * and if its parameter's types are any of: * - the self-type of the refinement @@ -2092,18 +1993,14 @@ trait Typers extends Modes with Adaptations with Tags { val enclClass = context.enclClass.owner def defineAlias(name: Name) = if (context.scope.lookup(name) == NoSymbol) { - lookupVariable(name.toString.substring(1), enclClass) match { - case Some(repl) => - silent(_.typedTypeConstructor(stringParser(repl).typ())) match { - case SilentResultValue(tpt) => - val alias = enclClass.newAliasType(name.toTypeName, useCase.pos) - val tparams = cloneSymbolsAtOwner(tpt.tpe.typeSymbol.typeParams, alias) - val newInfo = genPolyType(tparams, appliedType(tpt.tpe, tparams map (_.tpe))) - alias setInfo newInfo - context.scope.enter(alias) - case _ => - } - case _ => + lookupVariable(name.toString.substring(1), enclClass) foreach { repl => + silent(_.typedTypeConstructor(stringParser(repl).typ())) map { tpt => + val alias = enclClass.newAliasType(name.toTypeName, useCase.pos) + val tparams = cloneSymbolsAtOwner(tpt.tpe.typeSymbol.typeParams, alias) + val newInfo = genPolyType(tparams, appliedType(tpt.tpe, tparams map (_.tpe))) + alias setInfo newInfo + context.scope.enter(alias) + } } } for (tree <- trees; t <- tree) @@ -2119,10 +2016,6 @@ trait Typers extends Modes with Adaptations with Tags { useCase.defined foreach (sym => println("defined use cases: %s:%s".format(sym, sym.tpe))) } - /** - * @param ddef ... - * @return ... - */ def typedDefDef(ddef: DefDef): DefDef = { val meth = ddef.symbol.initialize @@ -2142,13 +2035,13 @@ trait Typers extends Modes with Adaptations with Tags { val vparamss1 = ddef.vparamss mapConserve (_ mapConserve typedValDef) // complete lazy annotations - val annots = meth.annotations + meth.annotations for (vparams1 <- vparamss1; vparam1 <- vparams1 dropRight 1) if (isRepeatedParamType(vparam1.symbol.tpe)) StarParamNotLastError(vparam1) - var tpt1 = checkNoEscaping.privates(meth, typedType(ddef.tpt)) + val tpt1 = checkNoEscaping.privates(meth, typedType(ddef.tpt)) checkNonCyclic(ddef, tpt1) ddef.tpt.setType(tpt1.tpe) val typedMods = typedModifiers(ddef.mods) @@ -2218,7 +2111,7 @@ trait Typers extends Modes with Adaptations with Tags { val tparams1 = tdef.tparams mapConserve typedTypeDef val typedMods = typedModifiers(tdef.mods) // complete lazy annotations - val annots = tdef.symbol.annotations + tdef.symbol.annotations // @specialized should not be pickled when compiling with -no-specialize if (settings.nospecialization.value && currentRun.compiles(tdef.symbol)) { @@ -2275,12 +2168,6 @@ trait Typers extends Modes with Adaptations with Tags { } } - /** - * @param block ... - * @param mode ... - * @param pt ... - * @return ... - */ def typedBlock(block: Block, mode: Int, pt: Type): Block = { val syntheticPrivates = new ListBuffer[Symbol] try { @@ -2353,12 +2240,6 @@ trait Typers extends Modes with Adaptations with Tags { } } - /** - * @param cdef ... - * @param pattpe ... - * @param pt ... - * @return ... - */ def typedCase(cdef: CaseDef, pattpe: Type, pt: Type): CaseDef = { // verify no _* except in last position for (Apply(_, xs) <- cdef.pat ; x <- xs dropRight 1 ; if treeInfo isStar x) @@ -2432,7 +2313,7 @@ trait Typers extends Modes with Adaptations with Tags { val casesTyped = typedCases(cases, selectorTp, pt) val (resTp, needAdapt) = - if (opt.virtPatmat) ptOrLubPacked(casesTyped, pt) + if (!settings.XoldPatmat.value) ptOrLubPacked(casesTyped, pt) else ptOrLub(casesTyped map (_.tpe), pt) val casesAdapted = if (!needAdapt) casesTyped else casesTyped map (adaptCase(_, mode, resTp)) @@ -2444,15 +2325,12 @@ trait Typers extends Modes with Adaptations with Tags { // (virtualized matches are expanded during type checking so they have the full context available) // otherwise, do nothing: matches are translated during phase `patmat` (unless -Xoldpatmat) def virtualizedMatch(match_ : Match, mode: Int, pt: Type) = { - import patmat.{vpmName, PureMatchTranslator, OptimizingMatchTranslator} + import patmat.{ vpmName, PureMatchTranslator } // TODO: add fallback __match sentinel to predef val matchStrategy: Tree = - if (!(newPatternMatching && opt.experimental && context.isNameInScope(vpmName._match))) null // fast path, avoiding the next line if there's no __match to be seen - else newTyper(context.makeImplicit(reportAmbiguousErrors = false)).silent(_.typed(Ident(vpmName._match), EXPRmode, WildcardType), reportAmbiguousErrors = false) match { - case SilentResultValue(ms) => ms - case _ => null - } + if (!(newPatternMatching && settings.Xexperimental.value && context.isNameInScope(vpmName._match))) null // fast path, avoiding the next line if there's no __match to be seen + else newTyper(context.makeImplicit(reportAmbiguousErrors = false)).silent(_.typed(Ident(vpmName._match), EXPRmode, WildcardType), reportAmbiguousErrors = false) orElse (_ => null) if (matchStrategy ne null) // virtualize typed((new PureMatchTranslator(this.asInstanceOf[patmat.global.analyzer.Typer] /*TODO*/, matchStrategy)).translateMatch(match_), mode, pt) @@ -2478,7 +2356,6 @@ trait Typers extends Modes with Adaptations with Tags { assert(isPartial) private val anonClass = context.owner.newAnonymousFunctionClass(tree.pos) - private val funThis = This(anonClass) anonClass addAnnotation AnnotationInfo(SerialVersionUIDAttr.tpe, List(Literal(Constant(0))), List()) @@ -2628,12 +2505,6 @@ trait Typers extends Modes with Adaptations with Tags { override def mkSel(params: List[Symbol]) = sel.duplicate } - /** - * @param fun ... - * @param mode ... - * @param pt ... - * @return ... - */ private def typedFunction(fun: Function, mode: Int, pt: Type): Tree = { val numVparams = fun.vparams.length if (numVparams > definitions.MaxFunctionArity) @@ -2659,15 +2530,13 @@ trait Typers extends Modes with Adaptations with Tags { else { fun match { case etaExpansion(vparams, fn, args) => - silent(_.typed(fn, forFunMode(mode), pt)) match { - case SilentResultValue(fn1) if context.undetparams.isEmpty => - // if context,undetparams is not empty, the function was polymorphic, - // so we need the missing arguments to infer its type. See #871 - //println("typing eta "+fun+":"+fn1.tpe+"/"+context.undetparams) - val ftpe = normalize(fn1.tpe) baseType FunctionClass(numVparams) - if (isFunctionType(ftpe) && isFullyDefined(ftpe)) - return typedFunction(fun, mode, ftpe) - case _ => + silent(_.typed(fn, forFunMode(mode), pt)) filter (_ => context.undetparams.isEmpty) map { fn1 => + // if context,undetparams is not empty, the function was polymorphic, + // so we need the missing arguments to infer its type. See #871 + //println("typing eta "+fun+":"+fn1.tpe+"/"+context.undetparams) + val ftpe = normalize(fn1.tpe) baseType FunctionClass(numVparams) + if (isFunctionType(ftpe) && isFullyDefined(ftpe)) + return typedFunction(fun, mode, ftpe) } case _ => } @@ -2693,16 +2562,13 @@ trait Typers extends Modes with Adaptations with Tags { if (context.retyping) context.scope enter vparam.symbol vparam.symbol } - val vparams = fun.vparams mapConserve (typedValDef) - // for (vparam <- vparams) { - // checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); () - // } + val vparams = fun.vparams mapConserve typedValDef val formals = vparamSyms map (_.tpe) - val body1 = typed(fun.body, respt) - val restpe = packedType(body1, fun.symbol).deconst.resultType - val funtpe = typeRef(clazz.tpe.prefix, clazz, formals :+ restpe) - // body = checkNoEscaping.locals(context.scope, restpe, body) - treeCopy.Function(fun, vparams, body1).setType(funtpe) + val body1 = typed(fun.body, respt) + val restpe = packedType(body1, fun.symbol).deconst.resultType + val funtpe = appliedType(clazz, formals :+ restpe: _*) + + treeCopy.Function(fun, vparams, body1) setType funtpe } } } @@ -2733,17 +2599,6 @@ trait Typers extends Modes with Adaptations with Tags { case Some(imp1: Import) => imp1 case _ => log("unhandled import: "+imp+" in "+unit); imp } - private def isWarnablePureExpression(tree: Tree) = tree match { - case EmptyTree | Literal(Constant(())) => false - case _ => - !tree.isErrorTyped && (treeInfo isExprSafeToInline tree) && { - val sym = tree.symbol - (sym == null) || !(sym.isModule || sym.isLazy) || { - debuglog("'Pure' but side-effecting expression in statement position: " + tree) - false - } - } - } def typedStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { val inBlock = exprOwner == context.owner @@ -2780,7 +2635,7 @@ trait Typers extends Modes with Adaptations with Tags { ConstructorsOrderError(stat) } - if (isWarnablePureExpression(result)) context.warning(stat.pos, + if (treeInfo.isPureExprForWarningPurposes(result)) context.warning(stat.pos, "a pure expression does nothing in statement position; " + "you may be omitting necessary parentheses" ) @@ -2964,21 +2819,20 @@ trait Typers extends Modes with Adaptations with Tags { def duplErrorTree(err: AbsTypeError) = { issue(err); duplErrTree } def preSelectOverloaded(fun: Tree): Tree = { - if (fun.hasSymbol && fun.symbol.isOverloaded) { + if (fun.hasSymbolField && fun.symbol.isOverloaded) { // remove alternatives with wrong number of parameters without looking at types. - // less expensive than including them in inferMethodAlternatvie (see below). + // less expensive than including them in inferMethodAlternative (see below). def shapeType(arg: Tree): Type = arg match { case Function(vparams, body) => - functionType(vparams map (vparam => AnyClass.tpe), shapeType(body)) + functionType(vparams map (_ => AnyClass.tpe), shapeType(body)) case AssignOrNamedArg(Ident(name), rhs) => NamedType(name, shapeType(rhs)) case _ => NothingClass.tpe } val argtypes = args map shapeType - val pre = fun.symbol.tpe.prefix - - var sym = fun.symbol filter { alt => + val pre = fun.symbol.tpe.prefix + var sym = fun.symbol filter { alt => // must use pt as expected type, not WildcardType (a tempting quick fix to #2665) // now fixed by using isWeaklyCompatible in exprTypeArgs // TODO: understand why exactly -- some types were not inferred anymore (`ant clean quick.bin` failed) @@ -2989,16 +2843,15 @@ trait Typers extends Modes with Adaptations with Tags { // Types: "refs = Array(Map(), Map())". I determined that inference fails if there are at // least two invariant type parameters. See the test case I checked in to help backstop: // pos/isApplicableSafe.scala. - isApplicableSafe(context.undetparams, followApply(pre.memberType(alt)), argtypes, pt) + isApplicableSafe(context.undetparams, followApply(pre memberType alt), argtypes, pt) } if (sym.isOverloaded) { - val sym1 = sym filter (alt => { - // eliminate functions that would result from tupling transforms - // keeps alternatives with repeated params - hasExactlyNumParams(followApply(alt.tpe), argtypes.length) || - // also keep alts which define at least one default - alt.tpe.paramss.exists(_.exists(_.hasDefault)) - }) + // eliminate functions that would result from tupling transforms + // keeps alternatives with repeated params + val sym1 = sym filter (alt => + isApplicableBasedOnArity(pre memberType alt, argtypes.length, varargsStar = false, tuplingAllowed = false) + || alt.tpe.params.exists(_.hasDefault) + ) if (sym1 != NoSymbol) sym = sym1 } if (sym == NoSymbol) fun @@ -3012,16 +2865,19 @@ trait Typers extends Modes with Adaptations with Tags { case OverloadedType(pre, alts) => def handleOverloaded = { val undetparams = context.extractUndetparams() - - val argtpes = new ListBuffer[Type] - val amode = forArgMode(fun, mode) + val argtpes = new ListBuffer[Type] + val amode = forArgMode(fun, mode) val args1 = args map { case arg @ AssignOrNamedArg(Ident(name), rhs) => // named args: only type the righthand sides ("unknown identifier" errors otherwise) val rhs1 = typedArg(rhs, amode, BYVALmode, WildcardType) argtpes += NamedType(name, rhs1.tpe.deconst) // the assign is untyped; that's ok because we call doTypedApply - atPos(arg.pos) { new AssignOrNamedArg(arg.lhs, rhs1) } + treeCopy.AssignOrNamedArg(arg, arg.lhs, rhs1) + case arg @ Typed(repeated, Ident(tpnme.WILDCARD_STAR)) => + val arg1 = typedArg(arg, amode, BYVALmode, WildcardType) + argtpes += RepeatedType(arg1.tpe.deconst) + arg1 case arg => val arg1 = typedArg(arg, amode, BYVALmode, WildcardType) argtpes += arg1.tpe.deconst @@ -3031,7 +2887,7 @@ trait Typers extends Modes with Adaptations with Tags { if (context.hasErrors) setError(tree) else { - inferMethodAlternative(fun, undetparams, argtpes.toList, pt, varArgsOnly = treeInfo.isWildcardStarArgList(args)) + inferMethodAlternative(fun, undetparams, argtpes.toList, pt) doTypedApply(tree, adapt(fun, forFunMode(mode), WildcardType), args1, mode, pt) } } @@ -3040,22 +2896,20 @@ trait Typers extends Modes with Adaptations with Tags { case mt @ MethodType(params, _) => val paramTypes = mt.paramTypes // repeat vararg as often as needed, remove by-name - val formals = formalTypes(paramTypes, args.length) + val argslen = args.length + val formals = formalTypes(paramTypes, argslen) /** Try packing all arguments into a Tuple and apply `fun` * to that. This is the last thing which is tried (after * default arguments) */ - def tryTupleApply: Option[Tree] = { - // if 1 formal, 1 arg (a tuple), otherwise unmodified args - val tupleArgs = actualArgs(tree.pos.makeTransparent, args, formals.length) - - if (!sameLength(tupleArgs, args) && !isUnitForVarArgs(args, params)) { + def tryTupleApply: Option[Tree] = ( + if (eligibleForTupleConversion(paramTypes, argslen) && !phase.erasedTypes) { + val tupleArgs = List(atPos(tree.pos.makeTransparent)(gen.mkTuple(args))) // expected one argument, but got 0 or >1 ==> try applying to tuple // the inner "doTypedApply" does "extractUndetparams" => restore when it fails val savedUndetparams = context.undetparams - silent(_.doTypedApply(tree, fun, tupleArgs, mode, pt)) match { - case SilentResultValue(t) => + silent(_.doTypedApply(tree, fun, tupleArgs, mode, pt)) map { t => // Depending on user options, may warn or error here if // a Unit or tuple was inserted. Some(t) filter (tupledTree => @@ -3063,12 +2917,10 @@ trait Typers extends Modes with Adaptations with Tags { || tupledTree.symbol == null || checkValidAdaptation(tupledTree, args) ) - case _ => - context.undetparams = savedUndetparams - None - } - } else None - } + } orElse { _ => context.undetparams = savedUndetparams ; None } + } + else None + ) /** Treats an application which uses named or default arguments. * Also works if names + a vararg used: when names are used, the vararg @@ -3245,15 +3097,14 @@ trait Typers extends Modes with Adaptations with Tags { } else arg1 } val args1 = map2(args, formals)(typedArgToPoly) - if (args1 exists { _.isErrorTyped }) duplErrTree + if (args1 exists {_.isErrorTyped}) duplErrTree else { - debuglog("infer method inst " + fun + ", tparams = " + tparams + ", args = " + args1.map(_.tpe) + ", pt = " + pt + ", lobounds = " + tparams.map(_.tpe.bounds.lo) + ", parambounds = " + tparams.map(_.info)) //debug + debuglog("infer method inst "+fun+", tparams = "+tparams+", args = "+args1.map(_.tpe)+", pt = "+pt+", lobounds = "+tparams.map(_.tpe.bounds.lo)+", parambounds = "+tparams.map(_.info)) //debug // define the undetparams which have been fixed by this param list, replace the corresponding symbols in "fun" // returns those undetparams which have not been instantiated. val undetparams = inferMethodInstance(fun, tparams, args1, pt) - val result = doTypedApply(tree, fun, args1, mode, pt) - context.undetparams = undetparams - result + try doTypedApply(tree, fun, args1, mode, pt) + finally context.undetparams = undetparams } } handlePolymorphicCall @@ -3336,10 +3187,7 @@ trait Typers extends Modes with Adaptations with Tags { if (formals == null) duplErrorTree(WrongNumberOfArgsError(tree, fun)) else { val args1 = typedArgs(args, mode, formals, formalsExpanded) - // This used to be the following (failing) assert: - // assert(isFullyDefined(pt), tree+" ==> "+UnApply(fun1, args1)+", pt = "+pt) - // I modified as follows. See SI-1048. - val pt1 = if (isFullyDefined(pt)) pt else makeFullyDefined(pt) + val pt1 = if (isFullyDefined(pt)) pt else makeFullyDefined(pt) // SI-1048 val itype = glb(List(pt1, arg.tpe)) arg.tpe = pt1 // restore type (arg is a dummy tree, just needs to pass typechecking) @@ -3377,16 +3225,16 @@ trait Typers extends Modes with Adaptations with Tags { // if there's a ClassTag that allows us to turn the unchecked type test for `pt` into a checked type test // return the corresponding extractor (an instance of ClassTag[`pt`]) - def extractorForUncheckedType(pos: Position, pt: Type): Option[Tree] = if (!opt.virtPatmat || isPastTyper) None else { + def extractorForUncheckedType(pos: Position, pt: Type): Option[Tree] = if (settings.XoldPatmat.value || isPastTyper) None else { // only look at top-level type, can't (reliably) do anything about unchecked type args (in general) pt.normalize.typeConstructor match { // if at least one of the types in an intersection is checkable, use the checkable ones // this avoids problems as in run/matchonseq.scala, where the expected type is `Coll with scala.collection.SeqLike` // Coll is an abstract type, but SeqLike of course is not - case RefinedType(parents, _) if (parents.length >= 2) && (parents.exists(tp => !infer.containsUnchecked(tp))) => + case RefinedType(ps, _) if ps.length > 1 && (ps exists infer.isCheckable) => None - case ptCheckable if infer.containsUnchecked(ptCheckable) => + case ptCheckable if infer isUncheckable ptCheckable => val classTagExtractor = resolveClassTag(pos, ptCheckable) if (classTagExtractor != EmptyTree && unapplyMember(classTagExtractor.tpe) != NoSymbol) @@ -3550,35 +3398,23 @@ trait Typers extends Modes with Adaptations with Tags { // local dummy fixes SI-5544 val localTyper = newTyper(context.make(ann, context.owner.newLocalDummy(ann.pos))) localTyper.typed(ann, mode, annClass.tpe) - } else { - // Since a selfsym is supplied, the annotation should have - // an extra "self" identifier in scope for type checking. - // This is implemented by wrapping the rhs - // in a function like "self => rhs" during type checking, - // and then stripping the "self =>" and substituting - // in the supplied selfsym. + } + else { + // Since a selfsym is supplied, the annotation should have an extra + // "self" identifier in scope for type checking. This is implemented + // by wrapping the rhs in a function like "self => rhs" during type + // checking, and then stripping the "self =>" and substituting in + // the supplied selfsym. val funcparm = ValDef(NoMods, nme.self, TypeTree(selfsym.info), EmptyTree) - val func = Function(List(funcparm), ann.duplicate) - // The .duplicate of annot.constr - // deals with problems that - // accur if this annotation is - // later typed again, which - // the compiler sometimes does. - // The problem is that "self" - // ident's within annot.constr - // will retain the old symbol - // from the previous typing. - val fun1clazz = FunctionClass(1) - val funcType = typeRef(fun1clazz.tpe.prefix, - fun1clazz, - List(selfsym.info, annClass.tpe)) - - (typed(func, mode, funcType): @unchecked) match { - case t @ Function(List(arg), rhs) => - val subs = - new TreeSymSubstituter(List(arg.symbol),List(selfsym)) - subs(rhs) - } + // The .duplicate of annot.constr deals with problems that accur + // if this annotation is later typed again, which the compiler + // sometimes does. The problem is that "self" ident's within + // annot.constr will retain the old symbol from the previous typing. + val func = Function(funcparm :: Nil, ann.duplicate) + val funcType = appliedType(FunctionClass(1), selfsym.info, annClass.tpe_*) + val Function(arg :: Nil, rhs) = typed(func, mode, funcType) + + rhs.substituteSymbols(arg.symbol :: Nil, selfsym :: Nil) } def annInfo(t: Tree): AnnotationInfo = t match { @@ -3799,11 +3635,11 @@ trait Typers extends Modes with Adaptations with Tags { if (wc.symbol == NoSymbol) { namer.enterSym(wc); wc.symbol setFlag EXISTENTIAL } else context.scope enter wc.symbol val whereClauses1 = typedStats(tree.whereClauses, context.owner) - for (vd @ ValDef(_, _, _, _) <- tree.whereClauses) + for (vd @ ValDef(_, _, _, _) <- whereClauses1) if (vd.symbol.tpe.isVolatile) AbstractionFromVolatileTypeError(vd) val tpt1 = typedType(tree.tpt, mode) - existentialTransform(tree.whereClauses map (_.symbol), tpt1.tpe)((tparams, tp) => + existentialTransform(whereClauses1 map (_.symbol), tpt1.tpe)((tparams, tp) => TypeTree(newExistentialType(tparams, tp)) setOriginal tree ) } @@ -3969,12 +3805,8 @@ trait Typers extends Modes with Adaptations with Tags { } } - def wrapErrors(tree: Tree, typeTree: Typer => Tree): Tree = { - silent(typeTree) match { - case SilentResultValue(r) => r - case SilentTypeError(err) => DynamicRewriteError(tree, err) - } - } + def wrapErrors(tree: Tree, typeTree: Typer => Tree): Tree = + silent(typeTree) orElse (err => DynamicRewriteError(tree, err)) } final def deindentTyping() = context.typingIndentLevel -= 2 @@ -3990,14 +3822,24 @@ trait Typers extends Modes with Adaptations with Tags { def typed1(tree: Tree, mode: Int, pt: Type): Tree = { def isPatternMode = inPatternMode(mode) - - //Console.println("typed1("+tree.getClass()+","+Integer.toHexString(mode)+","+pt+")") - //@M! get the type of the qualifier in a Select tree, otherwise: NoType - def prefixType(fun: Tree): Type = fun match { - case Select(qualifier, _) => qualifier.tpe -// case Ident(name) => ?? - case _ => NoType - } + def inPatternConstructor = inAllModes(mode, PATTERNmode | FUNmode) + def isQualifierMode = (mode & QUALmode) != 0 + + // Lookup in the given class using the root mirror. + def lookupInOwner(owner: Symbol, name: Name): Symbol = + if (isQualifierMode) rootMirror.missingHook(owner, name) else NoSymbol + + // Lookup in the given qualifier. Used in last-ditch efforts by typedIdent and typedSelect. + def lookupInRoot(name: Name): Symbol = lookupInOwner(rootMirror.RootClass, name) + def lookupInEmpty(name: Name): Symbol = lookupInOwner(rootMirror.EmptyPackageClass, name) + def lookupInQualifier(qual: Tree, name: Name): Symbol = ( + if (name == nme.ERROR || qual.tpe.widen.isErroneous) + NoSymbol + else lookupInOwner(qual.tpe.typeSymbol, name) orElse { + NotAMemberError(tree, qual, name) + NoSymbol + } + ) def typedAnnotated(atd: Annotated): Tree = { val ann = atd.annot @@ -4097,7 +3939,7 @@ trait Typers extends Modes with Adaptations with Tags { if (name != tpnme.WILDCARD) namer.enterInScope(sym) else context.scope.enter(sym) - tree setSymbol sym setType sym.tpe + tree setSymbol sym setType sym.tpeHK case name: TermName => val sym = @@ -4193,7 +4035,7 @@ trait Typers extends Modes with Adaptations with Tags { // in the special (though common) case where the types are equal, it pays to pack before comparing // especially virtpatmat needs more aggressive unification of skolemized types // this breaks src/library/scala/collection/immutable/TrieIterator.scala - if ( opt.virtPatmat && !isPastTyper + if ( !settings.XoldPatmat.value && !isPastTyper && thenp1.tpe.annotations.isEmpty && elsep1.tpe.annotations.isEmpty // annotated types need to be lubbed regardless (at least, continations break if you by pass them like this) && thenTp =:= elseTp ) (thenp1.tpe.deconst, false) // use unpacked type. Important to deconst, as is done in ptOrLub, otherwise `if (???) 0 else 0` evaluates to 0 (SI-6331) @@ -4266,7 +4108,7 @@ trait Typers extends Modes with Adaptations with Tags { val tpt1 = { val tpt0 = typedTypeConstructor(tpt) if (checkStablePrefixClassType(tpt0)) - if (tpt0.hasSymbol && !tpt0.symbol.typeParams.isEmpty) { + if (tpt0.hasSymbolField && !tpt0.symbol.typeParams.isEmpty) { context.undetparams = cloneSymbols(tpt0.symbol.typeParams) notifyUndetparamsAdded(context.undetparams) TypeTree().setOriginal(tpt0) @@ -4296,7 +4138,7 @@ trait Typers extends Modes with Adaptations with Tags { NotAMemberError(tpt, TypeTree(tp), nme.CONSTRUCTOR) setError(tpt) } - else if (!( tp == sym.thisSym.tpe // when there's no explicit self type -- with (#3612) or without self variable + else if (!( tp == sym.thisSym.tpe_* // when there's no explicit self type -- with (#3612) or without self variable // sym.thisSym.tpe == tp.typeOfThis (except for objects) || narrowRhs(tp) <:< tp.typeOfThis || phase.erasedTypes @@ -4344,10 +4186,6 @@ trait Typers extends Modes with Adaptations with Tags { UnderscoreEtaError(expr1) } - /** - * @param args ... - * @return ... - */ def tryTypedArgs(args: List[Tree], mode: Int): Option[List[Tree]] = { val c = context.makeSilent(false) c.retyping = true @@ -4421,12 +4259,7 @@ trait Typers extends Modes with Adaptations with Tags { setError(treeCopy.Apply(tree, fun, args)) } - silent(_.doTypedApply(tree, fun, args, mode, pt)) match { - case SilentResultValue(t) => - t - case SilentTypeError(err) => - onError(err) - } + silent(_.doTypedApply(tree, fun, args, mode, pt)) orElse onError } def normalTypedApply(tree: Tree, fun: Tree, args: List[Tree]) = { @@ -4477,15 +4310,6 @@ trait Typers extends Modes with Adaptations with Tags { if (useTry) tryTypedApply(fun2, args) else doTypedApply(tree, fun2, args, mode, pt) - /* - if (fun2.hasSymbol && fun2.symbol.isConstructor && (mode & EXPRmode) != 0) { - res.tpe = res.tpe.notNull - } - */ - // TODO: In theory we should be able to call: - //if (fun2.hasSymbol && fun2.symbol.name == nme.apply && fun2.symbol.owner == ArrayClass) { - // But this causes cyclic reference for Array class in Cleanup. It is easy to overcome this - // by calling ArrayClass.info here (or some other place before specialize). if (fun2.symbol == Array_apply && !res.isErrorTyped) { val checked = gen.mkCheckInit(res) // this check is needed to avoid infinite recursion in Duplicators @@ -4500,37 +4324,36 @@ trait Typers extends Modes with Adaptations with Tags { } } - def typedApply(tree: Apply) = { - val fun = tree.fun - val args = tree.args - fun match { - case Block(stats, expr) => - typed1(atPos(tree.pos)(Block(stats, Apply(expr, args) setPos tree.pos.makeTransparent)), mode, pt) - case _ => - normalTypedApply(tree, fun, args) match { - case Apply(Select(New(tpt), name), args) - if (tpt.tpe != null && - tpt.tpe.typeSymbol == ArrayClass && - args.length == 1 && - erasure.GenericArray.unapply(tpt.tpe).isDefined) => // !!! todo simplify by using extractor - // convert new Array[T](len) to evidence[ClassTag[T]].newArray(len) - // convert new Array^N[T](len) for N > 1 to evidence[ClassTag[Array[...Array[T]...]]].newArray(len), where Array HK gets applied (N-1) times - // [Eugene] no more MaxArrayDims. ClassTags are flexible enough to allow creation of arrays of arbitrary dimensionality (w.r.t JVM restrictions) - val Some((level, componentType)) = erasure.GenericArray.unapply(tpt.tpe) - val tagType = List.iterate(componentType, level)(tpe => appliedType(ArrayClass.toTypeConstructor, List(tpe))).last - atPos(tree.pos) { - val tag = resolveClassTag(tree.pos, tagType) - if (tag.isEmpty) MissingClassTagError(tree, tagType) - else typed(new ApplyToImplicitArgs(Select(tag, nme.newArray), args)) + // convert new Array[T](len) to evidence[ClassTag[T]].newArray(len) + // convert new Array^N[T](len) for N > 1 to evidence[ClassTag[Array[...Array[T]...]]].newArray(len) + // where Array HK gets applied (N-1) times + object ArrayInstantiation { + def unapply(tree: Apply) = tree match { + case Apply(Select(New(tpt), name), arg :: Nil) if tpt.tpe != null && tpt.tpe.typeSymbol == ArrayClass => + Some(tpt.tpe) collect { + case erasure.GenericArray(level, componentType) => + val tagType = (1 until level).foldLeft(componentType)((res, _) => arrayType(res)) + + resolveClassTag(tree.pos, tagType) match { + case EmptyTree => MissingClassTagError(tree, tagType) + case tag => atPos(tree.pos)(new ApplyToImplicitArgs(Select(tag, nme.newArray), arg :: Nil)) } - case Apply(Select(fun, nme.apply), _) if treeInfo.isSuperConstrCall(fun) => //SI-5696 - TooManyArgumentListsForConstructor(tree) - case tree1 => - tree1 } + case _ => None } } + def typedApply(tree: Apply) = tree match { + case Apply(Block(stats, expr), args) => + typed1(atPos(tree.pos)(Block(stats, Apply(expr, args) setPos tree.pos.makeTransparent)), mode, pt) + case Apply(fun, args) => + normalTypedApply(tree, fun, args) match { + case ArrayInstantiation(tree1) => typed(tree1, mode, pt) + case Apply(Select(fun, nme.apply), _) if treeInfo.isSuperConstrCall(fun) => TooManyArgumentListsForConstructor(tree) //SI-5696 + case tree1 => tree1 + } + } + def convertToAssignment(fun: Tree, qual: Tree, name: Name, args: List[Tree]): Tree = { val prefix = name.toTermName stripSuffix nme.EQL def mkAssign(vble: Tree): Tree = @@ -4584,8 +4407,6 @@ trait Typers extends Modes with Adaptations with Tags { case This(_) => qual1.symbol case _ => qual1.tpe.typeSymbol } - //println(clazz+"/"+qual1.tpe.typeSymbol+"/"+qual1) - def findMixinSuper(site: Type): Type = { var ps = site.parents filter (_.typeSymbol.name == mix) if (ps.isEmpty) @@ -4593,11 +4414,6 @@ trait Typers extends Modes with Adaptations with Tags { if (ps.isEmpty) { debuglog("Fatal: couldn't find site " + site + " in " + site.parents.map(_.typeSymbol.name)) if (phase.erasedTypes && context.enclClass.owner.isImplClass) { - // println(qual1) - // println(clazz) - // println(site) - // println(site.parents) - // println(mix) // the reference to super class got lost during erasure restrictionError(tree.pos, unit, "traits may not select fields or methods from super[C] where C is a class") ErrorType @@ -4629,14 +4445,28 @@ trait Typers extends Modes with Adaptations with Tags { if (isStableContext(tree, mode, pt)) tree setType clazz.thisType else tree } - /** Attribute a selection where <code>tree</code> is <code>qual.name</code>. - * <code>qual</code> is already attributed. - * - * @param qual ... - * @param name ... - * @return ... + /** Attribute a selection where `tree` is `qual.name`. + * `qual` is already attributed. */ def typedSelect(tree: Tree, qual: Tree, name: Name): Tree = { + val t = typedSelectInternal(tree, qual, name) + // Checking for OverloadedTypes being handed out after overloading + // resolution has already happened. + if (isPastTyper) t.tpe match { + case OverloadedType(pre, alts) => + if (alts forall (s => (s.owner == ObjectClass) || (s.owner == AnyClass) || isPrimitiveValueClass(s.owner))) () + else if (settings.debug.value) printCaller( + s"""|Select received overloaded type during $phase, but typer is over. + |If this type reaches the backend, we are likely doomed to crash. + |$t has these overloads: + |${alts map (s => " " + s.defStringSeenAs(pre memberType s)) mkString "\n"} + |""".stripMargin + )("") + case _ => + } + t + } + def typedSelectInternal(tree: Tree, qual: Tree, name: Name): Tree = { def asDynamicCall = dyna.mkInvoke(context.tree, tree, qual, name) map { t => dyna.wrapErrors(t, (_.typed1(t, mode, pt))) } @@ -4657,45 +4487,43 @@ trait Typers extends Modes with Adaptations with Tags { if (!reallyExists(sym)) { def handleMissing: Tree = { - if (context.owner.enclosingTopLevelClass.isJavaDefined && name.isTypeName) { - val tree1 = atPos(tree.pos) { gen.convertToSelectFromType(qual, name) } - if (tree1 != EmptyTree) return typed1(tree1, mode, pt) - } - - // try to expand according to Dynamic rules. - asDynamicCall foreach (x => return x) - - debuglog( - "qual = " + qual + ":" + qual.tpe + - "\nSymbol=" + qual.tpe.termSymbol + "\nsymbol-info = " + qual.tpe.termSymbol.info + - "\nscope-id = " + qual.tpe.termSymbol.info.decls.hashCode() + "\nmembers = " + qual.tpe.members + - "\nname = " + name + "\nfound = " + sym + "\nowner = " + context.enclClass.owner) - - def makeInteractiveErrorTree = { - val tree1 = tree match { - case Select(_, _) => treeCopy.Select(tree, qual, name) - case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name) - } - setError(tree1) + def errorTree = tree match { + case _ if !forInteractive => tree + case Select(_, _) => treeCopy.Select(tree, qual, name) + case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name) } - - if (name == nme.ERROR && forInteractive) - return makeInteractiveErrorTree - - if (!qual.tpe.widen.isErroneous) { - if ((mode & QUALmode) != 0) { - val lastTry = rootMirror.missingHook(qual.tpe.typeSymbol, name) - if (lastTry != NoSymbol) return typed1(tree setSymbol lastTry, mode, pt) + def asTypeSelection = ( + if (context.owner.enclosingTopLevelClass.isJavaDefined && name.isTypeName) { + atPos(tree.pos)(gen.convertToSelectFromType(qual, name)) match { + case EmptyTree => None + case tree1 => Some(typed1(tree1, mode, pt)) + } } - NotAMemberError(tree, qual, name) - } - - if (forInteractive) makeInteractiveErrorTree else setError(tree) + else None + ) + debuglog(s""" + |qual=$qual:${qual.tpe} + |symbol=${qual.tpe.termSymbol.defString} + |scope-id=${qual.tpe.termSymbol.info.decls.hashCode} + |members=${qual.tpe.members mkString ", "} + |name=$name + |found=$sym + |owner=${context.enclClass.owner} + """.stripMargin) + + // 1) Try converting a term selection on a java class into a type selection. + // 2) Try expanding according to Dynamic rules. + // 3) Try looking up the name in the qualifier. + asTypeSelection orElse asDynamicCall getOrElse (lookupInQualifier(qual, name) match { + case NoSymbol => setError(errorTree) + case found => typed1(tree setSymbol found, mode, pt) + }) } handleMissing - } else { + } + else { val tree1 = tree match { - case Select(_, _) => treeCopy.Select(tree, qual, name) + case Select(_, _) => treeCopy.Select(tree, qual, name) case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name) } val (result, accessibleError) = silent(_.makeAccessible(tree1, sym, qual.tpe, qual)) match { @@ -4764,19 +4592,16 @@ trait Typers extends Modes with Adaptations with Tags { val tree1 = // temporarily use `filter` and an alternative for `withFilter` if (name == nme.withFilter) - silent(_ => typedSelect(tree, qual1, name)) match { - case SilentResultValue(result) => - result - case _ => - silent(_ => typed1(Select(qual1, nme.filter) setPos tree.pos, mode, pt)) match { - case SilentResultValue(result2) => - unit.deprecationWarning( - tree.pos, "`withFilter' method does not yet exist on " + qual1.tpe.widen + - ", using `filter' method instead") - result2 - case SilentTypeError(err) => - WithFilterError(tree, err) - } + silent(_ => typedSelect(tree, qual1, name)) orElse { _ => + silent(_ => typed1(Select(qual1, nme.filter) setPos tree.pos, mode, pt)) match { + case SilentResultValue(result2) => + unit.deprecationWarning( + tree.pos, "`withFilter' method does not yet exist on " + qual1.tpe.widen + + ", using `filter' method instead") + result2 + case SilentTypeError(err) => + WithFilterError(tree, err) + } } else typedSelect(tree, qual1, name) @@ -4791,6 +4616,18 @@ trait Typers extends Modes with Adaptations with Tags { } } + /** A symbol qualifies if: + * - it exists + * - it is not stale (stale symbols are made to disappear here) + * - if we are in a pattern constructor, method definitions do not qualify + * unless they are stable. Otherwise, 'case x :: xs' would find the :: method. + */ + def qualifies(sym: Symbol) = ( + sym.hasRawInfo + && reallyExists(sym) + && !(inPatternConstructor && sym.isMethod && !sym.isStable) + ) + /** Attribute an identifier consisting of a simple name or an outer reference. * * @param tree The tree representing the identifier. @@ -4799,243 +4636,48 @@ trait Typers extends Modes with Adaptations with Tags { * (2) Change imported symbols to selections */ def typedIdent(tree: Tree, name: Name): Tree = { - var errorContainer: AbsTypeError = null - def ambiguousError(msg: String) = { - assert(errorContainer == null, "Cannot set ambiguous error twice for identifier") - errorContainer = AmbiguousIdentError(tree, name, msg) - } - def identError(tree: AbsTypeError) = { - assert(errorContainer == null, "Cannot set ambiguous error twice for identifier") - errorContainer = tree - } + // setting to enable unqualified idents in empty package + def inEmptyPackage = if (settings.exposeEmptyPackage.value) lookupInEmpty(name) else NoSymbol + + def issue(err: AbsTypeError) = { + // Avoiding some spurious error messages: see SI-2388. + val suppress = reporter.hasErrors && (name startsWith tpnme.ANON_CLASS_NAME) + if (!suppress) + ErrorUtils.issueTypeError(err) - var defSym: Symbol = tree.symbol // the directly found symbol - var pre: Type = NoPrefix // the prefix type of defSym, if a class member - var qual: Tree = EmptyTree // the qualifier tree if transformed tree is a select - var inaccessibleSym: Symbol = NoSymbol // the first symbol that was found but that was discarded - // for being inaccessible; used for error reporting - var inaccessibleExplanation: String = "" - - // If a special setting is given, the empty package will be checked as a - // last ditch effort before failing. This method sets defSym and returns - // true if a member of the given name exists. - def checkEmptyPackage(): Boolean = { - defSym = rootMirror.EmptyPackageClass.tpe.nonPrivateMember(name) - defSym != NoSymbol + setError(tree) } - def startingIdentContext = ( - // ignore current variable scope in patterns to enforce linearity - if ((mode & (PATTERNmode | TYPEPATmode)) == 0) context - else context.outer - ) - // A symbol qualifies if it exists and is not stale. Stale symbols - // are made to disappear here. In addition, - // if we are in a constructor of a pattern, we ignore all definitions - // which are methods (note: if we don't do that - // case x :: xs in class List would return the :: method) - // unless they are stable or are accessors (the latter exception is for better error messages). - def qualifies(sym: Symbol): Boolean = { - sym.hasRawInfo && // this condition avoids crashing on self-referential pattern variables - reallyExists(sym) && - ((mode & PATTERNmode | FUNmode) != (PATTERNmode | FUNmode) || !sym.isSourceMethod || sym.hasFlag(ACCESSOR)) + // ignore current variable scope in patterns to enforce linearity + val startContext = if (inNoModes(mode, PATTERNmode | TYPEPATmode)) context else context.outer + val nameLookup = tree.symbol match { + case NoSymbol => startContext.lookupSymbol(name, qualifies) + case sym => LookupSucceeded(EmptyTree, sym) } - - if (defSym == NoSymbol) { - var defEntry: ScopeEntry = null // the scope entry of defSym, if defined in a local scope - - var cx = startingIdentContext - while (defSym == NoSymbol && cx != NoContext && (cx.scope ne null)) { // cx.scope eq null arises during FixInvalidSyms in Duplicators - pre = cx.enclClass.prefix - defEntry = cx.scope.lookupEntry(name) - if ((defEntry ne null) && qualifies(defEntry.sym)) { - // Right here is where SI-1987, overloading in package objects, can be - // seen to go wrong. There is an overloaded symbol, but when referring - // to the unqualified identifier from elsewhere in the package, only - // the last definition is visible. So overloading mis-resolves and is - // definition-order dependent, bad things. See run/t1987.scala. - // - // I assume the actual problem involves how/where these symbols are entered - // into the scope. But since I didn't figure out how to fix it that way, I - // catch it here by looking up package-object-defined symbols in the prefix. - if (isInPackageObject(defEntry.sym, pre.typeSymbol)) { - defSym = pre.member(defEntry.sym.name) - if (defSym ne defEntry.sym) { - qual = gen.mkAttributedQualifier(pre) - log(sm""" - | !!! Overloaded package object member resolved incorrectly. - | prefix: $pre - | Discarded: ${defEntry.sym.defString} - | Using: ${defSym.defString} - """) - } - } - else - defSym = defEntry.sym - } - else { - cx = cx.enclClass - val foundSym = pre.member(name) filter qualifies - defSym = foundSym filter (context.isAccessible(_, pre, false)) - if (defSym == NoSymbol) { - if ((foundSym ne NoSymbol) && (inaccessibleSym eq NoSymbol)) { - inaccessibleSym = foundSym - inaccessibleExplanation = analyzer.lastAccessCheckDetails - } - cx = cx.outer - } - } - } - - val symDepth = if (defEntry eq null) cx.depth - else cx.depth - (cx.scope.nestingLevel - defEntry.owner.nestingLevel) - var impSym: Symbol = NoSymbol // the imported symbol - var imports = context.imports // impSym != NoSymbol => it is imported from imports.head - while (!reallyExists(impSym) && !imports.isEmpty && imports.head.depth > symDepth) { - impSym = imports.head.importedSymbol(name) - if (!impSym.exists) imports = imports.tail - } - - // detect ambiguous definition/import, - // update `defSym` to be the final resolved symbol, - // update `pre` to be `sym`s prefix type in case it is an imported member, - // and compute value of: - - if (defSym.exists && impSym.exists) { - // imported symbols take precedence over package-owned symbols in different - // compilation units. Defined symbols take precedence over erroneous imports. - if (defSym.isDefinedInPackage && - (!currentRun.compiles(defSym) || - context.unit.exists && defSym.sourceFile != context.unit.source.file)) - defSym = NoSymbol - else if (impSym.isError || impSym.name == nme.CONSTRUCTOR) - impSym = NoSymbol - } - if (defSym.exists) { - if (impSym.exists) - ambiguousError( - "it is both defined in "+defSym.owner + - " and imported subsequently by \n"+imports.head) - else if (!defSym.owner.isClass || defSym.owner.isPackageClass || defSym.isTypeParameterOrSkolem) - pre = NoPrefix - else - qual = atPos(tree.pos.focusStart)(gen.mkAttributedQualifier(pre)) - } else { - if (impSym.exists) { - var impSym1: Symbol = NoSymbol - var imports1 = imports.tail - - /** It's possible that seemingly conflicting identifiers are - * identifiably the same after type normalization. In such cases, - * allow compilation to proceed. A typical example is: - * package object foo { type InputStream = java.io.InputStream } - * import foo._, java.io._ - */ - def ambiguousImport() = { - // The types of the qualifiers from which the ambiguous imports come. - // If the ambiguous name is a value, these must be the same. - def t1 = imports.head.qual.tpe - def t2 = imports1.head.qual.tpe - // The types of the ambiguous symbols, seen as members of their qualifiers. - // If the ambiguous name is a monomorphic type, we can relax this far. - def mt1 = t1 memberType impSym - def mt2 = t2 memberType impSym1 - def characterize = List( - s"types: $t1 =:= $t2 ${t1 =:= t2} members: ${mt1 =:= mt2}", - s"member type 1: $mt1", - s"member type 2: $mt2", - s"$impSym == $impSym1 ${impSym == impSym1}", - s"${impSym.debugLocationString} ${impSym.getClass}", - s"${impSym1.debugLocationString} ${impSym1.getClass}" - ).mkString("\n ") - - // The symbol names are checked rather than the symbols themselves because - // each time an overloaded member is looked up it receives a new symbol. - // So foo.member("x") != foo.member("x") if x is overloaded. This seems - // likely to be the cause of other bugs too... - if (t1 =:= t2 && impSym.name == impSym1.name) - log(s"Suppressing ambiguous import: $t1 =:= $t2 && $impSym == $impSym1") - // Monomorphism restriction on types is in part because type aliases could have the - // same target type but attach different variance to the parameters. Maybe it can be - // relaxed, but doesn't seem worth it at present. - else if (mt1 =:= mt2 && name.isTypeName && impSym.isMonomorphicType && impSym1.isMonomorphicType) - log(s"Suppressing ambiguous import: $mt1 =:= $mt2 && $impSym and $impSym1 are equivalent") - else { - log(s"Import is genuinely ambiguous:\n " + characterize) - ambiguousError(s"it is imported twice in the same scope by\n${imports.head}\nand ${imports1.head}") - } - } - while (errorContainer == null && !imports1.isEmpty && - (!imports.head.isExplicitImport(name) || - imports1.head.depth == imports.head.depth)) { - impSym1 = imports1.head.importedSymbol(name) - if (reallyExists(impSym1)) { - if (imports1.head.isExplicitImport(name)) { - if (imports.head.isExplicitImport(name) || - imports1.head.depth != imports.head.depth) ambiguousImport() - impSym = impSym1 - imports = imports1 - } else if (!imports.head.isExplicitImport(name) && - imports1.head.depth == imports.head.depth) ambiguousImport() - } - imports1 = imports1.tail - } - defSym = impSym - val qual0 = imports.head.qual - if (!(shortenImports && qual0.symbol.isPackage)) // optimization: don't write out package prefixes - qual = atPos(tree.pos.focusStart)(resetPos(qual0.duplicate)) - pre = qual.tpe + import InferErrorGen._ + nameLookup match { + case LookupAmbiguous(msg) => issue(AmbiguousIdentError(tree, name, msg)) + case LookupInaccessible(sym, msg) => issue(AccessError(tree, sym, context, msg)) + case LookupNotFound => + inEmptyPackage orElse lookupInRoot(name) match { + case NoSymbol => issue(SymbolNotFoundError(tree, name, context.owner, startContext)) + case sym => typed1(tree setSymbol sym, mode, pt) } - else if (settings.exposeEmptyPackage.value && checkEmptyPackage()) - log("Allowing empty package member " + name + " due to settings.") + case LookupSucceeded(qual, sym) => + // this -> Foo.this + if (sym.isThisSym) + typed1(This(sym.owner) setPos tree.pos, mode, pt) + // Inferring classOf type parameter from expected type. Otherwise an + // actual call to the stubbed classOf method is generated, returning null. + else if (isPredefMemberNamed(sym, nme.classOf) && pt.typeSymbol == ClassClass && pt.typeArgs.nonEmpty) + typedClassOf(tree, TypeTree(pt.typeArgs.head)) else { - if ((mode & QUALmode) != 0) { - val lastTry = rootMirror.missingHook(rootMirror.RootClass, name) - if (lastTry != NoSymbol) return typed1(tree setSymbol lastTry, mode, pt) - } - if (settings.debug.value) { - log(context.imports)//debug - } - if (inaccessibleSym eq NoSymbol) { - // Avoiding some spurious error messages: see SI-2388. - if (reporter.hasErrors && (name startsWith tpnme.ANON_CLASS_NAME)) () - else identError(SymbolNotFoundError(tree, name, context.owner, startingIdentContext)) - } else - identError(InferErrorGen.AccessError( - tree, inaccessibleSym, context.enclClass.owner.thisType, context.enclClass.owner, - inaccessibleExplanation - )) - defSym = context.owner.newErrorSymbol(name) + val pre1 = if (sym.owner.isPackageClass) sym.owner.thisType else if (qual == EmptyTree) NoPrefix else qual.tpe + val tree1 = if (qual == EmptyTree) tree else atPos(tree.pos)(Select(atPos(tree.pos.focusStart)(qual), name)) + val (tree2, pre2) = makeAccessible(tree1, sym, pre1, qual) + // SI-5967 Important to replace param type A* with Seq[A] when seen from from a reference, to avoid + // inference errors in pattern matching. + stabilize(tree2, pre2, mode, pt) modifyType dropIllegalStarTypes } - } - } - if (errorContainer != null) { - ErrorUtils.issueTypeError(errorContainer) - setError(tree) - } else { - if (defSym.owner.isPackageClass) - pre = defSym.owner.thisType - - // Inferring classOf type parameter from expected type. - if (defSym.isThisSym) { - typed1(This(defSym.owner) setPos tree.pos, mode, pt) - } - // Inferring classOf type parameter from expected type. Otherwise an - // actual call to the stubbed classOf method is generated, returning null. - else if (isPredefMemberNamed(defSym, nme.classOf) && pt.typeSymbol == ClassClass && pt.typeArgs.nonEmpty) - typedClassOf(tree, TypeTree(pt.typeArgs.head)) - else { - val tree1 = ( - if (qual == EmptyTree) tree - // atPos necessary because qualifier might come from startContext - else atPos(tree.pos)(Select(qual, name)) - ) - val (tree2, pre2) = makeAccessible(tree1, defSym, pre, qual) - // assert(pre.typeArgs isEmpty) // no need to add #2416-style check here, right? - val tree3 = stabilize(tree2, pre2, mode, pt) - // SI-5967 Important to replace param type A* with Seq[A] when seen from from a reference, to avoid - // inference errors in pattern matching. - tree3 setType dropRepeatedParamType(tree3.tpe) - } } } @@ -5069,7 +4711,7 @@ trait Typers extends Modes with Adaptations with Tags { val tpt1 = typed1(tpt, mode | FUNmode | TAPPmode, WildcardType) if (tpt1.isErrorTyped) { tpt1 - } else if (!tpt1.hasSymbol) { + } else if (!tpt1.hasSymbolField) { AppliedTypeNoParametersError(tree, tpt1.tpe) } else { val tparams = tpt1.symbol.typeParams @@ -5123,7 +4765,7 @@ trait Typers extends Modes with Adaptations with Tags { val pid1 = typedQualifier(pdef.pid).asInstanceOf[RefTree] assert(sym.moduleClass ne NoSymbol, sym) // complete lazy annotations - val annots = sym.annotations + sym.annotations val stats1 = newTyper(context.make(tree, sym.moduleClass, sym.info.decls)) .typedStats(pdef.stats, NoSymbol) treeCopy.PackageDef(tree, pid1, stats1) setType NoType @@ -5178,14 +4820,12 @@ trait Typers extends Modes with Adaptations with Tags { var block1 = typed(tree.block, pt) var catches1 = typedCases(tree.catches, ThrowableClass.tpe, pt) - for (cdef <- catches1 if cdef.guard.isEmpty) { - def warn(name: Name) = context.warning(cdef.pat.pos, s"This catches all Throwables. If this is really intended, use `case ${name.decoded} : Throwable` to clear this warning.") - def unbound(t: Tree) = t.symbol == null || t.symbol == NoSymbol - cdef.pat match { - case Bind(name, i @ Ident(_)) if unbound(i) => warn(name) - case i @ Ident(name) if unbound(i) => warn(name) - case _ => - } + for (cdef <- catches1; if treeInfo catchesThrowable cdef) { + val name = (treeInfo assignedNameOfPattern cdef).decoded + context.warning(cdef.pat.pos, + s"""|This catches all Throwables, which often has undesirable consequences. + |If intentional, use `case $name : Throwable` to clear this warning.""".stripMargin + ) } val finalizer1 = @@ -5430,28 +5070,21 @@ trait Typers extends Modes with Adaptations with Tags { } } - /** - * @param tree ... - * @param mode ... - * @param pt ... - * @return ... - */ def typed(tree: Tree, mode: Int, pt: Type): Tree = { lastTreeToTyper = tree indentTyping() - var alreadyTyped = false val startByType = if (Statistics.canEnable) Statistics.pushTimer(byTypeStack, byTypeNanos(tree.getClass)) else null if (Statistics.canEnable) Statistics.incCounter(visitsByType, tree.getClass) try { if (context.retyping && (tree.tpe ne null) && (tree.tpe.isErroneous || !(tree.tpe <:< pt))) { tree.tpe = null - if (tree.hasSymbol) tree.symbol = NoSymbol + if (tree.hasSymbolField) tree.symbol = NoSymbol } - alreadyTyped = tree.tpe ne null - var tree1: Tree = if (alreadyTyped) tree else { + val alreadyTyped = tree.tpe ne null + val tree1: Tree = if (alreadyTyped) tree else { printTyping( ptLine("typing %s: pt = %s".format(ptTree(tree), pt), "undetparams" -> context.undetparams, @@ -5507,10 +5140,7 @@ trait Typers extends Modes with Adaptations with Tags { def atOwner(tree: Tree, owner: Symbol): Typer = newTyper(context.make(tree, owner)) - /** Types expression or definition <code>tree</code>. - * - * @param tree ... - * @return ... + /** Types expression or definition `tree`. */ def typed(tree: Tree): Tree = { val ret = typed(tree, EXPRmode, WildcardType) @@ -5523,23 +5153,19 @@ trait Typers extends Modes with Adaptations with Tags { // it makes for a lot less casting. // def typedPos[T <: Tree](pos: Position)(tree: T): T = typed(atPos(pos)(tree)).asInstanceOf[T] - /** Types expression <code>tree</code> with given prototype <code>pt</code>. - * - * @param tree ... - * @param pt ... - * @return ... + /** Types expression `tree` with given prototype `pt`. */ def typed(tree: Tree, pt: Type): Tree = typed(tree, EXPRmode, pt) - /** Types qualifier <code>tree</code> of a select node. - * E.g. is tree occurs in a context like <code>tree.m</code>. + /** Types qualifier `tree` of a select node. + * E.g. is tree occurs in a context like `tree.m`. */ def typedQualifier(tree: Tree, mode: Int, pt: Type): Tree = typed(tree, EXPRmode | QUALmode | POLYmode | mode & TYPEPATmode, pt) // TR: don't set BYVALmode, since qualifier might end up as by-name param to an implicit - /** Types qualifier <code>tree</code> of a select node. - * E.g. is tree occurs in a context like <code>tree.m</code>. + /** Types qualifier `tree` of a select node. + * E.g. is tree occurs in a context like `tree.m`. */ def typedQualifier(tree: Tree, mode: Int): Tree = typedQualifier(tree, mode, WildcardType) @@ -5550,7 +5176,7 @@ trait Typers extends Modes with Adaptations with Tags { def typedOperator(tree: Tree): Tree = typed(tree, EXPRmode | FUNmode | POLYmode | TAPPmode, WildcardType) - /** Types a pattern with prototype <code>pt</code> */ + /** Types a pattern with prototype `pt` */ def typedPattern(tree: Tree, pt: Type): Tree = { // We disable implicits because otherwise some constructs will // type check which should not. The pattern matcher does not @@ -5588,8 +5214,6 @@ trait Typers extends Modes with Adaptations with Tags { def typedHigherKindedType(tree: Tree, mode: Int): Tree = typed(tree, HKmode, WildcardType) - def typedHigherKindedType(tree: Tree): Tree = typedHigherKindedType(tree, NOmode) - /** Types a type constructor tree used in a new or supertype */ def typedTypeConstructor(tree: Tree, mode: Int): Tree = { val result = typed(tree, forTypeMode(mode) | FUNmode, WildcardType) @@ -5664,28 +5288,17 @@ trait Typers extends Modes with Adaptations with Tags { case Some(tree1) => transformed -= tree; tree1 case None => typed(tree, mode, pt) } - -/* - def convertToTypeTree(tree: Tree): Tree = tree match { - case TypeTree() => tree - case _ => TypeTree(tree.tpe) - } -*/ } } object TypersStats { import scala.reflect.internal.TypesStats._ - import scala.reflect.internal.BaseTypeSeqsStats._ val typedIdentCount = Statistics.newCounter("#typechecked identifiers") val typedSelectCount = Statistics.newCounter("#typechecked selections") val typedApplyCount = Statistics.newCounter("#typechecked applications") val rawTypeFailed = Statistics.newSubCounter (" of which in failed", rawTypeCount) val subtypeFailed = Statistics.newSubCounter(" of which in failed", subtypeCount) val findMemberFailed = Statistics.newSubCounter(" of which in failed", findMemberCount) - val compoundBaseTypeSeqCount = Statistics.newSubCounter(" of which for compound types", baseTypeSeqCount) - val typerefBaseTypeSeqCount = Statistics.newSubCounter(" of which for typerefs", baseTypeSeqCount) - val singletonBaseTypeSeqCount = Statistics.newSubCounter(" of which for singletons", baseTypeSeqCount) val failedSilentNanos = Statistics.newSubTimer("time spent in failed", typerNanos) val failedApplyNanos = Statistics.newSubTimer(" failed apply", typerNanos) val failedOpEqNanos = Statistics.newSubTimer(" failed op=", typerNanos) diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index bf44b65406..061c6679da 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -23,7 +23,6 @@ trait Unapplies extends ast.TreeDSL private val unapplyParamName = nme.x_0 - // In the typeCompleter (templateSig) of a case class (resp it's module), // synthetic `copy` (reps `apply`, `unapply`) methods are added. To compute // their signatures, the corresponding ClassDef is needed. During naming (in @@ -46,17 +45,6 @@ trait Unapplies extends ast.TreeDSL } } - /** returns type of the unapply method returning T_0...T_n - * for n == 0, boolean - * for n == 1, Some[T0] - * else Some[Product[Ti]] - */ - def unapplyReturnTypeExpected(argsLength: Int) = argsLength match { - case 0 => BooleanClass.tpe - case 1 => optionType(WildcardType) - case n => optionType(productType((List fill n)(WildcardType))) - } - /** returns unapply or unapplySeq if available */ def unapplyMember(tp: Type): Symbol = (tp member nme.unapply) match { case NoSymbol => tp member nme.unapplySeq diff --git a/src/compiler/scala/tools/nsc/typechecker/Variances.scala b/src/compiler/scala/tools/nsc/typechecker/Variances.scala index 7d97b0c782..aa66a8d00a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Variances.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Variances.scala @@ -40,7 +40,7 @@ trait Variances { (VARIANCES /: tps) ((v, tp) => v & varianceInType(tp)(tparam)) /** Compute variance of type parameter `tparam` in all type arguments - * <code>tps</code> which correspond to formal type parameters `tparams1`. + * `tps` which correspond to formal type parameters `tparams1`. */ def varianceInArgs(tps: List[Type], tparams1: List[Symbol])(tparam: Symbol): Int = { var v: Int = VARIANCES; @@ -63,10 +63,12 @@ trait Variances { varianceInType(annot.atp)(tparam) } - /** Compute variance of type parameter <code>tparam</code> in type <code>tp</code>. */ + /** Compute variance of type parameter `tparam` in type `tp`. */ def varianceInType(tp: Type)(tparam: Symbol): Int = tp match { case ErrorType | WildcardType | NoType | NoPrefix | ThisType(_) | ConstantType(_) => VARIANCES + case BoundedWildcardType(bounds) => + varianceInType(bounds)(tparam) case SingleType(pre, sym) => varianceInType(pre)(tparam) case TypeRef(pre, sym, args) => diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index 8732e06502..ee66801c45 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -11,7 +11,6 @@ import java.net.URL import scala.collection.{ mutable, immutable } import io.{ File, Directory, Path, Jar, AbstractFile } import scala.reflect.internal.util.StringOps.splitWhere -import scala.reflect.ClassTag import Jar.isJarOrZip import File.pathSeparator import java.net.MalformedURLException @@ -32,10 +31,6 @@ object ClassPath { def lsDir(dir: Directory, filt: String => Boolean = _ => true) = dir.list filter (x => filt(x.name) && (x.isDirectory || isJarOrZip(x))) map (_.path) toList - def basedir(s: String) = - if (s contains File.separator) s.substring(0, s.lastIndexOf(File.separator)) - else "." - if (pattern == "*") lsDir(Directory(".")) else if (pattern endsWith wildSuffix) lsDir(Directory(pattern dropRight 2)) else if (pattern contains '*') { @@ -54,22 +49,6 @@ object ClassPath { /** Split the classpath, apply a transformation function, and reassemble it. */ def map(cp: String, f: String => String): String = join(split(cp) map f: _*) - /** Split the classpath, filter according to predicate, and reassemble. */ - def filter(cp: String, p: String => Boolean): String = join(split(cp) filter p: _*) - - /** Split the classpath and map them into Paths */ - def toPaths(cp: String): List[Path] = split(cp) map (x => Path(x).toAbsolute) - - /** Make all classpath components absolute. */ - def makeAbsolute(cp: String): String = fromPaths(toPaths(cp): _*) - - /** Join the paths as a classpath */ - def fromPaths(paths: Path*): String = join(paths map (_.path): _*) - def fromURLs(urls: URL*): String = fromPaths(urls map (x => Path(x.getPath)) : _*) - - /** Split the classpath and map them into URLs */ - def toURLs(cp: String): List[URL] = toPaths(cp) map (_.toURL) - /** Expand path and possibly expanding stars */ def expandPath(path: String, expandStar: Boolean = true): List[String] = if (expandStar) split(path) flatMap expandS @@ -129,13 +108,6 @@ object ClassPath { for (dir <- expandPath(path, false) ; name <- expandDir(dir) ; entry <- Option(AbstractFile getDirectory name)) yield newClassPath(entry) - def classesAtAllURLS(path: String): List[ClassPath[T]] = - (path split " ").toList flatMap classesAtURL - - def classesAtURL(spec: String) = - for (url <- specToURL(spec).toList ; location <- Option(AbstractFile getURL url)) yield - newClassPath(location) - def classesInExpandedPath(path: String): IndexedSeq[ClassPath[T]] = classesInPathImpl(path, true).toIndexedSeq @@ -404,15 +376,3 @@ class JavaClassPath( containers: IndexedSeq[ClassPath[AbstractFile]], context: JavaContext) extends MergedClassPath[AbstractFile](containers, context) { } - -object JavaClassPath { - def fromURLs(urls: Seq[URL], context: JavaContext): JavaClassPath = { - val containers = { - for (url <- urls ; f = AbstractFile getURL url ; if f != null) yield - new DirectoryClassPath(f, context) - } - new JavaClassPath(containers.toIndexedSeq, context) - } - def fromURLs(urls: Seq[URL]): JavaClassPath = - fromURLs(urls, ClassPath.DefaultJavaContext) -} diff --git a/src/compiler/scala/tools/nsc/util/CommandLineParser.scala b/src/compiler/scala/tools/nsc/util/CommandLineParser.scala index 9cf2c535df..e8f962a9e2 100644 --- a/src/compiler/scala/tools/nsc/util/CommandLineParser.scala +++ b/src/compiler/scala/tools/nsc/util/CommandLineParser.scala @@ -7,7 +7,6 @@ package scala.tools.nsc package util import scala.util.parsing.combinator._ -import scala.util.parsing.input.{ Reader } import scala.util.parsing.input.CharArrayReader.EofCh import scala.collection.mutable.ListBuffer @@ -22,7 +21,6 @@ import scala.collection.mutable.ListBuffer trait ParserUtil extends Parsers { protected implicit class ParserPlus[+T](underlying: Parser[T]) { def !~>[U](p: => Parser[U]): Parser[U] = (underlying ~! p) ^^ { case a~b => b } - def <~![U](p: => Parser[U]): Parser[T] = (underlying ~! p) ^^ { case a~b => a } } } @@ -38,7 +36,6 @@ case class CommandLine( def withUnaryArgs(xs: List[String]) = copy(unaryArguments = xs) def withBinaryArgs(xs: List[String]) = copy(binaryArguments = xs) - def originalArgs = args def assumeBinary = true def enforceArity = true def onlyKnownOptions = false @@ -106,7 +103,6 @@ case class CommandLine( def isSet(arg: String) = args contains arg def get(arg: String) = argMap get arg - def getOrElse(arg: String, orElse: => String) = if (isSet(arg)) apply(arg) else orElse def apply(arg: String) = argMap(arg) override def toString() = "CommandLine(\n%s)\n" format (args map (" " + _ + "\n") mkString) @@ -116,7 +112,6 @@ object CommandLineParser extends RegexParsers with ParserUtil { override def skipWhitespace = false def elemExcept(xs: Elem*): Parser[Elem] = elem("elemExcept", x => x != EofCh && !(xs contains x)) - def elemOf(xs: Elem*): Parser[Elem] = elem("elemOf", xs contains _) def escaped(ch: Char): Parser[String] = "\\" + ch def mkQuoted(ch: Char): Parser[String] = ( elem(ch) !~> rep(escaped(ch) | elemExcept(ch)) <~ ch ^^ (_.mkString) diff --git a/src/compiler/scala/tools/nsc/util/Exceptional.scala b/src/compiler/scala/tools/nsc/util/Exceptional.scala index 34344263e8..1608ffa425 100644 --- a/src/compiler/scala/tools/nsc/util/Exceptional.scala +++ b/src/compiler/scala/tools/nsc/util/Exceptional.scala @@ -3,8 +3,6 @@ package util import java.util.concurrent.ExecutionException import java.lang.reflect.{ InvocationTargetException, UndeclaredThrowableException } -import scala.reflect.internal.util.StringOps._ -import scala.language.implicitConversions object Exceptional { def unwrap(x: Throwable): Throwable = x match { diff --git a/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala b/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala index 5421843438..e877c990f0 100644 --- a/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala +++ b/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala @@ -14,11 +14,6 @@ trait FreshNameCreator { */ def newName(): String def newName(prefix: String): String - - @deprecated("use newName(prefix)", "2.9.0") - def newName(pos: scala.reflect.internal.util.Position, prefix: String): String = newName(prefix) - @deprecated("use newName()", "2.9.0") - def newName(pos: scala.reflect.internal.util.Position): String = newName() } object FreshNameCreator { diff --git a/src/compiler/scala/tools/nsc/util/JavaCharArrayReader.scala b/src/compiler/scala/tools/nsc/util/JavaCharArrayReader.scala index b7ed7903bc..fc3dd2bac2 100644 --- a/src/compiler/scala/tools/nsc/util/JavaCharArrayReader.scala +++ b/src/compiler/scala/tools/nsc/util/JavaCharArrayReader.scala @@ -14,74 +14,32 @@ class JavaCharArrayReader(buf: IndexedSeq[Char], start: Int, /* startline: int, def this(buf: IndexedSeq[Char], decodeUni: Boolean, error: String => Unit) = this(buf, 0, /* 1, 1, */ decodeUni, error) - /** produce a duplicate of this char array reader which starts reading - * at current position, independent of what happens to original reader - */ - def dup: JavaCharArrayReader = clone().asInstanceOf[JavaCharArrayReader] - - /** layout constant - */ - val tabinc = 8 - /** the line and column position of the current character */ var ch: Char = _ var bp = start - var oldBp = -1 - var oldCh: Char = _ - - //private var cline: Int = _ - //private var ccol: Int = _ def cpos = bp var isUnicode: Boolean = _ - var lastLineStartPos: Int = 0 - var lineStartPos: Int = 0 - var lastBlankLinePos: Int = 0 - - private var onlyBlankChars = false - //private var nextline = startline - //private var nextcol = startcol - - private def markNewLine() { - lastLineStartPos = lineStartPos - if (onlyBlankChars) lastBlankLinePos = lineStartPos - lineStartPos = bp - onlyBlankChars = true - //nextline += 1 - //nextcol = 1 - } - - def hasNext: Boolean = if (bp < buf.length) true - else { - false - } - def last: Char = if (bp > start + 2) buf(bp - 2) else ' ' // XML literals + def hasNext = bp < buf.length def next(): Char = { - //cline = nextline - //ccol = nextcol val buf = this.buf.asInstanceOf[collection.mutable.WrappedArray[Char]].array if(!hasNext) { ch = SU return SU // there is an endless stream of SU's at the end } - oldBp = bp - oldCh = ch ch = buf(bp) isUnicode = false bp = bp + 1 ch match { case '\t' => - // nextcol = ((nextcol - 1) / tabinc * tabinc) + tabinc + 1; case CR => if (bp < buf.size && buf(bp) == LF) { ch = LF bp += 1 } - markNewLine() case LF | FF => - markNewLine() case '\\' => def evenSlashPrefix: Boolean = { var p = bp - 2 @@ -90,11 +48,10 @@ class JavaCharArrayReader(buf: IndexedSeq[Char], start: Int, /* startline: int, } def udigit: Int = { val d = digit2int(buf(bp), 16) - if (d >= 0) { bp += 1; /* nextcol = nextcol + 1 */ } + if (d >= 0) bp += 1 else error("error in unicode escape"); d } - // nextcol += 1 if (buf(bp) == 'u' && decodeUni && evenSlashPrefix) { do { bp += 1 //; nextcol += 1 @@ -104,20 +61,10 @@ class JavaCharArrayReader(buf: IndexedSeq[Char], start: Int, /* startline: int, isUnicode = true } case _ => - if (ch > ' ') onlyBlankChars = false - // nextcol += 1 } ch } - def rewind() { - if (oldBp == -1) throw new IllegalArgumentException - bp = oldBp - ch = oldCh - oldBp = -1 - oldCh = 'x' - } - def copy: JavaCharArrayReader = new JavaCharArrayReader(buf, bp, /* nextcol, nextline, */ decodeUni, error) } diff --git a/src/compiler/scala/tools/nsc/util/MsilClassPath.scala b/src/compiler/scala/tools/nsc/util/MsilClassPath.scala index aa3b7c286d..2f209c550d 100644 --- a/src/compiler/scala/tools/nsc/util/MsilClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/MsilClassPath.scala @@ -8,9 +8,6 @@ package scala.tools.nsc package util -import java.io.File -import java.net.URL -import java.util.StringTokenizer import scala.util.Sorting import scala.collection.mutable import scala.tools.nsc.io.{ AbstractFile, MsilFile } @@ -166,4 +163,4 @@ class AssemblyClassPath(types: Array[MSILType], namespace: String, val context: * MSILType values. */ class MsilClassPath(ext: String, user: String, source: String, context: MsilContext) -extends MergedClassPath[MsilFile](MsilClassPath.assembleEntries(ext, user, source, context), context) { }
\ No newline at end of file +extends MergedClassPath[MsilFile](MsilClassPath.assembleEntries(ext, user, source, context), context) { } diff --git a/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala index 1f6fa68f57..1d2cc73c6b 100644 --- a/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala +++ b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala @@ -46,9 +46,6 @@ trait ScalaClassLoader extends JClassLoader { def create(path: String): AnyRef = tryToInitializeClass[AnyRef](path) map (_.newInstance()) orNull - def constructorsOf[T <: AnyRef : ClassTag]: List[Constructor[T]] = - classTag[T].runtimeClass.getConstructors.toList map (_.asInstanceOf[Constructor[T]]) - /** The actual bytes for a class file, or an empty array if it can't be found. */ def classBytes(className: String): Array[Byte] = classAsStream(className) match { case null => Array() @@ -71,14 +68,6 @@ trait ScalaClassLoader extends JClassLoader { try asContext(method.invoke(null, Array(arguments.toArray: AnyRef): _*)) // !!! : AnyRef shouldn't be necessary catch unwrapHandler({ case ex => throw ex }) } - - /** A list comprised of this classloader followed by all its - * (non-null) parent classloaders, if any. - */ - def loaderChain: List[ScalaClassLoader] = this :: (getParent match { - case null => Nil - case p => p.loaderChain - }) } /** Methods for obtaining various classloaders. @@ -99,35 +88,6 @@ object ScalaClassLoader { } def contextLoader = apply(Thread.currentThread.getContextClassLoader) def appLoader = apply(JClassLoader.getSystemClassLoader) - def extLoader = apply(appLoader.getParent) - def bootLoader = apply(null) - def contextChain = loaderChain(contextLoader) - - def pathToErasure[T: ClassTag] = pathToClass(classTag[T].runtimeClass) - def pathToClass(clazz: Class[_]) = clazz.getName.replace('.', JFile.separatorChar) + ".class" - def locate[T: ClassTag] = contextLoader getResource pathToErasure[T] - - /** Tries to guess the classpath by type matching the context classloader - * and its parents, looking for any classloaders which will reveal their - * classpath elements as urls. It it can't find any, creates a classpath - * from the supplied string. - */ - def guessClassPathString(default: String = ""): String = { - val classpathURLs = contextChain flatMap { - case x: HasClassPath => x.classPathURLs - case x: JURLClassLoader => x.getURLs.toSeq - case _ => Nil - } - if (classpathURLs.isEmpty) default - else JavaClassPath.fromURLs(classpathURLs).asClasspathString - } - - def loaderChain(head: JClassLoader) = { - def loop(cl: JClassLoader): List[JClassLoader] = - if (cl == null) Nil else cl :: loop(cl.getParent) - - loop(head) - } def setContext(cl: JClassLoader) = Thread.currentThread.setContextClassLoader(cl) def savingContextLoader[T](body: => T): T = { @@ -142,16 +102,13 @@ object ScalaClassLoader { with HasClassPath { private var classloaderURLs: Seq[URL] = urls - private def classpathString = ClassPath.fromURLs(urls: _*) def classPathURLs: Seq[URL] = classloaderURLs - def classPath: ClassPath[_] = JavaClassPath fromURLs classPathURLs /** Override to widen to public */ override def addURL(url: URL) = { classloaderURLs :+= url super.addURL(url) } - def toLongString = urls.mkString("URLClassLoader(\n ", "\n ", "\n)\n") } def fromURLs(urls: Seq[URL], parent: ClassLoader = null): URLClassLoader = @@ -162,7 +119,6 @@ object ScalaClassLoader { fromURLs(urls) tryToLoadClass name isDefined /** Finding what jar a clazz or instance came from */ - def origin(x: Any): Option[URL] = originOfClass(x.getClass) def originOfClass(x: Class[_]): Option[URL] = Option(x.getProtectionDomain.getCodeSource) flatMap (x => Option(x.getLocation)) } diff --git a/src/compiler/scala/tools/nsc/util/ShowPickled.scala b/src/compiler/scala/tools/nsc/util/ShowPickled.scala index 2b87280c24..759c06dc0f 100644 --- a/src/compiler/scala/tools/nsc/util/ShowPickled.scala +++ b/src/compiler/scala/tools/nsc/util/ShowPickled.scala @@ -7,7 +7,7 @@ package scala.tools package nsc package util -import java.io.{File, FileInputStream, PrintStream} +import java.io.PrintStream import java.lang.Long.toHexString import java.lang.Float.intBitsToFloat import java.lang.Double.longBitsToDouble @@ -94,7 +94,6 @@ object ShowPickled extends Names { case ANNOTATEDtpe => "ANNOTATEDtpe" case ANNOTINFO => "ANNOTINFO" case ANNOTARGARRAY => "ANNOTARGARRAY" - // case DEBRUIJNINDEXtpe => "DEBRUIJNINDEXtpe" case EXISTENTIALtpe => "EXISTENTIALtpe" case TREE => "TREE" case MODIFIERS => "MODIFIERS" diff --git a/src/compiler/scala/tools/nsc/util/SimpleTracer.scala b/src/compiler/scala/tools/nsc/util/SimpleTracer.scala index b103ae9cb0..a33af1754d 100644 --- a/src/compiler/scala/tools/nsc/util/SimpleTracer.scala +++ b/src/compiler/scala/tools/nsc/util/SimpleTracer.scala @@ -14,6 +14,5 @@ class SimpleTracer(out: PrintStream, enabled: Boolean = true) { if (enabled) out.println(msg+value) value } - def withOutput(out: PrintStream) = new SimpleTracer(out, enabled) def when(enabled: Boolean): SimpleTracer = new SimpleTracer(out, enabled) } diff --git a/src/compiler/scala/tools/nsc/util/WorkScheduler.scala b/src/compiler/scala/tools/nsc/util/WorkScheduler.scala index b1f4696d3e..4f7a9ff878 100644 --- a/src/compiler/scala/tools/nsc/util/WorkScheduler.scala +++ b/src/compiler/scala/tools/nsc/util/WorkScheduler.scala @@ -7,9 +7,9 @@ class WorkScheduler { type Action = () => Unit - private var todo = new mutable.Queue[Action] - private var throwables = new mutable.Queue[Throwable] - private var interruptReqs = new mutable.Queue[InterruptReq] + private val todo = new mutable.Queue[Action] + private val throwables = new mutable.Queue[Throwable] + private val interruptReqs = new mutable.Queue[InterruptReq] /** Called from server: block until one of todo list, throwables or interruptReqs is nonempty */ def waitForMoreWork() = synchronized { diff --git a/src/compiler/scala/tools/nsc/util/package.scala b/src/compiler/scala/tools/nsc/util/package.scala index d34d4ee092..792a659ad6 100644 --- a/src/compiler/scala/tools/nsc/util/package.scala +++ b/src/compiler/scala/tools/nsc/util/package.scala @@ -18,16 +18,9 @@ package object util { type HashSet[T >: Null <: AnyRef] = scala.reflect.internal.util.HashSet[T] val HashSet = scala.reflect.internal.util.HashSet - def onull[T](value: T, orElse: => T): T = if (value == null) orElse else value - /** Apply a function and return the passed value */ def returning[T](x: T)(f: T => Unit): T = { f(x) ; x } - /** Frequency counter */ - def freq[T](xs: Traversable[T]): Map[T, Int] = xs groupBy identity mapValues (_.size) - - def freqrank[T](xs: Traversable[(T, Int)]): List[(Int, T)] = xs.toList map (_.swap) sortBy (-_._1) - /** Execute code and then wait for all non-daemon Threads * created and begun during its execution to complete. */ @@ -54,18 +47,6 @@ package object util { (result, ts2 filterNot (ts1 contains _)) } - /** Given a function and a block of code, evaluates code block, - * calls function with milliseconds elapsed, and returns block result. - */ - def millisElapsedTo[T](f: Long => Unit)(body: => T): T = { - val start = System.currentTimeMillis - val result = body - val end = System.currentTimeMillis - - f(end - start) - result - } - /** Generate a string using a routine that wants to write on a stream. */ def stringFromWriter(writer: PrintWriter => Unit): String = { val stringWriter = new StringWriter() @@ -83,8 +64,19 @@ package object util { } def stackTraceString(ex: Throwable): String = stringFromWriter(ex printStackTrace _) + /** A one line string which contains the class of the exception, the + * message if any, and the first non-Predef location in the stack trace + * (to exclude assert, require, etc.) + */ + def stackTraceHeadString(ex: Throwable): String = { + val frame = ex.getStackTrace.dropWhile(_.getClassName contains "Predef").head + val msg = ex.getMessage match { case null | "" => "" ; case s => s"""("$s")""" } + val clazz = ex.getClass.getName.split('.').last + + s"$clazz$msg @ $frame" + } + lazy val trace = new SimpleTracer(System.out) - lazy val errtrace = new SimpleTracer(System.err) @deprecated("Moved to scala.reflect.internal.util.StringOps", "2.10.0") val StringOps = scala.reflect.internal.util.StringOps diff --git a/src/compiler/scala/tools/reflect/MacroImplementations.scala b/src/compiler/scala/tools/reflect/MacroImplementations.scala index 86cd845c54..d7c50504a8 100644 --- a/src/compiler/scala/tools/reflect/MacroImplementations.scala +++ b/src/compiler/scala/tools/reflect/MacroImplementations.scala @@ -1,6 +1,5 @@ package scala.tools.reflect -import scala.reflect.macros.{ReificationException, UnexpectedReificationException} import scala.reflect.macros.runtime.Context import scala.collection.mutable.ListBuffer import scala.collection.mutable.Stack @@ -147,4 +146,4 @@ abstract class MacroImplementations { Block(evals.toList, atPos(origApplyPos.focus)(expr)) setPos origApplyPos.makeTransparent } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/reflect/ReflectMain.scala b/src/compiler/scala/tools/reflect/ReflectMain.scala index 116ae24cdd..3ae21b6b98 100644 --- a/src/compiler/scala/tools/reflect/ReflectMain.scala +++ b/src/compiler/scala/tools/reflect/ReflectMain.scala @@ -4,7 +4,6 @@ package reflect import scala.tools.nsc.Driver import scala.tools.nsc.Global import scala.tools.nsc.Settings -import scala.tools.nsc.util.ClassPath.DefaultJavaContext import scala.tools.nsc.util.ScalaClassLoader import scala.tools.util.PathResolver @@ -16,4 +15,4 @@ object ReflectMain extends Driver { } override def newCompiler(): Global = new ReflectGlobal(settings, reporter, classloaderFromSettings(settings)) -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/reflect/StdTags.scala b/src/compiler/scala/tools/reflect/StdTags.scala index a3bc9b9bd1..5c62819f04 100644 --- a/src/compiler/scala/tools/reflect/StdTags.scala +++ b/src/compiler/scala/tools/reflect/StdTags.scala @@ -1,7 +1,6 @@ package scala.tools package reflect -import java.lang.{Class => jClass} import scala.reflect.{ClassTag, classTag} import scala.reflect.api.{Mirror, TypeCreator, Universe => ApiUniverse} diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 95135b84e0..b1d343cee9 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -3,12 +3,8 @@ package reflect import scala.tools.nsc.reporters._ import scala.tools.nsc.CompilerCommand -import scala.tools.nsc.Global -import scala.tools.nsc.typechecker.Modes import scala.tools.nsc.io.VirtualDirectory import scala.tools.nsc.interpreter.AbstractFileClassLoader -import scala.tools.nsc.util.FreshNameCreator -import scala.reflect.internal.Flags import scala.reflect.internal.util.{BatchSourceFile, NoSourceFile, NoFile} import java.lang.{Class => jClass} import scala.compat.Platform.EOL @@ -29,8 +25,8 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => lazy val classLoader = new AbstractFileClassLoader(virtualDirectory, factorySelf.mirror.classLoader) lazy val mirror: u.Mirror = u.runtimeMirror(classLoader) - class ToolBoxGlobal(settings: scala.tools.nsc.Settings, reporter: Reporter) - extends ReflectGlobal(settings, reporter, toolBoxSelf.classLoader) { + class ToolBoxGlobal(settings: scala.tools.nsc.Settings, reporter0: Reporter) + extends ReflectGlobal(settings, reporter0, toolBoxSelf.classLoader) { import definitions._ private val trace = scala.tools.nsc.util.trace when settings.debug.value @@ -73,13 +69,14 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => val typed = expr filter (t => t.tpe != null && t.tpe != NoType && !t.isInstanceOf[TypeTree]) if (!typed.isEmpty) throw ToolBoxError("reflective toolbox has failed: cannot operate on trees that are already typed") - val freeTypes = expr.freeTypes - if (freeTypes.length > 0) { - var msg = "reflective toolbox has failed:" + EOL - msg += "unresolved free type variables (namely: " + (freeTypes map (ft => "%s %s".format(ft.name, ft.origin)) mkString ", ") + "). " - msg += "have you forgot to use TypeTag annotations for type parameters external to a reifee? " - msg += "if you have troubles tracking free type variables, consider using -Xlog-free-types" - throw ToolBoxError(msg) + if (expr.freeTypes.nonEmpty) { + val ft_s = expr.freeTypes map (ft => s" ${ft.name} ${ft.origin}") mkString "\n " + throw ToolBoxError(s""" + |reflective toolbox failed due to unresolved free type variables: + |$ft_s + |have you forgotten to use TypeTag annotations for type parameters external to a reifee? + |if you have troubles tracking free type variables, consider using -Xlog-free-types + """.stripMargin.trim) } } @@ -100,9 +97,9 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => if (namesakes.length > 0) name += ("$" + (namesakes.length + 1)) freeTermNames += (ft -> newTermName(name + nme.REIFY_FREE_VALUE_SUFFIX)) }) - var expr = new Transformer { + val expr = new Transformer { override def transform(tree: Tree): Tree = - if (tree.hasSymbol && tree.symbol.isFreeTerm) { + if (tree.hasSymbolField && tree.symbol.isFreeTerm) { tree match { case Ident(_) => val freeTermRef = Ident(freeTermNames(tree.symbol.asFreeTerm)) @@ -132,7 +129,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => val ownerClass = rootMirror.EmptyPackageClass.newClassSymbol(newTypeName("<expression-owner>")) build.setTypeSignature(ownerClass, ClassInfoType(List(ObjectClass.tpe), newScope, ownerClass)) val owner = ownerClass.newLocalDummy(expr.pos) - var currentTyper = analyzer.newTyper(analyzer.rootContext(NoCompilationUnit, EmptyTree).make(expr, owner)) + val currentTyper = analyzer.newTyper(analyzer.rootContext(NoCompilationUnit, EmptyTree).make(expr, owner)) val wrapper1 = if (!withImplicitViewsDisabled) (currentTyper.context.withImplicitsEnabled[Tree] _) else (currentTyper.context.withImplicitsDisabled[Tree] _) val wrapper2 = if (!withMacrosDisabled) (currentTyper.context.withMacrosEnabled[Tree] _) else (currentTyper.context.withMacrosDisabled[Tree] _) def wrapper (tree: => Tree) = wrapper1(wrapper2(tree)) @@ -146,7 +143,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => case Block(dummies, unwrapped) => (dummies, unwrapped) case unwrapped => (Nil, unwrapped) } - var invertedIndex = freeTerms map (_.swap) + val invertedIndex = freeTerms map (_.swap) // todo. also fixup singleton types unwrapped = new Transformer { override def transform(tree: Tree): Tree = @@ -202,7 +199,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => def wrap(expr0: Tree): ModuleDef = { val (expr, freeTerms) = extractFreeTerms(expr0, wrapFreeTermRefs = true) - val (obj, mclazz) = rootMirror.EmptyPackageClass.newModuleAndClassSymbol( + val (obj, _) = rootMirror.EmptyPackageClass.newModuleAndClassSymbol( nextWrapperModuleName()) val minfo = ClassInfoType(List(ObjectClass.tpe), newScope, obj.moduleClass) @@ -235,7 +232,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => NoPosition)) trace("wrapped: ")(showAttributed(moduledef, true, true, settings.Yshowsymkinds.value)) - var cleanedUp = resetLocalAttrs(moduledef) + val cleanedUp = resetLocalAttrs(moduledef) trace("cleaned up: ")(showAttributed(cleanedUp, true, true, settings.Yshowsymkinds.value)) cleanedUp.asInstanceOf[ModuleDef] } @@ -312,11 +309,9 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => // reporter doesn't accumulate errors, but the front-end does def throwIfErrors() = { - if (frontEnd.hasErrors) { - var msg = "reflective compilation has failed: " + EOL + EOL - msg += frontEnd.infos map (_.msg) mkString EOL - throw ToolBoxError(msg) - } + if (frontEnd.hasErrors) throw ToolBoxError( + "reflective compilation has failed: " + EOL + EOL + (frontEnd.infos map (_.msg) mkString EOL) + ) } } @@ -336,15 +331,15 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => command.settings.outputDirs setSingleOutput virtualDirectory val instance = new ToolBoxGlobal(command.settings, frontEndToReporter(frontEnd, command.settings)) if (frontEnd.hasErrors) { - var msg = "reflective compilation has failed: cannot initialize the compiler: " + EOL + EOL - msg += frontEnd.infos map (_.msg) mkString EOL - throw ToolBoxError(msg) + throw ToolBoxError( + "reflective compilation has failed: cannot initialize the compiler: " + EOL + EOL + + (frontEnd.infos map (_.msg) mkString EOL) + ) } instance } catch { case ex: Throwable => - var msg = "reflective compilation has failed: cannot initialize the compiler due to %s".format(ex.toString) - throw ToolBoxError(msg, ex) + throw ToolBoxError(s"reflective compilation has failed: cannot initialize the compiler due to $ex", ex) } } @@ -353,8 +348,8 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => def typeCheck(tree: u.Tree, expectedType: u.Type, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree = compiler.withCleanupCaches { if (compiler.settings.verbose.value) println("importing "+tree+", expectedType = "+expectedType) - var ctree: compiler.Tree = importer.importTree(tree) - var cexpectedType: compiler.Type = importer.importType(expectedType) + val ctree: compiler.Tree = importer.importTree(tree) + val cexpectedType: compiler.Type = importer.importType(expectedType) if (compiler.settings.verbose.value) println("typing "+ctree+", expectedType = "+expectedType) val ttree: compiler.Tree = compiler.typeCheck(ctree, cexpectedType, silent = silent, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled) @@ -373,9 +368,9 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => private def inferImplicit(tree: u.Tree, pt: u.Type, isView: Boolean, silent: Boolean, withMacrosDisabled: Boolean, pos: u.Position): u.Tree = compiler.withCleanupCaches { if (compiler.settings.verbose.value) println("importing "+pt, ", tree = "+tree+", pos = "+pos) - var ctree: compiler.Tree = importer.importTree(tree) - var cpt: compiler.Type = importer.importType(pt) - var cpos: compiler.Position = importer.importPosition(pos) + val ctree: compiler.Tree = importer.importTree(tree) + val cpt: compiler.Type = importer.importType(pt) + val cpos: compiler.Position = importer.importPosition(pos) if (compiler.settings.verbose.value) println("inferring implicit %s of type %s, macros = %s".format(if (isView) "view" else "value", pt, !withMacrosDisabled)) val itree: compiler.Tree = compiler.inferImplicit(ctree, cpt, isView = isView, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = cpos) @@ -397,9 +392,6 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => uttree } - def showAttributed(tree: u.Tree, printTypes: Boolean = true, printIds: Boolean = true, printKinds: Boolean = false): String = - compiler.showAttributed(importer.importTree(tree), printTypes, printIds, printKinds) - def parse(code: String): u.Tree = { if (compiler.settings.verbose.value) println("parsing "+code) val ctree: compiler.Tree = compiler.parse(code) @@ -409,7 +401,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => def compile(tree: u.Tree): () => Any = { if (compiler.settings.verbose.value) println("importing "+tree) - var ctree: compiler.Tree = importer.importTree(tree) + val ctree: compiler.Tree = importer.importTree(tree) if (compiler.settings.verbose.value) println("compiling "+ctree) compiler.compile(ctree) diff --git a/src/compiler/scala/tools/reflect/package.scala b/src/compiler/scala/tools/reflect/package.scala index 3f880bf7f8..bf533766d0 100644 --- a/src/compiler/scala/tools/reflect/package.scala +++ b/src/compiler/scala/tools/reflect/package.scala @@ -76,7 +76,6 @@ package object reflect { private[reflect] def frontEndToReporter(frontEnd: FrontEnd, settings0: Settings): Reporter = new AbstractReporter { val settings = settings0 - import frontEnd.{Severity => ApiSeverity} val API_INFO = frontEnd.INFO val API_WARNING = frontEnd.WARNING val API_ERROR = frontEnd.ERROR diff --git a/src/compiler/scala/tools/util/Javap.scala b/src/compiler/scala/tools/util/Javap.scala index c3264d0787..381dbd1d87 100644 --- a/src/compiler/scala/tools/util/Javap.scala +++ b/src/compiler/scala/tools/util/Javap.scala @@ -6,10 +6,8 @@ package scala.tools package util -import java.lang.reflect.{ GenericSignatureFormatError, Method, Constructor } -import java.lang.{ ClassLoader => JavaClassLoader } import scala.tools.nsc.util.ScalaClassLoader -import java.io.{ InputStream, PrintWriter, ByteArrayInputStream, FileNotFoundException } +import java.io.{ InputStream, PrintWriter, ByteArrayInputStream } import scala.tools.nsc.io.File import Javap._ import scala.language.reflectiveCalls @@ -109,19 +107,11 @@ object Javap { type FakeEnvironment = AnyRef type FakePrinter = AnyRef - def apply(path: String): Unit = apply(Seq(path)) - def apply(args: Seq[String]): Unit = new JavapClass() apply args foreach (_.show()) - sealed trait JpResult { type ResultType def isError: Boolean def value: ResultType def show(): Unit - // todo - // def header(): String - // def fields(): List[String] - // def methods(): List[String] - // def signatures(): List[String] } class JpError(msg: String) extends JpResult { type ResultType = String diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala index 0af1011bda..5d79a7d6cd 100644 --- a/src/compiler/scala/tools/util/PathResolver.scala +++ b/src/compiler/scala/tools/util/PathResolver.scala @@ -6,7 +6,6 @@ package scala.tools package util -import java.net.{ URL, MalformedURLException } import scala.tools.reflect.WrappedProperties.AccessControl import nsc.{ Settings, GenericRunnerSettings } import nsc.util.{ ClassPath, JavaClassPath, ScalaClassLoader } @@ -19,16 +18,9 @@ import scala.language.postfixOps // https://wiki.scala-lang.org/display/SW/Classpath object PathResolver { - // Imports property/environment functions which suppress - // security exceptions. + // Imports property/environment functions which suppress security exceptions. import AccessControl._ - def firstNonEmpty(xs: String*) = xs find (_ != "") getOrElse "" - - /** Map all classpath elements to absolute paths and reconstruct the classpath. - */ - def makeAbsolute(cp: String) = ClassPath.map(cp, x => Path(x).toAbsolute.path) - /** pretty print class path */ def ppcp(s: String) = split(s) match { case Nil => "" @@ -46,7 +38,6 @@ object PathResolver { /** Environment variables which java pays attention to so it * seems we do as well. */ - def classPathEnv = envOrElse("CLASSPATH", "") def sourcePathEnv = envOrElse("SOURCEPATH", "") def javaBootClassPath = propOrElse("sun.boot.class.path", searchForBootClasspath) @@ -86,7 +77,6 @@ object PathResolver { def scalaHome = Environment.scalaHome def scalaHomeDir = Directory(scalaHome) - def scalaHomeExists = scalaHomeDir.isDirectory def scalaLibDir = Directory(scalaHomeDir / "lib") def scalaClassesDir = Directory(scalaHomeDir / "classes") @@ -109,15 +99,7 @@ object PathResolver { // classpath as set up by the runner (or regular classpath under -nobootcp) // and then again here. def scalaBootClassPath = "" - // scalaLibDirFound match { - // case Some(dir) if scalaHomeExists => - // val paths = ClassPath expandDir dir.path - // join(paths: _*) - // case _ => "" - // } - def scalaExtDirs = Environment.scalaExtDirs - def scalaPluginPath = (scalaHomeDir / "misc" / "scala-devel" / "plugins").path override def toString = """ @@ -136,7 +118,7 @@ object PathResolver { ) } - def fromPathString(path: String, context: JavaContext = DefaultJavaContext): JavaClassPath = { + def fromPathString(path: String, context: JavaContext = DefaultJavaContext): JavaClassPath = { // called from scalap val s = new Settings() s.classpath.value = path new PathResolver(s, context) result @@ -161,7 +143,7 @@ object PathResolver { } } } -import PathResolver.{ Defaults, Environment, firstNonEmpty, ppcp } +import PathResolver.{ Defaults, Environment, ppcp } class PathResolver(settings: Settings, context: JavaContext) { def this(settings: Settings) = this(settings, if (settings.inline.value) new JavaContext else DefaultJavaContext) diff --git a/src/continuations/library/scala/util/continuations/ControlContext.scala b/src/continuations/library/scala/util/continuations/ControlContext.scala index 44a5b537b6..c196809da9 100644 --- a/src/continuations/library/scala/util/continuations/ControlContext.scala +++ b/src/continuations/library/scala/util/continuations/ControlContext.scala @@ -183,7 +183,7 @@ final class ControlContext[+A,-B,+C](val fun: (A => B, Exception => B) => C, val // need filter or other functions? - final def flatMapCatch[A1>:A,B1<:B,C1>:C<:B1](pf: PartialFunction[Exception, ControlContext[A1,B1,C1]]): ControlContext[A1,B1,C1] = { + final def flatMapCatch[A1>:A,B1<:B,C1>:C<:B1](pf: PartialFunction[Exception, ControlContext[A1,B1,C1]]): ControlContext[A1,B1,C1] = { // called by codegen from SelectiveCPSTransform if (fun eq null) this else { @@ -209,7 +209,7 @@ final class ControlContext[+A,-B,+C](val fun: (A => B, Exception => B) => C, val } } - final def mapFinally(f: () => Unit): ControlContext[A,B,C] = { + final def mapFinally(f: () => Unit): ControlContext[A,B,C] = { // called in code generated by SelectiveCPSTransform if (fun eq null) { try { f() diff --git a/src/continuations/library/scala/util/continuations/package.scala b/src/continuations/library/scala/util/continuations/package.scala index 90bab56805..573fae85e7 100644 --- a/src/continuations/library/scala/util/continuations/package.scala +++ b/src/continuations/library/scala/util/continuations/package.scala @@ -166,8 +166,8 @@ package object continuations { throw new NoSuchMethodException("this code has to be compiled with the Scala continuations plugin enabled") } - def shiftUnitR[A,B](x: A): ControlContext[A,B,B] = { - new ControlContext(null, x) + def shiftUnitR[A,B](x: A): ControlContext[A,B,B] = { // called in code generated by SelectiveCPSTransform + new ControlContext[A, B, B](null, x) } /** @@ -176,11 +176,11 @@ package object continuations { * a final result. * @see shift */ - def shiftR[A,B,C](fun: (A => B) => C): ControlContext[A,B,C] = { + def shiftR[A,B,C](fun: (A => B) => C): ControlContext[A,B,C] = { // called in code generated by SelectiveCPSTransform new ControlContext((f:A=>B,g:Exception=>B) => fun(f), null.asInstanceOf[A]) } - def reifyR[A,B,C](ctx: => ControlContext[A,B,C]): ControlContext[A,B,C] = { + def reifyR[A,B,C](ctx: => ControlContext[A,B,C]): ControlContext[A,B,C] = { // called in code generated by SelectiveCPSTransform ctx } diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala index 15025f85e3..c147dc483d 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala @@ -96,7 +96,7 @@ abstract class CPSAnnotationChecker extends CPSUtils with Modes { if (!cpsEnabled) return bounds val anyAtCPS = newCpsParamsMarker(NothingClass.tpe, AnyClass.tpe) - if (isFunctionType(tparams.head.owner.tpe) || isPartialFunctionType(tparams.head.owner.tpe)) { + if (isFunctionType(tparams.head.owner.tpe_*) || isPartialFunctionType(tparams.head.owner.tpe_*)) { vprintln("function bound: " + tparams.head.owner.tpe + "/"+bounds+"/"+targs) if (hasCpsParamTypes(targs.last)) bounds.reverse match { @@ -356,7 +356,7 @@ abstract class CPSAnnotationChecker extends CPSUtils with Modes { global.globalError("not a single cps annotation: " + xs) xs(0) } - + def emptyOrSingleList(xs: List[AnnotationInfo]) = if (xs.isEmpty) Nil else List(single(xs)) def transChildrenInOrder(tree: Tree, tpe: Type, childTrees: List[Tree], byName: List[Tree]) = { diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala index 46c644bcd6..c591030bce 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala @@ -7,7 +7,6 @@ import scala.tools.nsc.Global trait CPSUtils { val global: Global import global._ - import definitions._ var cpsEnabled = false val verbose: Boolean = System.getProperty("cpsVerbose", "false") == "true" @@ -57,7 +56,7 @@ trait CPSUtils { protected def newMarker(sym: Symbol): AnnotationInfo = AnnotationInfo marker sym.tpe protected def newCpsParamsMarker(tp1: Type, tp2: Type) = - newMarker(appliedType(MarkerCPSTypes.tpe, List(tp1, tp2))) + newMarker(appliedType(MarkerCPSTypes, tp1, tp2)) // annotation checker diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala index 8b39bf3961..f62eebaaa0 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala @@ -2,13 +2,10 @@ package scala.tools.selectivecps -import scala.tools.nsc._ import scala.tools.nsc.transform._ import scala.tools.nsc.symtab._ import scala.tools.nsc.plugins._ -import scala.tools.nsc.ast._ - /** * In methods marked @cps, explicitly name results of calls to other @cps methods */ @@ -172,7 +169,7 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with debuglog("transforming valdef " + vd.symbol) if (getExternalAnswerTypeAnn(tpt.tpe).isEmpty) { - + atOwner(vd.symbol) { val rhs1 = transExpr(rhs, None, None) @@ -471,7 +468,7 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with val sym: Symbol = ( currentOwner.newValue(newTermName(unit.fresh.newName("tmp")), tree.pos, Flags.SYNTHETIC) setInfo valueTpe - setAnnotations List(AnnotationInfo(MarkerCPSSym.tpe, Nil, Nil)) + setAnnotations List(AnnotationInfo(MarkerCPSSym.tpe_*, Nil, Nil)) ) expr.changeOwner(currentOwner -> sym) @@ -503,9 +500,7 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with // TODO: better yet: do without annotations on symbols val spcVal = getAnswerTypeAnn(anfRhs.tpe) - if (spcVal.isDefined) { - tree.symbol.setAnnotations(List(AnnotationInfo(MarkerCPSSym.tpe, Nil, Nil))) - } + spcVal foreach (_ => tree.symbol setAnnotations List(AnnotationInfo(MarkerCPSSym.tpe_*, Nil, Nil))) (stms:::List(treeCopy.ValDef(tree, mods, name, tpt, anfRhs)), linearize(spc, spcVal)(unit, tree.pos)) diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSPlugin.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSPlugin.scala index 8a500d6c4d..90e64d8171 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSPlugin.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSPlugin.scala @@ -3,15 +3,11 @@ package scala.tools.selectivecps import scala.tools.nsc -import scala.tools.nsc.typechecker._ import nsc.Global -import nsc.Phase import nsc.plugins.Plugin import nsc.plugins.PluginComponent class SelectiveCPSPlugin(val global: Global) extends Plugin { - import global._ - val name = "continuations" val description = "applies selective cps conversion" @@ -26,7 +22,6 @@ class SelectiveCPSPlugin(val global: Global) extends Plugin { override val runsBefore = List("uncurry") } - val components = List[PluginComponent](anfPhase, cpsPhase) val checker = new CPSAnnotationChecker { diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala index 4482bf2b7c..f16cfb10f8 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala @@ -2,13 +2,8 @@ package scala.tools.selectivecps -import scala.collection._ - -import scala.tools.nsc._ import scala.tools.nsc.transform._ import scala.tools.nsc.plugins._ - -import scala.tools.nsc.ast.TreeBrowsers import scala.tools.nsc.ast._ /** @@ -56,7 +51,7 @@ abstract class SelectiveCPSTransform extends PluginComponent with case _ => getExternalAnswerTypeAnn(tp) match { case Some((res, outer)) => - appliedType(Context.tpe, List(removeAllCPSAnnotations(tp), res, outer)) + appliedType(Context.tpeHK, List(removeAllCPSAnnotations(tp), res, outer)) case _ => removeAllCPSAnnotations(tp) } @@ -107,7 +102,7 @@ abstract class SelectiveCPSTransform extends PluginComponent with TypeApply(funR, List(targs(0), targs(1))).setType(appliedType(funR.tpe, List(targs(0).tpe, targs(1).tpe))), args.map(transform(_)) - ).setType(appliedType(Context.tpe, List(targs(0).tpe,targs(1).tpe,targs(1).tpe))) + ).setType(appliedType(Context.tpeHK, List(targs(0).tpe,targs(1).tpe,targs(1).tpe))) } case Apply(TypeApply(fun, targs), args) @@ -192,7 +187,7 @@ abstract class SelectiveCPSTransform extends PluginComponent with val targettp = transformCPSType(tree.tpe) val pos = catches.head.pos - val funSym = currentOwner.newValueParameter(cpsNames.catches, pos).setInfo(appliedType(PartialFunctionClass.tpe, List(ThrowableClass.tpe, targettp))) + val funSym = currentOwner.newValueParameter(cpsNames.catches, pos).setInfo(appliedType(PartialFunctionClass, ThrowableClass.tpe, targettp)) val funDef = localTyper.typedPos(pos) { ValDef(funSym, Match(EmptyTree, catches1)) } diff --git a/src/detach/plugin/scala/tools/detach/Detach.scala b/src/detach/plugin/scala/tools/detach/Detach.scala index f9a3d80da4..499a97b761 100644 --- a/src/detach/plugin/scala/tools/detach/Detach.scala +++ b/src/detach/plugin/scala/tools/detach/Detach.scala @@ -73,7 +73,7 @@ abstract class Detach extends PluginComponent } private val serializableAnnotationInfo = - AnnotationInfo(SerializableAttr.tpe, List(), List()) + AnnotationInfo(requiredClass[scala.annotation.serializable].tpe, List(), List()) /* private val throwsAnnotationInfo = { val RemoteExceptionClass = definitions.getClass("java.rmi.RemoteException") @@ -206,7 +206,7 @@ abstract class Detach extends PluginComponent symSet(capturedObjects, owner) += qsym case Select(qual, name) - if (qual.hasSymbol && + if (qual.hasSymbolField && (sym.owner != owner) && !(sym.ownerChain contains ScalaPackageClass) && !(sym.owner hasFlag JAVA)) => @@ -284,7 +284,7 @@ abstract class Detach extends PluginComponent def isOuter(sym: Symbol): Boolean = sym.isOuterAccessor || sym.name.endsWith(nme.OUTER/*, nme.OUTER.length*/) - if (tree.hasSymbol && isOuter(tree.symbol)) subst(from, to) + if (tree.hasSymbolField && isOuter(tree.symbol)) subst(from, to) super.traverse(tree) } } @@ -293,7 +293,7 @@ abstract class Detach extends PluginComponent private class TreeTypeRefSubstituter(clazz: Symbol) extends Traverser { override def traverse(tree: Tree) { val sym = tree.symbol - if (tree.hasSymbol && isRefClass(sym.tpe) && + if (tree.hasSymbolField && isRefClass(sym.tpe) && (sym.owner.enclClass == clazz) && (sym.isValueParameter || sym.hasFlag(PARAMACCESSOR))) { sym setInfo mkRemoteRefClass(sym.tpe) @@ -329,7 +329,7 @@ abstract class Detach extends PluginComponent } val map = new mutable.HashMap[Symbol, Symbol] override def traverse(tree: Tree) { - if (tree.hasSymbol && tree.symbol != NoSymbol) { + if (tree.hasSymbolField && tree.symbol != NoSymbol) { val sym = tree.symbol if (sym.owner == from) { val sym1 = map get sym match { @@ -369,7 +369,7 @@ abstract class Detach extends PluginComponent def removeAccessors(tree: Tree): Tree = tree match { case Apply(fun, _) => removeAccessors(fun) - case Select(qual, _) if tree.hasSymbol && tree.symbol.isOuterAccessor => + case Select(qual, _) if tree.hasSymbolField && tree.symbol.isOuterAccessor => removeAccessors(qual) case _ => tree @@ -382,7 +382,7 @@ abstract class Detach extends PluginComponent // transforms field assignment $outer.i$1.elem=.. // into setter $outer.i$1_=(..) case Assign(lhs @ Select(qual1 @ Select(qual, name), name1), rhs) - if qual1.hasSymbol && !qual1.symbol.isPrivateLocal && + if qual1.hasSymbolField && !qual1.symbol.isPrivateLocal && isRemoteRefClass(qual1.tpe) => if (DEBUG) println("\nTreeAccessorSubstituter: Assign1\n\tqual1="+qual1+", sel.tpe="+lhs.tpe+ @@ -398,7 +398,7 @@ abstract class Detach extends PluginComponent // transforms local assignment this.x$1.elem=.. // into setter method this.x$1_=(..) case Assign(lhs @ Select(qual, name), rhs) - if qual.hasSymbol && qual.symbol.isPrivateLocal && + if qual.hasSymbolField && qual.symbol.isPrivateLocal && isRemoteRefClass(qual.tpe) => if (DEBUG) println("\nTreeAccessorSubstituter: Assign2"+ @@ -412,7 +412,7 @@ abstract class Detach extends PluginComponent Apply(fun, List(super.transform(rhs))) setType lhs.tpe case Assign(Select(qual, name), rhs) - if qual.hasSymbol && (objs contains qual.symbol) => + if qual.hasSymbolField && (objs contains qual.symbol) => val sym = qual.symbol val proxy = proxySyms(objs indexOf sym) if (DEBUG) @@ -461,7 +461,7 @@ abstract class Detach extends PluginComponent // transforms field $outer.name$1 into getter method $outer.name$1() case Select(qual @ Select(_, name1), name) - if qual.hasSymbol && name1.endsWith(nme.OUTER/*, nme.OUTER.length*/) && + if qual.hasSymbolField && name1.endsWith(nme.OUTER/*, nme.OUTER.length*/) && !tree.symbol.isMethod => if (DEBUG) println("\nTreeAccessorSubstituter: Select0\n\tqual="+qual+ @@ -500,7 +500,7 @@ abstract class Detach extends PluginComponent // transforms field access $outer.i$1.elem // into invocation of getter method $outer.i$1() case Select(qual @ Select(qual1, name1), name) - if qual.hasSymbol && !qual.symbol.isPrivateLocal && + if qual.hasSymbolField && !qual.symbol.isPrivateLocal && isRemoteRefClass(qual.tpe) => if (DEBUG) println("\nTreeAccessorSubstituter: Select2\n\tqual="+qual+ @@ -513,7 +513,7 @@ abstract class Detach extends PluginComponent // transforms local access this.i$1.elem // into invocation of getter method this.i$1() case Select(qual, name) - if qual.hasSymbol && qual.symbol.isPrivateLocal && + if qual.hasSymbolField && qual.symbol.isPrivateLocal && isRemoteRefClass(qual.tpe) => if (DEBUG) println("\nTreeAccessorSubstituter: Select3\n\tqual="+qual+ @@ -523,7 +523,7 @@ abstract class Detach extends PluginComponent Apply(fun, List()) setType tree.tpe case Select(qual, name) - if qual.hasSymbol && (objs contains qual.symbol) => + if qual.hasSymbolField && (objs contains qual.symbol) => if (DEBUG) println("\nTreeAccessorSubstituter: Select4\n\tqual="+qual+ ", qual.tpe="+qual.tpe+", name="+name)//debug diff --git a/src/library/scala/Application.scala b/src/library/scala/Application.scala deleted file mode 100644 index e7db0d2db8..0000000000 --- a/src/library/scala/Application.scala +++ /dev/null @@ -1,79 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala - -import scala.compat.Platform.currentTime - -/** The `Application` trait can be used to quickly turn objects - * into executable programs, but is ''not recommended''. - * Here is an example: - * {{{ - * object Main extends Application { - * Console.println("Hello World!") - * } - * }}} - * Here, object `Main` inherits the `main` method of `Application`. - * The body of the `Main` object defines the main program. This technique - * does not work if the main program depends on command-line arguments - * (which are not accessible with the technique presented here). - * - * It is possible to time the execution of objects that inherit from class - * `Application` by setting the global `scala.time` - * property. Here is an example for benchmarking object `Main`: - * {{{ - * java -Dscala.time Main - * }}} - * In practice the `Application` trait has a number of serious pitfalls: - * - * - Threaded code that references the object will block until static - * initialization is complete. However, because the entire execution - * of an `object` extending `Application` takes place during - * static initialization, concurrent code will ''always'' deadlock if - * it must synchronize with the enclosing object. - * - As described above, there is no way to obtain the - * command-line arguments because all code in body of an `object` - * extending `Application` is run as part of the static initialization - * which occurs before `Application`'s `main` method - * even begins execution. - * - Static initializers are run only once during program execution, and - * JVM authors usually assume their execution to be relatively short. - * Therefore, certain JVM configurations may become confused, or simply - * fail to optimize or JIT the code in the body of an `object` extending - * `Application`. This can lead to a significant performance degradation. - * - * It is recommended to use the [[scala.App]] trait instead. - * {{{ - * object Main { - * def main(args: Array[String]) { - * //.. - * } - * } - * }}} - * - * @author Matthias Zenger - * @version 1.0, 10/09/2003 - */ -@deprecated("use App instead", "2.9.0") -trait Application { - - /** The time when the execution of this program started, - * in milliseconds since 1 January 1970 UTC. */ - val executionStart: Long = currentTime - - /** The default main method. - * - * @param args the arguments passed to the main method - */ - def main(args: Array[String]) { - if (util.Properties propIsSet "scala.time") { - val total = currentTime - executionStart - Console.println("[total " + total + "ms]") - } - } -} diff --git a/src/library/scala/Array.scala b/src/library/scala/Array.scala index 90684b5fdd..b9f51803ec 100644 --- a/src/library/scala/Array.scala +++ b/src/library/scala/Array.scala @@ -115,6 +115,8 @@ object Array extends FallbackArrayBuilding { * @param xs the elements to put in the array * @return an array containing all elements from xs. */ + // Subject to a compiler optimization in Cleanup. + // Array(e0, ..., en) is translated to { val a = new Array(3); a(i) = ei; a } def apply[T: ClassTag](xs: T*): Array[T] = { val array = new Array[T](xs.length) var i = 0 @@ -123,6 +125,7 @@ object Array extends FallbackArrayBuilding { } /** Creates an array of `Boolean` objects */ + // Subject to a compiler optimization in Cleanup, see above. def apply(x: Boolean, xs: Boolean*): Array[Boolean] = { val array = new Array[Boolean](xs.length + 1) array(0) = x @@ -132,6 +135,7 @@ object Array extends FallbackArrayBuilding { } /** Creates an array of `Byte` objects */ + // Subject to a compiler optimization in Cleanup, see above. def apply(x: Byte, xs: Byte*): Array[Byte] = { val array = new Array[Byte](xs.length + 1) array(0) = x @@ -141,6 +145,7 @@ object Array extends FallbackArrayBuilding { } /** Creates an array of `Short` objects */ + // Subject to a compiler optimization in Cleanup, see above. def apply(x: Short, xs: Short*): Array[Short] = { val array = new Array[Short](xs.length + 1) array(0) = x @@ -150,6 +155,7 @@ object Array extends FallbackArrayBuilding { } /** Creates an array of `Char` objects */ + // Subject to a compiler optimization in Cleanup, see above. def apply(x: Char, xs: Char*): Array[Char] = { val array = new Array[Char](xs.length + 1) array(0) = x @@ -159,6 +165,7 @@ object Array extends FallbackArrayBuilding { } /** Creates an array of `Int` objects */ + // Subject to a compiler optimization in Cleanup, see above. def apply(x: Int, xs: Int*): Array[Int] = { val array = new Array[Int](xs.length + 1) array(0) = x @@ -168,6 +175,7 @@ object Array extends FallbackArrayBuilding { } /** Creates an array of `Long` objects */ + // Subject to a compiler optimization in Cleanup, see above. def apply(x: Long, xs: Long*): Array[Long] = { val array = new Array[Long](xs.length + 1) array(0) = x @@ -177,6 +185,7 @@ object Array extends FallbackArrayBuilding { } /** Creates an array of `Float` objects */ + // Subject to a compiler optimization in Cleanup, see above. def apply(x: Float, xs: Float*): Array[Float] = { val array = new Array[Float](xs.length + 1) array(0) = x @@ -186,6 +195,7 @@ object Array extends FallbackArrayBuilding { } /** Creates an array of `Double` objects */ + // Subject to a compiler optimization in Cleanup, see above. def apply(x: Double, xs: Double*): Array[Double] = { val array = new Array[Double](xs.length + 1) array(0) = x diff --git a/src/library/scala/Option.scala b/src/library/scala/Option.scala index 3873df99e9..4b071166c7 100644 --- a/src/library/scala/Option.scala +++ b/src/library/scala/Option.scala @@ -209,6 +209,15 @@ sealed abstract class Option[+A] extends Product with Serializable { def withFilter(q: A => Boolean): WithFilter = new WithFilter(x => p(x) && q(x)) } + /** Tests whether the option contains a given value as an element. + * + * @param elem the element to test. + * @return `true` if the option has an element that is equal (as + * determined by `==`) to `elem`, `false` otherwise. + */ + final def contains[A1 >: A](elem: A1): Boolean = + !isEmpty && this.get == elem + /** Returns true if this option is nonempty '''and''' the predicate * $p returns true when applied to this $option's value. * Otherwise, returns false. @@ -247,7 +256,7 @@ sealed abstract class Option[+A] extends Product with Serializable { * value (if possible), or $none. */ @inline final def collect[B](pf: PartialFunction[A, B]): Option[B] = - if (!isEmpty && pf.isDefinedAt(this.get)) Some(pf(this.get)) else None + if (!isEmpty) pf.lift(this.get) else None /** Returns this $option if it is nonempty, * otherwise return the result of evaluating `alternative`. diff --git a/src/library/scala/SerialVersionUID.scala b/src/library/scala/SerialVersionUID.scala index 1f7d047060..77094f0bbf 100644 --- a/src/library/scala/SerialVersionUID.scala +++ b/src/library/scala/SerialVersionUID.scala @@ -12,4 +12,4 @@ package scala * Annotation for specifying the `static SerialVersionUID` field * of a serializable class. */ -class SerialVersionUID(uid: Long) extends scala.annotation.StaticAnnotation +class SerialVersionUID(value: Long) extends scala.annotation.ClassfileAnnotation diff --git a/src/library/scala/UninitializedFieldError.scala b/src/library/scala/UninitializedFieldError.scala index 10c6cccf15..0dfba2a187 100644 --- a/src/library/scala/UninitializedFieldError.scala +++ b/src/library/scala/UninitializedFieldError.scala @@ -18,8 +18,6 @@ package scala * * @since 2.7 */ -final case class UninitializedFieldError(msg: String) - extends RuntimeException(msg) { - def this(obj: Any) = - this(if (null != obj) obj.toString() else "null") +final case class UninitializedFieldError(msg: String) extends RuntimeException(msg) { + def this(obj: Any) = this("" + obj) } diff --git a/src/library/scala/collection/BitSetLike.scala b/src/library/scala/collection/BitSetLike.scala index 4a1c0beaa6..d0f4e323c7 100644 --- a/src/library/scala/collection/BitSetLike.scala +++ b/src/library/scala/collection/BitSetLike.scala @@ -11,7 +11,6 @@ package scala.collection import BitSetLike._ -import generic._ import mutable.StringBuilder /** A template trait for bitsets. diff --git a/src/library/scala/collection/DefaultMap.scala b/src/library/scala/collection/DefaultMap.scala index 5c91183891..cbd7e3f8b9 100644 --- a/src/library/scala/collection/DefaultMap.scala +++ b/src/library/scala/collection/DefaultMap.scala @@ -6,12 +6,8 @@ ** |/ ** \* */ - - package scala.collection -import generic._ - /** A default map which implements the `+` and `-` methods of maps. * * Instances that inherit from `DefaultMap[A, B]` still have to define: @@ -27,7 +23,7 @@ import generic._ * @since 2.8 */ trait DefaultMap[A, +B] extends Map[A, B] { self => - + /** A default implementation which creates a new immutable map. */ override def +[B1 >: B](kv: (A, B1)): Map[A, B1] = { diff --git a/src/library/scala/collection/GenIterableLike.scala b/src/library/scala/collection/GenIterableLike.scala index 2ba9a7283d..ceb97707e1 100644 --- a/src/library/scala/collection/GenIterableLike.scala +++ b/src/library/scala/collection/GenIterableLike.scala @@ -8,7 +8,7 @@ package scala.collection -import generic.{ CanBuildFrom => CBF, _ } +import generic.{ CanBuildFrom => CBF } /** A template trait for all iterable collections which may possibly * have their operations implemented in parallel. diff --git a/src/library/scala/collection/GenIterableView.scala b/src/library/scala/collection/GenIterableView.scala index ca0332e9ad..5ab48efdf3 100644 --- a/src/library/scala/collection/GenIterableView.scala +++ b/src/library/scala/collection/GenIterableView.scala @@ -8,11 +8,4 @@ package scala.collection - -import generic._ - - - trait GenIterableView[+A, +Coll] extends GenIterableViewLike[A, Coll, GenIterableView[A, Coll]] { } - - diff --git a/src/library/scala/collection/GenIterableViewLike.scala b/src/library/scala/collection/GenIterableViewLike.scala index 4e4ceb4cea..e8d264cdd4 100644 --- a/src/library/scala/collection/GenIterableViewLike.scala +++ b/src/library/scala/collection/GenIterableViewLike.scala @@ -8,13 +8,6 @@ package scala.collection - - -import generic._ -import TraversableView.NoBuilder - - - trait GenIterableViewLike[+A, +Coll, +This <: GenIterableView[A, Coll] with GenIterableViewLike[A, Coll, This]] diff --git a/src/library/scala/collection/GenSeqView.scala b/src/library/scala/collection/GenSeqView.scala index 92c8b779e9..423f8e305e 100644 --- a/src/library/scala/collection/GenSeqView.scala +++ b/src/library/scala/collection/GenSeqView.scala @@ -8,11 +8,4 @@ package scala.collection - -import generic._ - - - trait GenSeqView[+A, +Coll] extends GenSeqViewLike[A, Coll, GenSeqView[A, Coll]] { } - - diff --git a/src/library/scala/collection/GenTraversableOnce.scala b/src/library/scala/collection/GenTraversableOnce.scala index 093db2a972..afaced4264 100644 --- a/src/library/scala/collection/GenTraversableOnce.scala +++ b/src/library/scala/collection/GenTraversableOnce.scala @@ -261,11 +261,12 @@ trait GenTraversableOnce[+A] extends Any { * @tparam B the type of accumulated results * @param z the initial value for the accumulated result of the partition - this * will typically be the neutral element for the `seqop` operator (e.g. - * `Nil` for list concatenation or `0` for summation) + * `Nil` for list concatenation or `0` for summation) and may be evaluated + * more than once * @param seqop an operator used to accumulate results within a partition * @param combop an associative operator used to combine results from different partitions */ - def aggregate[B](z: B)(seqop: (B, A) => B, combop: (B, B) => B): B + def aggregate[B](z: =>B)(seqop: (B, A) => B, combop: (B, B) => B): B /** Applies a binary operator to all elements of this $coll, going right to left. * $willNotTerminateInf diff --git a/src/library/scala/collection/GenTraversableView.scala b/src/library/scala/collection/GenTraversableView.scala index cceb06882e..1d98eff8c1 100644 --- a/src/library/scala/collection/GenTraversableView.scala +++ b/src/library/scala/collection/GenTraversableView.scala @@ -8,11 +8,4 @@ package scala.collection - -import generic._ - - - trait GenTraversableView[+A, +Coll] extends GenTraversableViewLike[A, Coll, GenTraversableView[A, Coll]] { } - - diff --git a/src/library/scala/collection/GenTraversableViewLike.scala b/src/library/scala/collection/GenTraversableViewLike.scala index 77fe0802bf..8c9607663b 100644 --- a/src/library/scala/collection/GenTraversableViewLike.scala +++ b/src/library/scala/collection/GenTraversableViewLike.scala @@ -11,8 +11,6 @@ package scala.collection import generic._ import mutable.{ Builder, ArrayBuffer } -import TraversableView.NoBuilder - trait GenTraversableViewLike[+A, +Coll, diff --git a/src/library/scala/collection/IndexedSeq.scala b/src/library/scala/collection/IndexedSeq.scala index 63e5adf428..0b6e640537 100644 --- a/src/library/scala/collection/IndexedSeq.scala +++ b/src/library/scala/collection/IndexedSeq.scala @@ -6,8 +6,6 @@ ** |/ ** \* */ - - package scala.collection import generic._ @@ -38,4 +36,3 @@ object IndexedSeq extends IndexedSeqFactory[IndexedSeq] { implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, IndexedSeq[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] } - diff --git a/src/library/scala/collection/IndexedSeqLike.scala b/src/library/scala/collection/IndexedSeqLike.scala index 9d0e9cbaea..1d8e2b1583 100644 --- a/src/library/scala/collection/IndexedSeqLike.scala +++ b/src/library/scala/collection/IndexedSeqLike.scala @@ -8,7 +8,6 @@ package scala.collection -import generic._ import mutable.ArrayBuffer import scala.annotation.tailrec @@ -53,7 +52,6 @@ trait IndexedSeqLike[+A, +Repr] extends Any with SeqLike[A, Repr] { // pre: start >= 0, end <= self.length @SerialVersionUID(1756321872811029277L) protected class Elements(start: Int, end: Int) extends AbstractIterator[A] with BufferedIterator[A] with Serializable { - private def initialSize = if (end <= start) 0 else end - start private var index = start private def available = (end - index) max 0 diff --git a/src/library/scala/collection/Iterable.scala b/src/library/scala/collection/Iterable.scala index 5b73d720a8..09c9ce122c 100644 --- a/src/library/scala/collection/Iterable.scala +++ b/src/library/scala/collection/Iterable.scala @@ -11,7 +11,6 @@ package scala.collection import generic._ -import scala.util.control.Breaks._ import mutable.Builder /** A base trait for iterable collections. diff --git a/src/library/scala/collection/IterableProxy.scala b/src/library/scala/collection/IterableProxy.scala index 2d041928cc..ddb2502965 100644 --- a/src/library/scala/collection/IterableProxy.scala +++ b/src/library/scala/collection/IterableProxy.scala @@ -8,8 +8,6 @@ package scala.collection -import generic._ - /** This trait implements a proxy for iterable objects. It forwards all calls * to a different iterable object. * diff --git a/src/library/scala/collection/IterableViewLike.scala b/src/library/scala/collection/IterableViewLike.scala index 3a81a3422f..b195ae4bc7 100644 --- a/src/library/scala/collection/IterableViewLike.scala +++ b/src/library/scala/collection/IterableViewLike.scala @@ -9,7 +9,6 @@ package scala.collection import generic._ -import TraversableView.NoBuilder import immutable.Stream import scala.language.implicitConversions diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala index cbf8cc4931..d7dc202fad 100644 --- a/src/library/scala/collection/Iterator.scala +++ b/src/library/scala/collection/Iterator.scala @@ -562,7 +562,6 @@ trait Iterator[+A] extends TraversableOnce[A] { * handling of structural calls. It's not what's intended here. */ class Leading extends AbstractIterator[A] { - private var isDone = false val lookahead = new mutable.Queue[A] def advance() = { self.hasNext && p(self.head) && { @@ -572,7 +571,6 @@ trait Iterator[+A] extends TraversableOnce[A] { } def finish() = { while (advance()) () - isDone = true } def hasNext = lookahead.nonEmpty || advance() def next() = { diff --git a/src/library/scala/collection/JavaConversions.scala b/src/library/scala/collection/JavaConversions.scala index 59d4259c70..7ff29650fa 100644 --- a/src/library/scala/collection/JavaConversions.scala +++ b/src/library/scala/collection/JavaConversions.scala @@ -8,7 +8,6 @@ package scala.collection -import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } import convert._ /** A collection of implicit conversions supporting interoperability between @@ -91,42 +90,6 @@ object JavaConversions extends WrapAsScala with WrapAsJava { @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val MutableSeqWrapper = Wrappers.MutableSeqWrapper @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val MutableSetWrapper = Wrappers.MutableSetWrapper @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val SeqWrapper = Wrappers.SeqWrapper - - // Note to implementors: the cavalcade of deprecated methods herein should - // serve as a warning to any who follow: don't overload implicit methods. - - @deprecated("use bufferAsJavaList instead", "2.9.0") - def asJavaList[A](b : mutable.Buffer[A]): ju.List[A] = bufferAsJavaList[A](b) - - @deprecated("use mutableSeqAsJavaList instead", "2.9.0") - def asJavaList[A](b : mutable.Seq[A]): ju.List[A] = mutableSeqAsJavaList[A](b) - - @deprecated("use seqAsJavaList instead", "2.9.0") - def asJavaList[A](b : Seq[A]): ju.List[A] = seqAsJavaList[A](b) - - @deprecated("use mutableSetAsJavaSet instead", "2.9.0") - def asJavaSet[A](s : mutable.Set[A]): ju.Set[A] = mutableSetAsJavaSet[A](s) - - @deprecated("use setAsJavaSet instead", "2.9.0") - def asJavaSet[A](s: Set[A]): ju.Set[A] = setAsJavaSet[A](s) - - @deprecated("use mutableMapAsJavaMap instead", "2.9.0") - def asJavaMap[A, B](m : mutable.Map[A, B]): ju.Map[A, B] = mutableMapAsJavaMap[A, B](m) - - @deprecated("use mapAsJavaMap instead", "2.9.0") - def asJavaMap[A, B](m : Map[A, B]): ju.Map[A, B] = mapAsJavaMap[A, B](m) - - @deprecated("use iterableAsScalaIterable instead", "2.9.0") - def asScalaIterable[A](i : jl.Iterable[A]): Iterable[A] = iterableAsScalaIterable[A](i) - - @deprecated("use collectionAsScalaIterable instead", "2.9.0") - def asScalaIterable[A](i : ju.Collection[A]): Iterable[A] = collectionAsScalaIterable[A](i) - - @deprecated("use mapAsScalaMap instead", "2.9.0") - def asScalaMap[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = mapAsScalaMap[A, B](m) - - @deprecated("use propertiesAsScalaMap instead", "2.9.0") - def asScalaMap(p: ju.Properties): mutable.Map[String, String] = propertiesAsScalaMap(p) } diff --git a/src/library/scala/collection/JavaConverters.scala b/src/library/scala/collection/JavaConverters.scala index ab3ac8925c..439991708e 100755 --- a/src/library/scala/collection/JavaConverters.scala +++ b/src/library/scala/collection/JavaConverters.scala @@ -8,14 +8,12 @@ package scala.collection -import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } import convert._ // TODO: I cleaned all this documentation up in JavaConversions, but the // documentation in here is basically the pre-cleaned-up version with minor // additions. Would be nice to have in one place. - /** A collection of decorators that allow converting between * Scala and Java collections using `asScala` and `asJava` methods. * @@ -67,37 +65,4 @@ object JavaConverters extends DecorateAsJava with DecorateAsScala { type AsJavaEnumeration[A] = Decorators.AsJavaEnumeration[A] @deprecated("Don't access these decorators directly.", "2.10.0") type AsJavaDictionary[A, B] = Decorators.AsJavaDictionary[A, B] - - @deprecated("Use bufferAsJavaListConverter instead", "2.9.0") - def asJavaListConverter[A](b : mutable.Buffer[A]): AsJava[ju.List[A]] = bufferAsJavaListConverter(b) - - @deprecated("Use mutableSeqAsJavaListConverter instead", "2.9.0") - def asJavaListConverter[A](b : mutable.Seq[A]): AsJava[ju.List[A]] = mutableSeqAsJavaListConverter(b) - - @deprecated("Use seqAsJavaListConverter instead", "2.9.0") - def asJavaListConverter[A](b : Seq[A]): AsJava[ju.List[A]] = seqAsJavaListConverter(b) - - @deprecated("Use mutableSetAsJavaSetConverter instead", "2.9.0") - def asJavaSetConverter[A](s : mutable.Set[A]): AsJava[ju.Set[A]] = mutableSetAsJavaSetConverter(s) - - @deprecated("Use setAsJavaSetConverter instead", "2.9.0") - def asJavaSetConverter[A](s : Set[A]): AsJava[ju.Set[A]] = setAsJavaSetConverter(s) - - @deprecated("use mutableMapAsJavaMapConverter instead", "2.9.0") - def asJavaMapConverter[A, B](m : mutable.Map[A, B]): AsJava[ju.Map[A, B]] = mutableMapAsJavaMapConverter(m) - - @deprecated("Use mapAsJavaMapConverter instead", "2.9.0") - def asJavaMapConverter[A, B](m : Map[A, B]): AsJava[ju.Map[A, B]] = mapAsJavaMapConverter(m) - - @deprecated("Use iterableAsScalaIterableConverter instead", "2.9.0") - def asScalaIterableConverter[A](i : jl.Iterable[A]): AsScala[Iterable[A]] = iterableAsScalaIterableConverter(i) - - @deprecated("Use collectionAsScalaIterableConverter instead", "2.9.0") - def asScalaIterableConverter[A](i : ju.Collection[A]): AsScala[Iterable[A]] = collectionAsScalaIterableConverter(i) - - @deprecated("Use mapAsScalaMapConverter instead", "2.9.0") - def asScalaMapConverter[A, B](m : ju.Map[A, B]): AsScala[mutable.Map[A, B]] = mapAsScalaMapConverter(m) - - @deprecated("Use propertiesAsScalaMapConverter instead", "2.9.0") - def asScalaMapConverter(p: ju.Properties): AsScala[mutable.Map[String, String]] = propertiesAsScalaMapConverter(p) } diff --git a/src/library/scala/collection/LinearSeqLike.scala b/src/library/scala/collection/LinearSeqLike.scala index 78108a9c0f..2a824bcff3 100644 --- a/src/library/scala/collection/LinearSeqLike.scala +++ b/src/library/scala/collection/LinearSeqLike.scala @@ -6,13 +6,9 @@ ** |/ ** \* */ - package scala.collection -import generic._ -import mutable.ListBuffer import immutable.List -import scala.util.control.Breaks._ import scala.annotation.tailrec /** A template trait for linear sequences of type `LinearSeq[A]`. diff --git a/src/library/scala/collection/LinearSeqOptimized.scala b/src/library/scala/collection/LinearSeqOptimized.scala index 0f0a405a85..f71fd227cd 100755 --- a/src/library/scala/collection/LinearSeqOptimized.scala +++ b/src/library/scala/collection/LinearSeqOptimized.scala @@ -8,10 +8,8 @@ package scala.collection -import generic._ import mutable.ListBuffer import immutable.List -import scala.util.control.Breaks._ /** A template trait for linear sequences of type `LinearSeq[A]` which optimizes * the implementation of several methods under the assumption of fast linear access. @@ -83,7 +81,7 @@ trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends Linea } override /*SeqLike*/ - def contains(elem: Any): Boolean = { + def contains[A1 >: A](elem: A1): Boolean = { var these = this while (!these.isEmpty) { if (these.head == elem) return true @@ -91,7 +89,7 @@ trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends Linea } false } - + override /*IterableLike*/ def find(p: A => Boolean): Option[A] = { var these = this @@ -112,7 +110,7 @@ trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends Linea } acc } - + override /*IterableLike*/ def foldRight[B](z: B)(f: (A, B) => B): B = if (this.isEmpty) z diff --git a/src/library/scala/collection/MapProxyLike.scala b/src/library/scala/collection/MapProxyLike.scala index 44b39f65da..ad09f7b970 100644 --- a/src/library/scala/collection/MapProxyLike.scala +++ b/src/library/scala/collection/MapProxyLike.scala @@ -8,8 +8,6 @@ package scala.collection -import generic._ - // Methods could be printed by cat MapLike.scala | egrep '^ (override )?def' /** This trait implements a proxy for Map objects. It forwards diff --git a/src/library/scala/collection/Searching.scala b/src/library/scala/collection/Searching.scala new file mode 100644 index 0000000000..33e50365ee --- /dev/null +++ b/src/library/scala/collection/Searching.scala @@ -0,0 +1,116 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2012, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.collection + +import scala.annotation.tailrec +import scala.collection.generic.IsSeqLike +import scala.math.Ordering + +/** A collection of wrappers that provide sequence classes with search functionality. + * + * Example usage: + * {{{ + * import scala.collection.Searching._ + * val l = List(1, 2, 3, 4, 5) + * l.search(3) + * // == Found(2) + * }}} + */ +object Searching { + sealed abstract class SearchResult { + def insertionPoint: Int + } + + case class Found(foundIndex: Int) extends SearchResult { + override def insertionPoint = foundIndex + } + case class InsertionPoint(insertionPoint: Int) extends SearchResult + + class SearchImpl[A, Repr](val coll: SeqLike[A, Repr]) { + /** Search the sorted sequence for a specific element. If the sequence is an + * `IndexedSeq`, a binary search is used. Otherwise, a linear search is used. + * + * The sequence should be sorted with the same `Ordering` before calling; otherwise, + * the results are undefined. + * + * @see [[scala.collection.IndexedSeq]] + * @see [[scala.math.Ordering]] + * @see [[scala.collection.SeqLike]], method `sorted` + * + * @param elem the element to find. + * @param ord the ordering to be used to compare elements. + * + * @return a `Found` value containing the index corresponding to the element in the + * sequence, or the `InsertionPoint` where the element would be inserted if + * the element is not in the sequence. + */ + final def search[B >: A](elem: B)(implicit ord: Ordering[B]): SearchResult = + coll match { + case _: IndexedSeq[A] => binarySearch(elem, -1, coll.length)(ord) + case _ => linearSearch(coll.view, elem, 0)(ord) + } + + /** Search within an interval in the sorted sequence for a specific element. If the + * sequence is an IndexedSeq, a binary search is used. Otherwise, a linear search + * is used. + * + * The sequence should be sorted with the same `Ordering` before calling; otherwise, + * the results are undefined. + * + * @see [[scala.collection.IndexedSeq]] + * @see [[scala.math.Ordering]] + * @see [[scala.collection.SeqLike]], method `sorted` + * + * @param elem the element to find. + * @param from the index where the search starts. + * @param to the index following where the search ends. + * @param ord the ordering to be used to compare elements. + * + * @return a `Found` value containing the index corresponding to the element in the + * sequence, or the `InsertionPoint` where the element would be inserted if + * the element is not in the sequence. + */ + final def search[B >: A](elem: B, from: Int, to: Int) + (implicit ord: Ordering[B]): SearchResult = + coll match { + case _: IndexedSeq[A] => binarySearch(elem, from-1, to)(ord) + case _ => linearSearch(coll.view(from, to), elem, from)(ord) + } + + @tailrec + private def binarySearch[B >: A](elem: B, from: Int, to: Int) + (implicit ord: Ordering[B]): SearchResult = { + if ((to-from) == 1) InsertionPoint(from) else { + val idx = from+(to-from)/2 + math.signum(ord.compare(elem, coll(idx))) match { + case -1 => binarySearch(elem, from, idx)(ord) + case 1 => binarySearch(elem, idx, to)(ord) + case _ => Found(idx) + } + } + } + + private def linearSearch[B >: A](c: SeqView[A, Repr], elem: B, offset: Int) + (implicit ord: Ordering[B]): SearchResult = { + var idx = offset + val it = c.iterator + while (it.hasNext) { + val cur = it.next() + if (ord.equiv(elem, cur)) return Found(idx) + else if (ord.lt(elem, cur)) return InsertionPoint(idx-1) + idx += 1 + } + InsertionPoint(idx) + } + + } + + implicit def search[Repr, A](coll: Repr) + (implicit fr: IsSeqLike[Repr]): SearchImpl[fr.A, Repr] = new SearchImpl(fr.conversion(coll)) +} diff --git a/src/library/scala/collection/SeqLike.scala b/src/library/scala/collection/SeqLike.scala index 6871a3cb73..603e0b6497 100644 --- a/src/library/scala/collection/SeqLike.scala +++ b/src/library/scala/collection/SeqLike.scala @@ -103,7 +103,7 @@ trait SeqLike[+A, +Repr] extends Any with IterableLike[A, Repr] with GenSeqLike[ def segmentLength(p: A => Boolean, from: Int): Int = { var i = 0 - var it = iterator.drop(from) + val it = iterator.drop(from) while (it.hasNext && p(it.next())) i += 1 i @@ -111,7 +111,7 @@ trait SeqLike[+A, +Repr] extends Any with IterableLike[A, Repr] with GenSeqLike[ def indexWhere(p: A => Boolean, from: Int): Int = { var i = from - var it = iterator.drop(from) + val it = iterator.drop(from) while (it.hasNext) { if (p(it.next())) return i else i += 1 @@ -177,10 +177,10 @@ trait SeqLike[+A, +Repr] extends Any with IterableLike[A, Repr] with GenSeqLike[ result } private def swap(i: Int, j: Int) { - var tmpI = idxs(i) + val tmpI = idxs(i) idxs(i) = idxs(j) idxs(j) = tmpI - var tmpE = elms(i) + val tmpE = elms(i) elms(i) = elms(j) elms(j) = tmpE } @@ -386,7 +386,7 @@ trait SeqLike[+A, +Repr] extends Any with IterableLike[A, Repr] with GenSeqLike[ * @return `true` if this $coll has an element that is equal (as * determined by `==`) to `elem`, `false` otherwise. */ - def contains(elem: Any): Boolean = exists (_ == elem) + def contains[A1 >: A](elem: A1): Boolean = exists (_ == elem) /** Produces a new sequence which contains all elements of this $coll and also all elements of * a given sequence. `xs union ys` is equivalent to `xs ++ ys`. @@ -776,7 +776,7 @@ object SeqLike { val iter = S.iterator.drop(m0) val Wopt = kmpOptimizeWord(W, n0, n1, true) val T = kmpJumpTable(Wopt, n1-n0) - var cache = new Array[AnyRef](n1-n0) // Ring buffer--need a quick way to do a look-behind + val cache = new Array[AnyRef](n1-n0) // Ring buffer--need a quick way to do a look-behind var largest = 0 var i, m = 0 var answer = -1 diff --git a/src/library/scala/collection/SeqProxyLike.scala b/src/library/scala/collection/SeqProxyLike.scala index 5e8030d1e4..ee88ee3da3 100644 --- a/src/library/scala/collection/SeqProxyLike.scala +++ b/src/library/scala/collection/SeqProxyLike.scala @@ -50,7 +50,7 @@ trait SeqProxyLike[+A, +Repr <: SeqLike[A, Repr] with Seq[A]] extends SeqLike[A, override def lastIndexOfSlice[B >: A](that: GenSeq[B]): Int = self.lastIndexOfSlice(that) override def lastIndexOfSlice[B >: A](that: GenSeq[B], end: Int): Int = self.lastIndexOfSlice(that, end) override def containsSlice[B](that: GenSeq[B]): Boolean = self.indexOfSlice(that) != -1 - override def contains(elem: Any): Boolean = self.contains(elem) + override def contains[A1 >: A](elem: A1): Boolean = self.contains(elem) override def union[B >: A, That](that: GenSeq[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = self.union(that)(bf) override def diff[B >: A](that: GenSeq[B]): Repr = self.diff(that) override def intersect[B >: A](that: GenSeq[B]): Repr = self.intersect(that) diff --git a/src/library/scala/collection/SeqViewLike.scala b/src/library/scala/collection/SeqViewLike.scala index 5f2bf902b1..27536791a2 100644 --- a/src/library/scala/collection/SeqViewLike.scala +++ b/src/library/scala/collection/SeqViewLike.scala @@ -10,7 +10,6 @@ package scala.collection import generic._ import Seq.fill -import TraversableView.NoBuilder /** A template trait for non-strict views of sequences. * $seqViewInfo diff --git a/src/library/scala/collection/Sequentializable.scala.disabled b/src/library/scala/collection/Sequentializable.scala.disabled deleted file mode 100644 index df457671a6..0000000000 --- a/src/library/scala/collection/Sequentializable.scala.disabled +++ /dev/null @@ -1,10 +0,0 @@ -package scala.collection - - - - -trait Sequentializable[+T, +Repr] { - - def seq: Repr - -} diff --git a/src/library/scala/collection/SetProxyLike.scala b/src/library/scala/collection/SetProxyLike.scala index 5196f39917..265d1c4806 100644 --- a/src/library/scala/collection/SetProxyLike.scala +++ b/src/library/scala/collection/SetProxyLike.scala @@ -6,11 +6,8 @@ ** |/ ** \* */ - package scala.collection -import generic._ - // Methods could be printed by cat SetLike.scala | egrep '^ (override )?def' /** This trait implements a proxy for sets. It forwards diff --git a/src/library/scala/collection/Traversable.scala b/src/library/scala/collection/Traversable.scala index 36ef230a42..4ca2095f4c 100644 --- a/src/library/scala/collection/Traversable.scala +++ b/src/library/scala/collection/Traversable.scala @@ -6,12 +6,10 @@ ** |/ ** \* */ - - package scala.collection import generic._ -import mutable.{Builder, Buffer, ArrayBuffer, ListBuffer} +import mutable.Builder import scala.util.control.Breaks /** A trait for traversable collections. diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala index 5f193eb211..c1a68b6b16 100644 --- a/src/library/scala/collection/TraversableLike.scala +++ b/src/library/scala/collection/TraversableLike.scala @@ -86,7 +86,7 @@ trait TraversableLike[+A, +Repr] extends Any def repr: Repr = this.asInstanceOf[Repr] final def isTraversableAgain: Boolean = true - + /** The underlying collection seen as an instance of `$Coll`. * By default this is implemented as the current collection object itself, * but this can be overridden. @@ -174,7 +174,7 @@ trait TraversableLike[+A, +Repr] extends Any * * @usecase def ++:[B](that: TraversableOnce[B]): $Coll[B] * @inheritdoc - * + * * Example: * {{{ * scala> val x = List(1) @@ -275,7 +275,7 @@ trait TraversableLike[+A, +Repr] extends Any def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = { val b = bf(repr) - for (x <- this) if (pf.isDefinedAt(x)) b += pf(x) + foreach(pf.runWith(b += _)) b.result } diff --git a/src/library/scala/collection/TraversableOnce.scala b/src/library/scala/collection/TraversableOnce.scala index d53d000e90..82cf1d1198 100644 --- a/src/library/scala/collection/TraversableOnce.scala +++ b/src/library/scala/collection/TraversableOnce.scala @@ -128,10 +128,8 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] { * @example `Seq("a", 1, 5L).collectFirst({ case x: Int => x*10 }) = Some(10)` */ def collectFirst[B](pf: PartialFunction[A, B]): Option[B] = { - for (x <- self.toIterator) { // make sure to use an iterator or `seq` - if (pf isDefinedAt x) - return Some(pf(x)) - } + // make sure to use an iterator or `seq` + self.toIterator.foreach(pf.runWith(b => return Some(b))) None } @@ -184,7 +182,7 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] { def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op) - def aggregate[B](z: B)(seqop: (B, A) => B, combop: (B, B) => B): B = foldLeft(z)(seqop) + def aggregate[B](z: =>B)(seqop: (B, A) => B, combop: (B, B) => B): B = foldLeft(z)(seqop) def sum[B >: A](implicit num: Numeric[B]): B = foldLeft(num.zero)(num.plus) diff --git a/src/library/scala/collection/TraversableView.scala b/src/library/scala/collection/TraversableView.scala index cce6b72257..af219084b8 100644 --- a/src/library/scala/collection/TraversableView.scala +++ b/src/library/scala/collection/TraversableView.scala @@ -10,7 +10,6 @@ package scala.collection import generic._ import mutable.Builder -import TraversableView.NoBuilder /** A base trait for non-strict views of traversable collections. * $traversableViewInfo diff --git a/src/library/scala/collection/TraversableViewLike.scala b/src/library/scala/collection/TraversableViewLike.scala index 14f865c2f0..36f6210ef4 100644 --- a/src/library/scala/collection/TraversableViewLike.scala +++ b/src/library/scala/collection/TraversableViewLike.scala @@ -10,7 +10,6 @@ package scala.collection import generic._ import mutable.{ Builder, ArrayBuffer } -import TraversableView.NoBuilder import scala.annotation.migration import scala.language.implicitConversions @@ -59,7 +58,7 @@ trait ViewMkString[+A] { * $viewInfo * * All views for traversable collections are defined by creating a new `foreach` method. - * + * * @author Martin Odersky * @version 2.8 * @since 2.8 @@ -162,7 +161,7 @@ trait TraversableViewLike[+A, // if (b.isInstanceOf[NoBuilder[_]]) newFlatMapped(f).asInstanceOf[That] // else super.flatMap[B, That](f)(bf) } - override def flatten[B](implicit asTraversable: A => /*<:<!!!*/ GenTraversableOnce[B]) = + override def flatten[B](implicit asTraversable: A => /*<:<!!!*/ GenTraversableOnce[B]) = newFlatMapped(asTraversable) private[this] implicit def asThis(xs: Transformed[A]): This = xs.asInstanceOf[This] diff --git a/src/library/scala/collection/concurrent/TrieMap.scala b/src/library/scala/collection/concurrent/TrieMap.scala index 6c11c5bcb5..14b475dd1f 100644 --- a/src/library/scala/collection/concurrent/TrieMap.scala +++ b/src/library/scala/collection/concurrent/TrieMap.scala @@ -545,7 +545,7 @@ private[collection] final class CNode[K, V](val bitmap: Int, val array: Array[Ba // removed (those existing when the op began) // - if there are only null-i-nodes below, returns null def toCompressed(ct: TrieMap[K, V], lev: Int, gen: Gen) = { - var bmp = bitmap + val bmp = bitmap var i = 0 val arr = array val tmparray = new Array[BasicNode](arr.length) @@ -920,8 +920,8 @@ object TrieMap extends MutableMapFactory[TrieMap] { private[collection] class TrieMapIterator[K, V](var level: Int, private var ct: TrieMap[K, V], mustInit: Boolean = true) extends Iterator[(K, V)] { - private var stack = new Array[Array[BasicNode]](7) - private var stackpos = new Array[Int](7) + private val stack = new Array[Array[BasicNode]](7) + private val stackpos = new Array[Int](7) private var depth = -1 private var subiter: Iterator[(K, V)] = null private var current: KVNode[K, V] = null diff --git a/src/library/scala/collection/convert/Decorators.scala b/src/library/scala/collection/convert/Decorators.scala index e2c46c1e4f..f004e4712b 100644 --- a/src/library/scala/collection/convert/Decorators.scala +++ b/src/library/scala/collection/convert/Decorators.scala @@ -9,7 +9,7 @@ package scala.collection package convert -import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } +import java.{ util => ju } private[collection] trait Decorators { /** Generic class containing the `asJava` converter method */ diff --git a/src/library/scala/collection/generic/GenTraversableFactory.scala b/src/library/scala/collection/generic/GenTraversableFactory.scala index a43862abaf..b36dd3ccaf 100644 --- a/src/library/scala/collection/generic/GenTraversableFactory.scala +++ b/src/library/scala/collection/generic/GenTraversableFactory.scala @@ -249,4 +249,3 @@ extends GenericCompanion[CC] { b.result } } - diff --git a/src/library/scala/collection/generic/IsSeqLike.scala b/src/library/scala/collection/generic/IsSeqLike.scala new file mode 100644 index 0000000000..9467510a2c --- /dev/null +++ b/src/library/scala/collection/generic/IsSeqLike.scala @@ -0,0 +1,57 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2012, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.collection +package generic + +/** Type class witnessing that a collection representation type `Repr` has + * elements of type `A` and has a conversion to `SeqLike[A, Repr]`. + * + * This type enables simple enrichment of `Seq`s with extension methods which + * can make full use of the mechanics of the Scala collections framework in + * their implementation. + * + * Example usage: + * {{{ + * class FilterMapImpl[A, Repr](val r: SeqLike[A, Repr]) { + * final def filterMap[B, That](f: A => Option[B])(implicit cbf: CanBuildFrom[Repr, B, That]): That = + * r.flatMap(f(_)) + * } + * implicit def filterMap[Repr, A](r: Repr)(implicit fr: IsSeqLike[Repr]): FilterMapImpl[fr.A,Repr] = + * new FilterMapImpl(fr.conversion(r)) + * + * val l = List(1, 2, 3, 4, 5) + * List(1, 2, 3, 4, 5) filterMap (i => if(i % 2 == 0) Some(i) else None) + * // == List(2, 4) + * }}} + * + * @see [[scala.collection.Seq]] + * @see [[scala.collection.generic.IsTraversableLike]] + */ +trait IsSeqLike[Repr] { + /** The type of elements we can traverse over. */ + type A + /** A conversion from the representation type `Repr` to a `SeqLike[A,Repr]`. */ + val conversion: Repr => SeqLike[A, Repr] +} + +object IsSeqLike { + import language.higherKinds + + implicit val stringRepr: IsSeqLike[String] { type A = Char } = + new IsSeqLike[String] { + type A = Char + val conversion = implicitly[String => SeqLike[Char, String]] + } + + implicit def seqLikeRepr[C[_], A0](implicit conv: C[A0] => SeqLike[A0,C[A0]]): IsSeqLike[C[A0]] { type A = A0 } = + new IsSeqLike[C[A0]] { + type A = A0 + val conversion = conv + } +} diff --git a/src/library/scala/collection/generic/IterableForwarder.scala b/src/library/scala/collection/generic/IterableForwarder.scala index 90ebcace84..8feace3f8b 100644 --- a/src/library/scala/collection/generic/IterableForwarder.scala +++ b/src/library/scala/collection/generic/IterableForwarder.scala @@ -6,12 +6,9 @@ ** |/ ** \* */ - - package scala.collection.generic -import scala.collection._ -import scala.collection.mutable.Buffer +import scala.collection._ /** This trait implements a forwarder for iterable objects. It forwards * all calls to a different iterable object, except for diff --git a/src/library/scala/collection/generic/SeqForwarder.scala b/src/library/scala/collection/generic/SeqForwarder.scala index e8b15ec450..aafaffc159 100644 --- a/src/library/scala/collection/generic/SeqForwarder.scala +++ b/src/library/scala/collection/generic/SeqForwarder.scala @@ -50,7 +50,7 @@ trait SeqForwarder[+A] extends Seq[A] with IterableForwarder[A] { override def lastIndexOfSlice[B >: A](that: GenSeq[B]): Int = underlying lastIndexOfSlice that override def lastIndexOfSlice[B >: A](that: GenSeq[B], end: Int): Int = underlying.lastIndexOfSlice(that, end) override def containsSlice[B](that: GenSeq[B]): Boolean = underlying containsSlice that - override def contains(elem: Any): Boolean = underlying contains elem + override def contains[A1 >: A](elem: A1): Boolean = underlying contains elem override def corresponds[B](that: GenSeq[B])(p: (A,B) => Boolean): Boolean = underlying.corresponds(that)(p) override def indices: Range = underlying.indices } diff --git a/src/library/scala/collection/immutable/DefaultMap.scala b/src/library/scala/collection/immutable/DefaultMap.scala index 4a0503adfd..620baec9a8 100755 --- a/src/library/scala/collection/immutable/DefaultMap.scala +++ b/src/library/scala/collection/immutable/DefaultMap.scala @@ -6,13 +6,9 @@ ** |/ ** \* */ - - package scala.collection package immutable -import generic._ - /** A default map which implements the `+` and `-` * methods of maps. It does so using the default builder for * maps defined in the `Map` object. diff --git a/src/library/scala/collection/immutable/GenIterable.scala.disabled b/src/library/scala/collection/immutable/GenIterable.scala.disabled deleted file mode 100644 index d34f7fd856..0000000000 --- a/src/library/scala/collection/immutable/GenIterable.scala.disabled +++ /dev/null @@ -1,37 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.collection -package immutable - - -import generic._ -import mutable.Builder - - -/** A base trait for iterable collections that can be mutated. - * - * $possiblyparinfo - * - * $iterableInfo - */ -trait GenIterable[+A] extends GenTraversable[A] - with scala.collection.GenIterable[A] - with scala.collection.GenIterableLike[A, GenIterable[A]] -// with GenericTraversableTemplate[A, GenIterable] -{ - def seq: Iterable[A] - //override def companion: GenericCompanion[GenIterable] = GenIterable -} - - -// object GenIterable extends TraversableFactory[GenIterable] { -// implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, GenIterable[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] -// def newBuilder[A]: Builder[A, GenIterable[A]] = Iterable.newBuilder -// } - diff --git a/src/library/scala/collection/immutable/GenMap.scala.disabled b/src/library/scala/collection/immutable/GenMap.scala.disabled deleted file mode 100644 index 73557a4a66..0000000000 --- a/src/library/scala/collection/immutable/GenMap.scala.disabled +++ /dev/null @@ -1,36 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.collection -package immutable - -import generic._ - - -/** A base trait for maps that can be mutated. - * $possiblyparinfo - * $mapNote - * $mapTags - * @since 1.0 - * @author Matthias Zenger - */ -trait GenMap[A, +B] -extends GenIterable[(A, B)] - with scala.collection.GenMap[A, B] - with scala.collection.GenMapLike[A, B, GenMap[A, B]] -{ - def seq: Map[A, B] -} - - -// object GenMap extends MapFactory[GenMap] { -// def empty[A, B]: Map[A, B] = Map.empty - -// /** $mapCanBuildFromInfo */ -// implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), GenMap[A, B]] = new MapCanBuildFrom[A, B] -// } diff --git a/src/library/scala/collection/immutable/GenSeq.scala.disabled b/src/library/scala/collection/immutable/GenSeq.scala.disabled deleted file mode 100644 index 713529f3db..0000000000 --- a/src/library/scala/collection/immutable/GenSeq.scala.disabled +++ /dev/null @@ -1,49 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - - -package scala.collection -package immutable - - -import generic._ -import mutable.Builder - - -/** A subtrait of `collection.GenSeq` which represents sequences - * that can be mutated. - * - * $possiblyparinfo - * - * $seqInfo - * - * The class adds an `update` method to `collection.Seq`. - * - * @define Coll `mutable.Seq` - * @define coll mutable sequence - */ -trait GenSeq[+A] extends GenIterable[A] - with scala.collection.GenSeq[A] - with scala.collection.GenSeqLike[A, GenSeq[A]] -// with GenericTraversableTemplate[A, GenSeq] -{ - def seq: Seq[A] - //override def companion: GenericCompanion[GenSeq] = GenSeq -} - - -// object GenSeq extends SeqFactory[GenSeq] { -// implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, GenSeq[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] -// def newBuilder[A]: Builder[A, GenSeq[A]] = Seq.newBuilder -// } - - - - - diff --git a/src/library/scala/collection/immutable/GenSet.scala.disabled b/src/library/scala/collection/immutable/GenSet.scala.disabled deleted file mode 100644 index 56bd2738fd..0000000000 --- a/src/library/scala/collection/immutable/GenSet.scala.disabled +++ /dev/null @@ -1,43 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - - -package scala.collection -package immutable - - -import generic._ -import mutable.Builder - - -/** A generic trait for mutable sets. - * - * $possiblyparinfo - * $setNote - * $setTags - * - * @since 1.0 - * @author Matthias Zenger - * @define Coll `mutable.Set` - * @define coll mutable set - */ -trait GenSet[A] extends GenIterable[A] - with scala.collection.GenSet[A] - with scala.collection.GenSetLike[A, GenSet[A]] -// with GenericSetTemplate[A, GenSet] -{ - //override def companion: GenericCompanion[GenSet] = GenSet - def seq: Set[A] -} - - -// object GenSet extends TraversableFactory[GenSet] { -// implicit def canBuildFrom[A] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] -// def newBuilder[A] = Set.newBuilder -// } diff --git a/src/library/scala/collection/immutable/GenTraversable.scala.disabled b/src/library/scala/collection/immutable/GenTraversable.scala.disabled deleted file mode 100644 index e5b609f9ed..0000000000 --- a/src/library/scala/collection/immutable/GenTraversable.scala.disabled +++ /dev/null @@ -1,41 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - - -package scala.collection -package immutable - - -import generic._ -import mutable.Builder - - -/** A trait for traversable collections that can be mutated. - * - * $possiblyparinfo - * - * $traversableInfo - * @define mutability mutable - */ -trait GenTraversable[+A] extends scala.collection.GenTraversable[A] - with scala.collection.GenTraversableLike[A, GenTraversable[A]] -// with GenericTraversableTemplate[A, GenTraversable] - with Mutable -{ - def seq: Traversable[A] - //override def companion: GenericCompanion[GenTraversable] = GenTraversable -} - - -// object GenTraversable extends TraversableFactory[GenTraversable] { -// implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, GenTraversable[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] -// def newBuilder[A]: Builder[A, GenTraversable[A]] = Traversable.newBuilder -// } - - diff --git a/src/library/scala/collection/immutable/HashMap.scala b/src/library/scala/collection/immutable/HashMap.scala index 84416a62d2..29267f22dc 100644 --- a/src/library/scala/collection/immutable/HashMap.scala +++ b/src/library/scala/collection/immutable/HashMap.scala @@ -471,9 +471,6 @@ time { mNew.iterator.foreach( p => ()) } // condition below is due to 2 things: // 1) no unsigned int compare on JVM // 2) 0 (no lsb) should always be greater in comparison - val a = thislsb - 1 - val b = thatlsb - 1 - if (unsignedCompare(thislsb - 1, thatlsb - 1)) { val m = thiselems(thisi) totalelems += m.size diff --git a/src/library/scala/collection/immutable/IndexedSeq.scala b/src/library/scala/collection/immutable/IndexedSeq.scala index bf4ba3a381..9316ff5e72 100644 --- a/src/library/scala/collection/immutable/IndexedSeq.scala +++ b/src/library/scala/collection/immutable/IndexedSeq.scala @@ -37,6 +37,7 @@ object IndexedSeq extends IndexedSeqFactory[IndexedSeq] { def apply(idx: Int) = buf.apply(idx) } def newBuilder[A]: Builder[A, IndexedSeq[A]] = Vector.newBuilder[A] + implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, IndexedSeq[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] } diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index 56e386ad67..aeaa479e2f 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -152,7 +152,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] * @usecase def mapConserve(f: A => A): List[A] * @inheritdoc */ - def mapConserve[B >: A <: AnyRef](f: A => B): List[B] = { + @inline final def mapConserve[B >: A <: AnyRef](f: A => B): List[B] = { @tailrec def loop(mapped: ListBuffer[B], unchanged: List[A], pending: List[A]): List[B] = if (pending.isEmpty) { @@ -257,7 +257,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] (b.toList, these) } - override def takeWhile(p: A => Boolean): List[A] = { + @inline final override def takeWhile(p: A => Boolean): List[A] = { val b = new ListBuffer[A] var these = this while (!these.isEmpty && p(these.head)) { @@ -267,7 +267,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] b.toList } - override def dropWhile(p: A => Boolean): List[A] = { + @inline final override def dropWhile(p: A => Boolean): List[A] = { @tailrec def loop(xs: List[A]): List[A] = if (xs.isEmpty || !p(xs.head)) xs @@ -276,7 +276,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] loop(this) } - override def span(p: A => Boolean): (List[A], List[A]) = { + @inline final override def span(p: A => Boolean): (List[A], List[A]) = { val b = new ListBuffer[A] var these = this while (!these.isEmpty && p(these.head)) { @@ -286,6 +286,16 @@ sealed abstract class List[+A] extends AbstractSeq[A] (b.toList, these) } + // Overridden with an implementation identical to the inherited one (at this time) + // solely so it can be finalized and thus inlinable. + @inline final override def foreach[U](f: A => U) { + var these = this + while (!these.isEmpty) { + f(these.head) + these = these.tail + } + } + override def reverse: List[A] = { var result: List[A] = Nil var these = this @@ -301,18 +311,6 @@ sealed abstract class List[+A] extends AbstractSeq[A] override def toStream : Stream[A] = if (isEmpty) Stream.Empty else new Stream.Cons(head, tail.toStream) - - @inline override final - def foreach[B](f: A => B) { - var these = this - while (!these.isEmpty) { - f(these.head) - these = these.tail - } - } - - @deprecated("use `distinct` instead", "2.8.0") - def removeDuplicates: List[A] = distinct } /** The empty list. @@ -381,12 +379,6 @@ final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extend current = list } } - - private def oldWriteObject(out: ObjectOutputStream) { - var xs: List[B] = this - while (!xs.isEmpty) { out.writeObject(xs.head); xs = xs.tail } - out.writeObject(ListSerializeEnd) - } } /** $factoryInfo @@ -394,9 +386,6 @@ final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extend * @define Coll `List` */ object List extends SeqFactory[List] { - - import scala.collection.{Iterable, Seq, IndexedSeq} - /** $genericCanBuildFromInfo */ implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, List[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] @@ -406,248 +395,6 @@ object List extends SeqFactory[List] { override def empty[A]: List[A] = Nil override def apply[A](xs: A*): List[A] = xs.toList - - /** Create a sorted list with element values `v,,>n+1,, = step(v,,n,,)` - * where `v,,0,, = start` and elements are in the range between `start` - * (inclusive) and `end` (exclusive). - * - * @param start the start value of the list - * @param end the end value of the list - * @param step the increment function of the list, which given `v,,n,,`, - * computes `v,,n+1,,`. Must be monotonically increasing - * or decreasing. - * @return the sorted list of all integers in range `[start;end)`. - */ - @deprecated("use `iterate` instead", "2.8.0") - def range(start: Int, end: Int, step: Int => Int): List[Int] = { - val up = step(start) > start - val down = step(start) < start - val b = new ListBuffer[Int] - var i = start - while ((!up || i < end) && (!down || i > end)) { - b += i - val next = step(i) - if (i == next) - throw new IllegalArgumentException("the step function did not make any progress on "+ i) - i = next - } - b.toList - } - - /** Create a list containing several copies of an element. - * - * @param n the length of the resulting list - * @param elem the element composing the resulting list - * @return a list composed of `n` elements all equal to `elem` - */ - @deprecated("use `fill` instead", "2.8.0") - def make[A](n: Int, elem: A): List[A] = { - val b = new ListBuffer[A] - var i = 0 - while (i < n) { - b += elem - i += 1 - } - b.toList - } - - /** Concatenate all the elements of a given list of lists. - * - * @param xss the list of lists that are to be concatenated - * @return the concatenation of all the lists - */ - @deprecated("use `xss.flatten` instead of `List.flatten(xss)`", "2.8.0") - def flatten[A](xss: List[List[A]]): List[A] = { - val b = new ListBuffer[A] - for (xs <- xss) { - var xc = xs - while (!xc.isEmpty) { - b += xc.head - xc = xc.tail - } - } - b.toList - } - - /** Transforms a list of pairs into a pair of lists. - * - * @param xs the list of pairs to unzip - * @return a pair of lists. - */ - @deprecated("use `xs.unzip` instead of `List.unzip(xs)`", "2.8.0") - def unzip[A,B](xs: List[(A,B)]): (List[A], List[B]) = { - val b1 = new ListBuffer[A] - val b2 = new ListBuffer[B] - var xc = xs - while (!xc.isEmpty) { - b1 += xc.head._1 - b2 += xc.head._2 - xc = xc.tail - } - (b1.toList, b2.toList) - } - - /** Transforms an iterable of pairs into a pair of lists. - * - * @param xs the iterable of pairs to unzip - * @return a pair of lists. - */ - @deprecated("use `xs.unzip` instead of `List.unzip(xs)`", "2.8.0") - def unzip[A,B](xs: Iterable[(A,B)]): (List[A], List[B]) = - xs.foldRight[(List[A], List[B])]((Nil, Nil)) { - case ((x, y), (xs, ys)) => (x :: xs, y :: ys) - } - - /** - * Returns the `Left` values in the given `Iterable` of `Either`s. - */ - @deprecated("use `xs collect { case Left(x: A) => x }` instead of `List.lefts(xs)`", "2.8.0") - def lefts[A, B](es: Iterable[Either[A, B]]) = - es.foldRight[List[A]](Nil)((e, as) => e match { - case Left(a) => a :: as - case Right(_) => as - }) - - /** - * Returns the `Right` values in the given `Iterable` of `Either`s. - */ - @deprecated("use `xs collect { case Right(x: B) => x }` instead of `List.rights(xs)`", "2.8.0") - def rights[A, B](es: Iterable[Either[A, B]]) = - es.foldRight[List[B]](Nil)((e, bs) => e match { - case Left(_) => bs - case Right(b) => b :: bs - }) - - /** Transforms an Iterable of Eithers into a pair of lists. - * - * @param es the iterable of Eithers to separate - * @return a pair of lists. - */ - @deprecated("use `(for (Left(x) <- es) yield x, for (Right(x) <- es) yield x)` instead", "2.8.0") - def separate[A,B](es: Iterable[Either[A, B]]): (List[A], List[B]) = - es.foldRight[(List[A], List[B])]((Nil, Nil)) { - case (Left(a), (lefts, rights)) => (a :: lefts, rights) - case (Right(b), (lefts, rights)) => (lefts, b :: rights) - } - - /** Converts an iterator to a list. - * - * @param it the iterator to convert - * @return a list that contains the elements returned by successive - * calls to `it.next` - */ - @deprecated("use `it.toList` instead of `List.toList(it)`", "2.8.0") - def fromIterator[A](it: Iterator[A]): List[A] = it.toList - - /** Converts an array into a list. - * - * @param arr the array to convert - * @return a list that contains the same elements than `arr` - * in the same order - */ - @deprecated("use `array.toList` instead of `List.fromArray(array)`", "2.8.0") - def fromArray[A](arr: Array[A]): List[A] = fromArray(arr, 0, arr.length) - - /** Converts a range of an array into a list. - * - * @param arr the array to convert - * @param start the first index to consider - * @param len the length of the range to convert - * @return a list that contains the same elements than `arr` - * in the same order - */ - @deprecated("use `array.view(start, end).toList` instead of `List.fromArray(array, start, end)`", "2.8.0") - def fromArray[A](arr: Array[A], start: Int, len: Int): List[A] = { - var res: List[A] = Nil - var i = start + len - while (i > start) { - i -= 1 - res = arr(i) :: res - } - res - } - - /** Returns the list resulting from applying the given function `f` - * to corresponding elements of the argument lists. - * - * @param f function to apply to each pair of elements. - * @return `[f(a,,0,,,b,,0,,), ..., f(a,,n,,,b,,n,,)]` if the lists are - * `[a,,0,,, ..., a,,k,,]`, `[b,,0,,, ..., b,,l,,]` and - * `n = min(k,l)` - */ - @deprecated("use `(xs, ys).zipped.map(f)` instead of `List.map2(xs, ys)(f)`", "2.8.0") - def map2[A,B,C](xs: List[A], ys: List[B])(f: (A, B) => C): List[C] = { - val b = new ListBuffer[C] - var xc = xs - var yc = ys - while (!xc.isEmpty && !yc.isEmpty) { - b += f(xc.head, yc.head) - xc = xc.tail - yc = yc.tail - } - b.toList - } - - /** Tests whether the given predicate `p` holds - * for all corresponding elements of the argument lists. - * - * @param f function to apply to each pair of elements. - * @return `(p(a<sub>0</sub>,b<sub>0</sub>) && - * ... && p(a<sub>n</sub>,b<sub>n</sub>))]` - * if the lists are `[a<sub>0</sub>, ..., a<sub>k</sub>]`; - * `[b<sub>0</sub>, ..., b<sub>l</sub>]` - * and `n = min(k,l)` - */ - @deprecated("use `(xs, ys).zipped.forall(f)` instead of `List.forall2(xs, ys)(f)`", "2.8.0") - def forall2[A,B](xs: List[A], ys: List[B])(f: (A, B) => Boolean): Boolean = { - var xc = xs - var yc = ys - while (!xc.isEmpty && !yc.isEmpty) { - if (!f(xc.head, yc.head)) return false - xc = xc.tail - yc = yc.tail - } - true - } - - /** Tests whether the given predicate `p` holds - * for some corresponding elements of the argument lists. - * - * @param f function to apply to each pair of elements. - * @return `n != 0 && (p(a<sub>0</sub>,b<sub>0</sub>) || - * ... || p(a<sub>n</sub>,b<sub>n</sub>))]` if the lists are - * `[a<sub>0</sub>, ..., a<sub>k</sub>]`, - * `[b<sub>0</sub>, ..., b<sub>l</sub>]` and - * `n = min(k,l)` - */ - @deprecated("use `(xs, ys).zipped.exists(f)` instead of `List.exists2(xs, ys)(f)`", "2.8.0") - def exists2[A,B](xs: List[A], ys: List[B])(f: (A, B) => Boolean): Boolean = { - var xc = xs - var yc = ys - while (!xc.isEmpty && !yc.isEmpty) { - if (f(xc.head, yc.head)) return true - xc = xc.tail - yc = yc.tail - } - false - } - - /** Transposes a list of lists. - * pre: All element lists have the same length. - * - * @param xss the list of lists - * @return the transposed list of lists - */ - @deprecated("use `xss.transpose` instead of `List.transpose(xss)`", "2.8.0") - def transpose[A](xss: List[List[A]]): List[List[A]] = { - val buf = new ListBuffer[List[A]] - var yss = xss - while (!yss.head.isEmpty) { - buf += (yss map (_.head)) - yss = (yss map (_.tail)) - } - buf.toList - } } /** Only used for list serialization */ diff --git a/src/library/scala/collection/immutable/LongMap.scala b/src/library/scala/collection/immutable/LongMap.scala index 2a2910439a..fab1b7f00b 100644 --- a/src/library/scala/collection/immutable/LongMap.scala +++ b/src/library/scala/collection/immutable/LongMap.scala @@ -77,8 +77,6 @@ object LongMap { } } -import LongMap._ - // Iterator over a non-empty LongMap. private[immutable] abstract class LongMapIterator[V, T](it: LongMap[V]) extends AbstractIterator[T] { diff --git a/src/library/scala/collection/immutable/NumericRange.scala b/src/library/scala/collection/immutable/NumericRange.scala index d3be299f89..195aeed281 100644 --- a/src/library/scala/collection/immutable/NumericRange.scala +++ b/src/library/scala/collection/immutable/NumericRange.scala @@ -6,12 +6,10 @@ ** |/ ** \* */ - package scala.collection package immutable import mutable.{ Builder, ListBuffer } -import generic._ /** `NumericRange` is a more generic version of the * `Range` class which works with arbitrary types. @@ -81,17 +79,6 @@ extends AbstractSeq[T] with IndexedSeq[T] with Serializable { // to guard against any (most likely illusory) performance drop. They should // be eliminated one way or another. - // Counts how many elements from the start meet the given test. - private def skipCount(p: T => Boolean): Int = { - var current = start - var counted = 0 - - while (counted < length && p(current)) { - counted += 1 - current += step - } - counted - } // Tests whether a number is within the endpoints, without testing // whether it is a member of the sequence (i.e. when step > 1.) private def isWithinBoundaries(elem: T) = !isEmpty && ( @@ -124,21 +111,21 @@ extends AbstractSeq[T] with IndexedSeq[T] with Serializable { if (idx < 0 || idx >= length) throw new IndexOutOfBoundsException(idx.toString) else locationAfterN(idx) } - + import NumericRange.defaultOrdering - + override def min[T1 >: T](implicit ord: Ordering[T1]): T = if (ord eq defaultOrdering(num)) { if (num.signum(step) > 0) start else last } else super.min(ord) - - override def max[T1 >: T](implicit ord: Ordering[T1]): T = + + override def max[T1 >: T](implicit ord: Ordering[T1]): T = if (ord eq defaultOrdering(num)) { if (num.signum(step) > 0) last else start } else super.max(ord) - + // Motivated by the desire for Double ranges with BigDecimal precision, // we need some way to map a Range and get another Range. This can't be // done in any fully general way because Ranges are not arbitrary @@ -182,12 +169,11 @@ extends AbstractSeq[T] with IndexedSeq[T] with Serializable { def containsTyped(x: T): Boolean = isWithinBoundaries(x) && (((x - start) % step) == zero) - override def contains(x: Any): Boolean = + override def contains[A1 >: T](x: A1): Boolean = try containsTyped(x.asInstanceOf[T]) catch { case _: ClassCastException => false } final override def sum[B >: T](implicit num: Numeric[B]): B = { - import num.Ops if (isEmpty) this.num fromInt 0 else if (numRangeElements == 1) head else ((this.num fromInt numRangeElements) * (head + last) / (this.num fromInt 2)) @@ -213,7 +199,7 @@ extends AbstractSeq[T] with IndexedSeq[T] with Serializable { /** A companion object for numeric ranges. */ object NumericRange { - + /** Calculates the number of elements in a range given start, end, step, and * whether or not it is inclusive. Throws an exception if step == 0 or * the number of elements exceeds the maximum Int. @@ -272,7 +258,7 @@ object NumericRange { new Exclusive(start, end, step) def inclusive[T](start: T, end: T, step: T)(implicit num: Integral[T]): Inclusive[T] = new Inclusive(start, end, step) - + private[collection] val defaultOrdering = Map[Numeric[_], Ordering[_]]( Numeric.BigIntIsIntegral -> Ordering.BigInt, Numeric.IntIsIntegral -> Ordering.Int, @@ -284,6 +270,6 @@ object NumericRange { Numeric.DoubleAsIfIntegral -> Ordering.Double, Numeric.BigDecimalAsIfIntegral -> Ordering.BigDecimal ) - + } diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala index 3b6ab81146..e1aba20fdb 100644 --- a/src/library/scala/collection/immutable/Range.scala +++ b/src/library/scala/collection/immutable/Range.scala @@ -78,6 +78,7 @@ extends scala.collection.AbstractSeq[Int] final val terminalElement = start + numRangeElements * step override def last = if (isEmpty) Nil.last else lastElement + override def head = if (isEmpty) Nil.head else start override def min[A1 >: Int](implicit ord: Ordering[A1]): Int = if (ord eq Ordering.Int) { diff --git a/src/library/scala/collection/immutable/RedBlackTree.scala b/src/library/scala/collection/immutable/RedBlackTree.scala index 0254e9ca3a..99f8d95517 100644 --- a/src/library/scala/collection/immutable/RedBlackTree.scala +++ b/src/library/scala/collection/immutable/RedBlackTree.scala @@ -18,7 +18,7 @@ import scala.annotation.meta.getter /** An object containing the RedBlack tree implementation used by for `TreeMaps` and `TreeSets`. * * Implementation note: since efficiency is important for data structures this implementation - * uses <code>null</code> to represent empty trees. This also means pattern matching cannot + * uses `null` to represent empty trees. This also means pattern matching cannot * easily be used. The API represented by the RedBlackTree object tries to hide these * optimizations behind a reasonably clean API. * @@ -74,15 +74,21 @@ object RedBlackTree { result } - def foreach[A, B, U](tree: Tree[A, B], f: ((A, B)) => U): Unit = if (tree ne null) { - if (tree.left ne null) foreach(tree.left, f) + + def foreach[A,B,U](tree:Tree[A,B], f:((A,B)) => U):Unit = if (tree ne null) _foreach(tree,f) + + private[this] def _foreach[A, B, U](tree: Tree[A, B], f: ((A, B)) => U) { + if (tree.left ne null) _foreach(tree.left, f) f((tree.key, tree.value)) - if (tree.right ne null) foreach(tree.right, f) + if (tree.right ne null) _foreach(tree.right, f) } - def foreachKey[A, U](tree: Tree[A, _], f: A => U): Unit = if (tree ne null) { - if (tree.left ne null) foreachKey(tree.left, f) - f(tree.key) - if (tree.right ne null) foreachKey(tree.right, f) + + def foreachKey[A, U](tree:Tree[A,_], f: A => U):Unit = if (tree ne null) _foreachKey(tree,f) + + private[this] def _foreachKey[A, U](tree: Tree[A, _], f: A => U) { + if (tree.left ne null) _foreachKey(tree.left, f) + f((tree.key)) + if (tree.right ne null) _foreachKey(tree.right, f) } def iterator[A, B](tree: Tree[A, B]): Iterator[(A, B)] = new EntriesIterator(tree) diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index be2cd91c68..3f7d27981b 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -181,6 +181,7 @@ import scala.language.implicitConversions * @define coll stream * @define orderDependent * @define orderDependentFold + * @define willTerminateInf Note: lazily evaluated; will terminate for infinite-sized collections. */ abstract class Stream[+A] extends AbstractSeq[A] with LinearSeq[A] @@ -286,9 +287,8 @@ self => len } - /** It's an imperfect world, but at least we can bottle up the - * imperfection in a capsule. - */ + // It's an imperfect world, but at least we can bottle up the + // imperfection in a capsule. @inline private def asThat[That](x: AnyRef): That = x.asInstanceOf[That] @inline private def asStream[B](x: AnyRef): Stream[B] = x.asInstanceOf[Stream[B]] @inline private def isStreamBuilder[B, That](bf: CanBuildFrom[Stream[A], B, That]) = @@ -385,12 +385,17 @@ self => // 1) stackoverflows (could be achieved with tailrec, too) // 2) out of memory errors for big streams (`this` reference can be eliminated from the stack) var rest: Stream[A] = this - while (rest.nonEmpty && !pf.isDefinedAt(rest.head)) rest = rest.tail + + // Avoids calling both `pf.isDefined` and `pf.apply`. + var newHead: B = null.asInstanceOf[B] + val runWith = pf.runWith((b: B) => newHead = b) + + while (rest.nonEmpty && !runWith(rest.head)) rest = rest.tail // without the call to the companion object, a thunk is created for the tail of the new stream, // and the closure of the thunk will reference `this` if (rest.isEmpty) Stream.Empty.asInstanceOf[That] - else Stream.collectedTail(rest, pf, bf).asInstanceOf[That] + else Stream.collectedTail(newHead, rest, pf, bf).asInstanceOf[That] } } @@ -725,10 +730,15 @@ self => * // produces: "5, 6, 7, 8, 9" * }}} */ - override def take(n: Int): Stream[A] = + override def take(n: Int): Stream[A] = ( + // Note that the n == 1 condition appears redundant but is not. + // It prevents "tail" from being referenced (and its head being evaluated) + // when obtaining the last element of the result. Such are the challenges + // of working with a lazy-but-not-really sequence. if (n <= 0 || isEmpty) Stream.empty else if (n == 1) cons(head, Stream.empty) else cons(head, tail take n-1) + ) @tailrec final override def drop(n: Int): Stream[A] = if (n <= 0 || isEmpty) this @@ -784,8 +794,23 @@ self => these } - // there's nothing we can do about dropRight, so we just keep the definition - // in LinearSeq + /** + * @inheritdoc + * $willTerminateInf + */ + override def dropRight(n: Int): Stream[A] = { + // We make dropRight work for possibly infinite streams by carrying + // a buffer of the dropped size. As long as the buffer is full and the + // rest is non-empty, we can feed elements off the buffer head. When + // the rest becomes empty, the full buffer is the dropped elements. + def advance(stub0: List[A], stub1: List[A], rest: Stream[A]): Stream[A] = { + if (rest.isEmpty) Stream.empty + else if (stub0.isEmpty) advance(stub1.reverse, Nil, rest) + else cons(stub0.head, advance(stub0.tail, rest.head :: stub1, rest.tail)) + } + if (n <= 0) this + else advance((this take n).toList, Nil, this drop n) + } /** Returns the longest prefix of this `Stream` whose elements satisfy the * predicate `p`. @@ -841,9 +866,16 @@ self => * // produces: "1, 2, 3, 4, 5, 6" * }}} */ - override def distinct: Stream[A] = - if (isEmpty) this - else cons(head, tail.filter(head != _).distinct) + override def distinct: Stream[A] = { + // This should use max memory proportional to N, whereas + // recursively calling distinct on the tail is N^2. + def loop(seen: Set[A], rest: Stream[A]): Stream[A] = { + if (rest.isEmpty) rest + else if (seen(rest.head)) loop(seen, rest.tail) + else cons(rest.head, loop(seen + rest.head, rest.tail)) + } + loop(Set(), this) + } /** Returns a new sequence of given length containing the elements of this * sequence followed by zero or more occurrences of given elements. @@ -1142,8 +1174,8 @@ object Stream extends SeqFactory[Stream] { cons(stream.head, stream.tail filter p) } - private[immutable] def collectedTail[A, B, That](stream: Stream[A], pf: PartialFunction[A, B], bf: CanBuildFrom[Stream[A], B, That]) = { - cons(pf(stream.head), stream.tail.collect(pf)(bf).asInstanceOf[Stream[B]]) + private[immutable] def collectedTail[A, B, That](head: B, stream: Stream[A], pf: PartialFunction[A, B], bf: CanBuildFrom[Stream[A], B, That]) = { + cons(head, stream.tail.collect(pf)(bf).asInstanceOf[Stream[B]]) } } diff --git a/src/library/scala/collection/immutable/StringLike.scala b/src/library/scala/collection/immutable/StringLike.scala index edea89b555..663318330c 100644 --- a/src/library/scala/collection/immutable/StringLike.scala +++ b/src/library/scala/collection/immutable/StringLike.scala @@ -9,7 +9,6 @@ package scala.collection package immutable -import generic._ import mutable.Builder import scala.util.matching.Regex import scala.math.ScalaNumber @@ -19,12 +18,11 @@ import scala.reflect.ClassTag * @since 2.8 */ object StringLike { - // just statics for companion class. - private final val LF: Char = 0x0A - private final val FF: Char = 0x0C - private final val CR: Char = 0x0D - private final val SU: Char = 0x1A + private final val LF = 0x0A + private final val FF = 0x0C + private final val CR = 0x0D + private final val SU = 0x1A } import StringLike._ diff --git a/src/library/scala/collection/immutable/StringOps.scala b/src/library/scala/collection/immutable/StringOps.scala index a650d98697..16c1f96cc2 100644 --- a/src/library/scala/collection/immutable/StringOps.scala +++ b/src/library/scala/collection/immutable/StringOps.scala @@ -6,8 +6,6 @@ ** |/ ** \* */ - - package scala.collection package immutable diff --git a/src/library/scala/collection/immutable/TrieIterator.scala b/src/library/scala/collection/immutable/TrieIterator.scala index ae427852d4..f117bddb8c 100644 --- a/src/library/scala/collection/immutable/TrieIterator.scala +++ b/src/library/scala/collection/immutable/TrieIterator.scala @@ -177,7 +177,6 @@ private[collection] abstract class TrieIterator[+T](elems: Array[Iterable[T]]) e if (depth > 0) { // 2) topmost comes before (is not) arrayD // steal a portion of top to create a new iterator - val topmost = arrayStack(0) if (posStack(0) == arrayStack(0).length - 1) { // 2a) only a single entry left on top // this means we have to modify this iterator - pop topmost diff --git a/src/library/scala/collection/immutable/Vector.scala b/src/library/scala/collection/immutable/Vector.scala index f083e80175..abaffd9d6a 100644 --- a/src/library/scala/collection/immutable/Vector.scala +++ b/src/library/scala/collection/immutable/Vector.scala @@ -139,7 +139,7 @@ override def companion: GenericCompanion[Vector] = Vector if (bf eq IndexedSeq.ReusableCBF) appendFront(elem).asInstanceOf[That] // just ignore bf else super.+:(elem)(bf) - override def :+[B >: A, That](elem: B)(implicit bf: CanBuildFrom[Vector[A], B, That]): That = + override def :+[B >: A, That](elem: B)(implicit bf: CanBuildFrom[Vector[A], B, That]): That = if (bf eq IndexedSeq.ReusableCBF) appendBack(elem).asInstanceOf[That] // just ignore bf else super.:+(elem)(bf) @@ -242,8 +242,8 @@ override def companion: GenericCompanion[Vector] = Vector private[immutable] def appendFront[B>:A](value: B): Vector[B] = { if (endIndex != startIndex) { - var blockIndex = (startIndex - 1) & ~31 - var lo = (startIndex - 1) & 31 + val blockIndex = (startIndex - 1) & ~31 + val lo = (startIndex - 1) & 31 if (startIndex != blockIndex + 32) { val s = new Vector(startIndex - 1, endIndex, blockIndex) @@ -339,8 +339,8 @@ override def companion: GenericCompanion[Vector] = Vector // //println("------- append " + value) // debug() if (endIndex != startIndex) { - var blockIndex = endIndex & ~31 - var lo = endIndex & 31 + val blockIndex = endIndex & ~31 + val lo = endIndex & 31 if (endIndex != blockIndex) { //println("will make writable block (from "+focus+") at: " + blockIndex) @@ -574,9 +574,7 @@ override def companion: GenericCompanion[Vector] = Vector } private def dropFront0(cutIndex: Int): Vector[A] = { - var blockIndex = cutIndex & ~31 - var lo = cutIndex & 31 - + val blockIndex = cutIndex & ~31 val xor = cutIndex ^ (endIndex - 1) val d = requiredDepth(xor) val shift = (cutIndex & ~((1 << (5*d))-1)) @@ -606,9 +604,7 @@ override def companion: GenericCompanion[Vector] = Vector } private def dropBack0(cutIndex: Int): Vector[A] = { - var blockIndex = (cutIndex - 1) & ~31 - var lo = ((cutIndex - 1) & 31) + 1 - + val blockIndex = (cutIndex - 1) & ~31 val xor = startIndex ^ (cutIndex - 1) val d = requiredDepth(xor) val shift = (startIndex & ~((1 << (5*d))-1)) @@ -630,14 +626,13 @@ override def companion: GenericCompanion[Vector] = Vector } -class VectorIterator[+A](_startIndex: Int, _endIndex: Int) +class VectorIterator[+A](_startIndex: Int, endIndex: Int) extends AbstractIterator[A] with Iterator[A] with VectorPointer[A @uncheckedVariance] { private var blockIndex: Int = _startIndex & ~31 private var lo: Int = _startIndex & 31 - private var endIndex: Int = _endIndex private var endLo = math.min(endIndex - blockIndex, 32) @@ -667,13 +662,13 @@ extends AbstractIterator[A] res } - private[collection] def remainingElementCount: Int = (_endIndex - (blockIndex + lo)) max 0 + private[collection] def remainingElementCount: Int = (endIndex - (blockIndex + lo)) max 0 /** Creates a new vector which consists of elements remaining in this iterator. * Such a vector can then be split into several vectors using methods like `take` and `drop`. */ private[collection] def remainingVector: Vector[A] = { - val v = new Vector(blockIndex + lo, _endIndex, blockIndex + lo) + val v = new Vector(blockIndex + lo, endIndex, blockIndex + lo) v.initFrom(this) v } diff --git a/src/library/scala/collection/mutable/ArrayBuilder.scala b/src/library/scala/collection/mutable/ArrayBuilder.scala index 0ce2cda32c..2fe3e91d68 100644 --- a/src/library/scala/collection/mutable/ArrayBuilder.scala +++ b/src/library/scala/collection/mutable/ArrayBuilder.scala @@ -6,12 +6,9 @@ ** |/ ** \* */ - - package scala.collection package mutable -import generic._ import scala.reflect.ClassTag import scala.runtime.ScalaRunTime diff --git a/src/library/scala/collection/mutable/ArrayLike.scala b/src/library/scala/collection/mutable/ArrayLike.scala index 31f3d2a497..40017aa08e 100644 --- a/src/library/scala/collection/mutable/ArrayLike.scala +++ b/src/library/scala/collection/mutable/ArrayLike.scala @@ -6,11 +6,8 @@ ** |/ ** \* */ - - package scala.collection package mutable -import generic._ /** A common supertrait of `ArrayOps` and `WrappedArray` that factors out most * operations on arrays and wrapped arrays. diff --git a/src/library/scala/collection/mutable/BufferProxy.scala b/src/library/scala/collection/mutable/BufferProxy.scala index 37aa1862fa..ade0b94230 100644 --- a/src/library/scala/collection/mutable/BufferProxy.scala +++ b/src/library/scala/collection/mutable/BufferProxy.scala @@ -6,12 +6,9 @@ ** |/ ** \* */ - - package scala.collection package mutable -import generic._ import script._ /** This is a simple proxy class for <a href="Buffer.html" diff --git a/src/library/scala/collection/mutable/FlatHashTable.scala b/src/library/scala/collection/mutable/FlatHashTable.scala index 91e95e039b..7ab99fcda2 100644 --- a/src/library/scala/collection/mutable/FlatHashTable.scala +++ b/src/library/scala/collection/mutable/FlatHashTable.scala @@ -265,7 +265,7 @@ trait FlatHashTable[A] extends FlatHashTable.HashUtils[A] { val totalbuckets = totalSizeMapBuckets var bucketidx = 0 var tableidx = 0 - var tbl = table + val tbl = table var tableuntil = sizeMapBucketSize min tbl.length while (bucketidx < totalbuckets) { var currbucketsz = 0 diff --git a/src/library/scala/collection/mutable/GenIterable.scala.disabled b/src/library/scala/collection/mutable/GenIterable.scala.disabled deleted file mode 100644 index 9acfccdae8..0000000000 --- a/src/library/scala/collection/mutable/GenIterable.scala.disabled +++ /dev/null @@ -1,37 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.collection -package mutable - - -import generic._ - - -/** A base trait for iterable collections that can be mutated. - * - * $possiblyparinfo - * - * $iterableInfo - */ -trait GenIterable[A] extends GenTraversable[A] - with scala.collection.GenIterable[A] - with scala.collection.GenIterableLike[A, GenIterable[A]] -// with GenericTraversableTemplate[A, GenIterable] -{ - def seq: Iterable[A] - //override def companion: GenericCompanion[GenIterable] = GenIterable -} - - -// object GenIterable extends TraversableFactory[GenIterable] { -// implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, GenIterable[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] -// def newBuilder[A]: Builder[A, GenIterable[A]] = Iterable.newBuilder -// } - - diff --git a/src/library/scala/collection/mutable/GenMap.scala.disabled b/src/library/scala/collection/mutable/GenMap.scala.disabled deleted file mode 100644 index e4fd1dad64..0000000000 --- a/src/library/scala/collection/mutable/GenMap.scala.disabled +++ /dev/null @@ -1,40 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - - -package scala.collection -package mutable - - -import generic._ - - -/** A base trait for maps that can be mutated. - * $possiblyparinfo - * $mapNote - * $mapTags - * @since 1.0 - * @author Matthias Zenger - */ -trait GenMap[A, B] -extends GenIterable[(A, B)] - with scala.collection.GenMap[A, B] - with scala.collection.GenMapLike[A, B, GenMap[A, B]] -{ - def seq: Map[A, B] -} - - -// object GenMap extends MapFactory[GenMap] { -// def empty[A, B]: Map[A, B] = Map.empty - -// /** $mapCanBuildFromInfo */ -// implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), GenMap[A, B]] = new MapCanBuildFrom[A, B] -// } - diff --git a/src/library/scala/collection/mutable/GenSeq.scala.disabled b/src/library/scala/collection/mutable/GenSeq.scala.disabled deleted file mode 100644 index ec904723a5..0000000000 --- a/src/library/scala/collection/mutable/GenSeq.scala.disabled +++ /dev/null @@ -1,44 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - - -package scala.collection -package mutable - - -import generic._ - - -/** A subtrait of `collection.GenSeq` which represents sequences - * that can be mutated. - * - * $possiblyparinfo - * - * $seqInfo - * - * The class adds an `update` method to `collection.Seq`. - * - * @define Coll `mutable.Seq` - * @define coll mutable sequence - */ -trait GenSeq[A] extends GenIterable[A] - with scala.collection.GenSeq[A] - with scala.collection.GenSeqLike[A, GenSeq[A]] -// with GenericTraversableTemplate[A, GenSeq] -{ - //override def companion: GenericCompanion[GenSeq] = GenSeq - def seq: Seq[A] -} - - -// object GenSeq extends SeqFactory[GenSeq] { -// implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, GenSeq[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] -// def newBuilder[A]: Builder[A, GenSeq[A]] = Seq.newBuilder -// } - diff --git a/src/library/scala/collection/mutable/GenSet.scala.disabled b/src/library/scala/collection/mutable/GenSet.scala.disabled deleted file mode 100644 index dec20e2a46..0000000000 --- a/src/library/scala/collection/mutable/GenSet.scala.disabled +++ /dev/null @@ -1,46 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - - -package scala.collection -package mutable - - - -import generic._ - - -/** A generic trait for mutable sets. - * - * $possiblyparinfo - * $setNote - * $setTags - * - * @since 1.0 - * @author Matthias Zenger - * @define Coll `mutable.Set` - * @define coll mutable set - */ -trait GenSet[A] extends GenIterable[A] - with Growable[A] - with scala.collection.GenSet[A] - with scala.collection.GenSetLike[A, GenSet[A]] -// with GenericSetTemplate[A, GenSet] -{ - //override def companion: GenericCompanion[GenSet] = GenSet - def seq: Set[A] -} - - -// object GenSet extends TraversableFactory[GenSet] { -// implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, GenSet[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] -// def newBuilder[A]: Builder[A, GenSet[A]] = Set.newBuilder -// } - - diff --git a/src/library/scala/collection/mutable/GenTraversable.scala.disabled b/src/library/scala/collection/mutable/GenTraversable.scala.disabled deleted file mode 100644 index 2453e2ce87..0000000000 --- a/src/library/scala/collection/mutable/GenTraversable.scala.disabled +++ /dev/null @@ -1,38 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - - -package scala.collection -package mutable - - -import generic._ - - -/** A trait for traversable collections that can be mutated. - * - * $possiblyparinfo - * - * $traversableInfo - * @define mutability mutable - */ -trait GenTraversable[A] extends scala.collection.GenTraversable[A] - with scala.collection.GenTraversableLike[A, GenTraversable[A]] -// with GenericTraversableTemplate[A, GenTraversable] - with Mutable -{ - def seq: Traversable[A] - //override def companion: GenericCompanion[GenTraversable] = GenTraversable -} - -// object GenTraversable extends TraversableFactory[GenTraversable] { -// implicit def canBuildFrom[A] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] -// def newBuilder[A] = Traversable.newBuilder -// } - diff --git a/src/library/scala/collection/mutable/IndexedSeqLike.scala b/src/library/scala/collection/mutable/IndexedSeqLike.scala index f0c31ec7fb..7b582eb5cb 100644 --- a/src/library/scala/collection/mutable/IndexedSeqLike.scala +++ b/src/library/scala/collection/mutable/IndexedSeqLike.scala @@ -6,11 +6,8 @@ ** |/ ** \* */ - - package scala.collection package mutable -import generic._ /** A subtrait of scala.collection.IndexedSeq which represents sequences * that can be mutated. diff --git a/src/library/scala/collection/mutable/IndexedSeqOptimized.scala b/src/library/scala/collection/mutable/IndexedSeqOptimized.scala index cb7e8efdc7..80b527a7b9 100755 --- a/src/library/scala/collection/mutable/IndexedSeqOptimized.scala +++ b/src/library/scala/collection/mutable/IndexedSeqOptimized.scala @@ -6,11 +6,8 @@ ** |/ ** \* */ - - package scala.collection package mutable -import generic._ /** A subtrait of scala.collection.IndexedSeq which represents sequences * that can be mutated. diff --git a/src/library/scala/collection/mutable/IndexedSeqView.scala b/src/library/scala/collection/mutable/IndexedSeqView.scala index cf5166eea8..a88ed8f123 100644 --- a/src/library/scala/collection/mutable/IndexedSeqView.scala +++ b/src/library/scala/collection/mutable/IndexedSeqView.scala @@ -82,8 +82,6 @@ self => protected override def newTakenWhile(p: A => Boolean): Transformed[A] = new { val pred = p } with AbstractTransformed[A] with TakenWhile protected override def newReversed: Transformed[A] = new AbstractTransformed[A] with Reversed - private implicit def asThis(xs: Transformed[A]): This = xs.asInstanceOf[This] - override def filter(p: A => Boolean): This = newFiltered(p) override def init: This = newSliced(SliceInterval(0, self.length - 1)) override def drop(n: Int): This = newSliced(SliceInterval(n, self.length)) diff --git a/src/library/scala/collection/mutable/LinkedListLike.scala b/src/library/scala/collection/mutable/LinkedListLike.scala index 4f63ede7ca..b3470ed3cd 100644 --- a/src/library/scala/collection/mutable/LinkedListLike.scala +++ b/src/library/scala/collection/mutable/LinkedListLike.scala @@ -6,12 +6,9 @@ ** |/ ** \* */ - - package scala.collection package mutable -import generic._ import scala.annotation.tailrec /** This extensible class may be used as a basis for implementing linked diff --git a/src/library/scala/collection/mutable/ListBuffer.scala b/src/library/scala/collection/mutable/ListBuffer.scala index 67af4a6bd6..b7b487964c 100644 --- a/src/library/scala/collection/mutable/ListBuffer.scala +++ b/src/library/scala/collection/mutable/ListBuffer.scala @@ -56,12 +56,18 @@ final class ListBuffer[A] import scala.collection.Traversable import scala.collection.immutable.ListSerializeEnd + /** Expected invariants: + * If start.isEmpty, last0 == null + * If start.nonEmpty, last0 != null + * If len == 0, start.isEmpty + * If len > 0, start.nonEmpty + */ private var start: List[A] = Nil private var last0: ::[A] = _ private var exported: Boolean = false private var len = 0 - protected def underlying: immutable.Seq[A] = start + protected def underlying: List[A] = start private def writeObject(out: ObjectOutputStream) { // write start @@ -160,7 +166,7 @@ final class ListBuffer[A] */ def += (x: A): this.type = { if (exported) copy() - if (start.isEmpty) { + if (isEmpty) { last0 = new :: (x, Nil) start = last0 } else { @@ -182,6 +188,7 @@ final class ListBuffer[A] */ def clear() { start = Nil + last0 = null exported = false len = 0 } @@ -195,7 +202,7 @@ final class ListBuffer[A] def +=: (x: A): this.type = { if (exported) copy() val newElem = new :: (x, start) - if (start.isEmpty) last0 = newElem + if (isEmpty) last0 = newElem start = newElem len += 1 this @@ -238,6 +245,15 @@ final class ListBuffer[A] } } + /** Reduce the length of the buffer, and null out last0 + * if this reduces the length to 0. + */ + private def reduceLengthBy(num: Int) { + len -= num + if (len <= 0) // obviously shouldn't be < 0, but still better not to leak + last0 = null + } + /** Removes a given number of elements on a given index position. May take * time linear in the buffer size. * @@ -253,7 +269,6 @@ final class ListBuffer[A] if (exported) copy() val n1 = n max 0 val count1 = count min (len - n1) - var old = start.head if (n1 == 0) { var c = count1 while (c > 0) { @@ -274,7 +289,7 @@ final class ListBuffer[A] c -= 1 } } - len -= count1 + reduceLengthBy(count1) } // Implementation of abstract method in Builder @@ -285,7 +300,7 @@ final class ListBuffer[A] * copied lazily, the first time it is mutated. */ override def toList: List[A] = { - exported = !start.isEmpty + exported = !isEmpty start } @@ -296,7 +311,7 @@ final class ListBuffer[A] * @param xs the list to which elements are prepended */ def prependToList(xs: List[A]): List[A] = { - if (start.isEmpty) xs + if (isEmpty) xs else { if (exported) copy() last0.tl = xs @@ -331,7 +346,7 @@ final class ListBuffer[A] if (last0 eq cursor.tail) last0 = cursor.asInstanceOf[::[A]] cursor.asInstanceOf[::[A]].tl = cursor.tail.tail } - len -= 1 + reduceLengthBy(1) old } @@ -343,11 +358,12 @@ final class ListBuffer[A] */ override def -= (elem: A): this.type = { if (exported) copy() - if (start.isEmpty) {} + if (isEmpty) {} else if (start.head == elem) { start = start.tail - len -= 1 - } else { + reduceLengthBy(1) + } + else { var cursor = start while (!cursor.tail.isEmpty && cursor.tail.head != elem) { cursor = cursor.tail @@ -357,7 +373,7 @@ final class ListBuffer[A] if (z.tl == last0) last0 = z z.tl = cursor.tail.tail - len -= 1 + reduceLengthBy(1) } } this @@ -397,6 +413,7 @@ final class ListBuffer[A] /** Copy contents of this buffer */ private def copy() { + if (isEmpty) return var cursor = start val limit = last0.tail clear() diff --git a/src/library/scala/collection/mutable/MapLike.scala b/src/library/scala/collection/mutable/MapLike.scala index a53aa3b76a..49d1e039f0 100644 --- a/src/library/scala/collection/mutable/MapLike.scala +++ b/src/library/scala/collection/mutable/MapLike.scala @@ -11,7 +11,7 @@ package scala.collection package mutable import generic._ -import scala.annotation.{migration, bridge} +import scala.annotation.migration import parallel.mutable.ParMap /** A template trait for mutable maps. @@ -50,8 +50,6 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] with Parallelizable[(A, B), ParMap[A, B]] { self => - import scala.collection.Traversable - /** A common implementation of `newBuilder` for all mutable maps * in terms of `empty`. * diff --git a/src/library/scala/collection/mutable/SeqLike.scala b/src/library/scala/collection/mutable/SeqLike.scala index 447100cf4c..ddfde536c9 100644 --- a/src/library/scala/collection/mutable/SeqLike.scala +++ b/src/library/scala/collection/mutable/SeqLike.scala @@ -9,7 +9,6 @@ package scala.collection package mutable -import generic._ import parallel.mutable.ParSeq /** A template trait for mutable sequences of type `mutable.Seq[A]`. diff --git a/src/library/scala/collection/mutable/SetBuilder.scala b/src/library/scala/collection/mutable/SetBuilder.scala index 42fd651d41..40f0b8932c 100644 --- a/src/library/scala/collection/mutable/SetBuilder.scala +++ b/src/library/scala/collection/mutable/SetBuilder.scala @@ -6,12 +6,9 @@ ** |/ ** \* */ - package scala.collection package mutable -import generic._ - /** The canonical builder for mutable Sets. * * @tparam A The type of the elements that will be contained in this set. diff --git a/src/library/scala/collection/mutable/SetLike.scala b/src/library/scala/collection/mutable/SetLike.scala index 01f87447ae..4a907e7dc4 100644 --- a/src/library/scala/collection/mutable/SetLike.scala +++ b/src/library/scala/collection/mutable/SetLike.scala @@ -11,7 +11,7 @@ package mutable import generic._ import script._ -import scala.annotation.{ migration, bridge } +import scala.annotation.migration import parallel.mutable.ParSet /** A template trait for mutable sets of type `mutable.Set[A]`. diff --git a/src/library/scala/collection/mutable/SynchronizedPriorityQueue.scala b/src/library/scala/collection/mutable/SynchronizedPriorityQueue.scala index 8dfc40b9c8..0065d4c556 100644 --- a/src/library/scala/collection/mutable/SynchronizedPriorityQueue.scala +++ b/src/library/scala/collection/mutable/SynchronizedPriorityQueue.scala @@ -73,14 +73,6 @@ class SynchronizedPriorityQueue[A](implicit ord: Ordering[A]) extends PriorityQu */ override def head: A = synchronized { super.head } - /** Returns the element with the highest priority in the queue, - * or throws an error if there is no element contained in the queue. - * - * @return the element with the highest priority. - */ - @deprecated("Use `head` instead.", "2.9.0") - override def max: A = synchronized { super.max } - /** Removes all elements from the queue. After this operation is completed, * the queue will be empty. */ diff --git a/src/library/scala/collection/mutable/SynchronizedQueue.scala b/src/library/scala/collection/mutable/SynchronizedQueue.scala index 9559d5eaa5..c5f133eec7 100644 --- a/src/library/scala/collection/mutable/SynchronizedQueue.scala +++ b/src/library/scala/collection/mutable/SynchronizedQueue.scala @@ -25,8 +25,6 @@ package mutable * @define coll synchronized queue */ class SynchronizedQueue[A] extends Queue[A] { - import scala.collection.Traversable - /** Checks if the queue is empty. * * @return true, iff there is no element in the queue. diff --git a/src/library/scala/collection/mutable/SynchronizedSet.scala b/src/library/scala/collection/mutable/SynchronizedSet.scala index e4a44993ff..bc9873880c 100644 --- a/src/library/scala/collection/mutable/SynchronizedSet.scala +++ b/src/library/scala/collection/mutable/SynchronizedSet.scala @@ -24,8 +24,6 @@ import script._ * @define coll synchronized set */ trait SynchronizedSet[A] extends Set[A] { - import scala.collection.Traversable - abstract override def size: Int = synchronized { super.size } diff --git a/src/library/scala/collection/mutable/WrappedArrayBuilder.scala b/src/library/scala/collection/mutable/WrappedArrayBuilder.scala index 7e0210311c..55328a5d3d 100644 --- a/src/library/scala/collection/mutable/WrappedArrayBuilder.scala +++ b/src/library/scala/collection/mutable/WrappedArrayBuilder.scala @@ -11,7 +11,6 @@ package scala.collection package mutable -import generic._ import scala.reflect.ClassTag import scala.runtime.ScalaRunTime._ diff --git a/src/library/scala/collection/parallel/ParIterable.scala b/src/library/scala/collection/parallel/ParIterable.scala index 2b24c88139..f170b944eb 100644 --- a/src/library/scala/collection/parallel/ParIterable.scala +++ b/src/library/scala/collection/parallel/ParIterable.scala @@ -11,7 +11,6 @@ package scala.collection.parallel import scala.collection.GenIterable import scala.collection.generic._ import scala.collection.parallel.mutable.ParArrayCombiner -import scala.collection.parallel.mutable.ParArray /** A template trait for parallel iterable collections. * diff --git a/src/library/scala/collection/parallel/ParIterableLike.scala b/src/library/scala/collection/parallel/ParIterableLike.scala index 0f06ff37af..d77e5a6744 100644 --- a/src/library/scala/collection/parallel/ParIterableLike.scala +++ b/src/library/scala/collection/parallel/ParIterableLike.scala @@ -171,9 +171,9 @@ self: ParIterableLike[T, Repr, Sequential] => /** The task support object which is responsible for scheduling and * load-balancing tasks to processors. - * + * * @see [[scala.collection.parallel.TaskSupport]] - */ + */ def tasksupport = { val ts = _tasksupport if (ts eq null) { @@ -188,18 +188,18 @@ self: ParIterableLike[T, Repr, Sequential] => * A task support object can be changed in a parallel collection after it * has been created, but only during a quiescent period, i.e. while there * are no concurrent invocations to parallel collection methods. - * - * Here is a way to change the task support of a parallel collection: - * - * {{{ - * import scala.collection.parallel._ - * val pc = mutable.ParArray(1, 2, 3) - * pc.tasksupport = new ForkJoinTaskSupport( - * new scala.concurrent.forkjoin.ForkJoinPool(2)) - * }}} + * + * Here is a way to change the task support of a parallel collection: + * + * {{{ + * import scala.collection.parallel._ + * val pc = mutable.ParArray(1, 2, 3) + * pc.tasksupport = new ForkJoinTaskSupport( + * new scala.concurrent.forkjoin.ForkJoinPool(2)) + * }}} * * @see [[scala.collection.parallel.TaskSupport]] - */ + */ def tasksupport_=(ts: TaskSupport) = _tasksupport = ts def seq: Sequential @@ -433,12 +433,13 @@ self: ParIterableLike[T, Repr, Sequential] => * @tparam S the type of accumulated results * @param z the initial value for the accumulated result of the partition - this * will typically be the neutral element for the `seqop` operator (e.g. - * `Nil` for list concatenation or `0` for summation) + * `Nil` for list concatenation or `0` for summation) and may be evaluated + * more than once * @param seqop an operator used to accumulate results within a partition * @param combop an associative operator used to combine results from different partitions */ - def aggregate[S](z: S)(seqop: (S, T) => S, combop: (S, S) => S): S = { - tasksupport.executeAndWaitResult(new Aggregate(z, seqop, combop, splitter)) + def aggregate[S](z: =>S)(seqop: (S, T) => S, combop: (S, S) => S): S = { + tasksupport.executeAndWaitResult(new Aggregate(() => z, seqop, combop, splitter)) } def foldLeft[S](z: S)(op: (S, T) => S): S = seq.foldLeft(z)(op) @@ -877,13 +878,13 @@ self: ParIterableLike[T, Repr, Sequential] => override def toSet[U >: T]: immutable.ParSet[U] = toParCollection[U, immutable.ParSet[U]](() => immutable.ParSet.newCombiner[U]) override def toMap[K, V](implicit ev: T <:< (K, V)): immutable.ParMap[K, V] = toParMap[K, V, immutable.ParMap[K, V]](() => immutable.ParMap.newCombiner[K, V]) - + override def toVector: Vector[T] = to[Vector] override def to[Col[_]](implicit cbf: CanBuildFrom[Nothing, T, Col[T @uncheckedVariance]]): Col[T @uncheckedVariance] = if (cbf().isCombiner) { toParCollection[T, Col[T]](() => cbf().asCombiner) } else seq.to(cbf) - + /* tasks */ protected trait StrictSplitterCheckTask[R, Tp] extends Task[R, Tp] { @@ -935,8 +936,8 @@ self: ParIterableLike[T, Repr, Sequential] => (f: First, s: Second) extends Composite[FR, SR, R, First, Second](f, s) { def leaf(prevr: Option[R]) = { - tasksupport.executeAndWaitResult(ft) - tasksupport.executeAndWaitResult(st) + tasksupport.executeAndWaitResult(ft) : Any + tasksupport.executeAndWaitResult(st) : Any mergeSubtasks } } @@ -946,8 +947,8 @@ self: ParIterableLike[T, Repr, Sequential] => (f: First, s: Second) extends Composite[FR, SR, R, First, Second](f, s) { def leaf(prevr: Option[R]) = { - val ftfuture = tasksupport.execute(ft) - tasksupport.executeAndWaitResult(st) + val ftfuture: () => Any = tasksupport.execute(ft) + tasksupport.executeAndWaitResult(st) : Any ftfuture() mergeSubtasks } @@ -1005,10 +1006,10 @@ self: ParIterableLike[T, Repr, Sequential] => override def merge(that: Fold[U]) = result = op(result, that.result) } - protected[this] class Aggregate[S](z: S, seqop: (S, T) => S, combop: (S, S) => S, protected[this] val pit: IterableSplitter[T]) + protected[this] class Aggregate[S](z: () => S, seqop: (S, T) => S, combop: (S, S) => S, protected[this] val pit: IterableSplitter[T]) extends Accessor[S, Aggregate[S]] { @volatile var result: S = null.asInstanceOf[S] - def leaf(prevr: Option[S]) = result = pit.foldLeft(z)(seqop) + def leaf(prevr: Option[S]) = result = pit.foldLeft(z())(seqop) protected[this] def newSubtask(p: IterableSplitter[T]) = new Aggregate(z, seqop, combop, p) override def merge(that: Aggregate[S]) = result = combop(result, that.result) } @@ -1504,31 +1505,3 @@ self: ParIterableLike[T, Repr, Sequential] => }) } - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/library/scala/collection/parallel/ParSeq.scala b/src/library/scala/collection/parallel/ParSeq.scala index b905d1d41f..dee523ad89 100644 --- a/src/library/scala/collection/parallel/ParSeq.scala +++ b/src/library/scala/collection/parallel/ParSeq.scala @@ -18,9 +18,6 @@ import scala.collection.generic.ParFactory import scala.collection.generic.CanCombineFrom import scala.collection.GenSeq import scala.collection.parallel.mutable.ParArrayCombiner -import scala.collection.parallel.mutable.ParArray - - /** A template trait for parallel sequences. * diff --git a/src/library/scala/collection/parallel/ParSeqView.scala b/src/library/scala/collection/parallel/ParSeqView.scala index 3e3c497352..9acc4b0b73 100644 --- a/src/library/scala/collection/parallel/ParSeqView.scala +++ b/src/library/scala/collection/parallel/ParSeqView.scala @@ -6,10 +6,9 @@ ** |/ ** \* */ - package scala.collection.parallel -import scala.collection.{ TraversableView, SeqView, Parallel, Iterator } +import scala.collection.{ SeqView, Parallel, Iterator } import scala.collection.generic.CanCombineFrom /** A template view of a non-strict view of a parallel sequence. diff --git a/src/library/scala/collection/parallel/ParSet.scala b/src/library/scala/collection/parallel/ParSet.scala index 6e5e9b4387..bc6d5c6245 100644 --- a/src/library/scala/collection/parallel/ParSet.scala +++ b/src/library/scala/collection/parallel/ParSet.scala @@ -17,14 +17,8 @@ package scala.collection.parallel import scala.collection.Set import scala.collection.GenSet -import scala.collection.mutable.Builder import scala.collection.generic._ - - - - - /** A template trait for parallel sets. * * $sideeffects diff --git a/src/library/scala/collection/parallel/ParSetLike.scala b/src/library/scala/collection/parallel/ParSetLike.scala index c80b5ded26..20a5f693ce 100644 --- a/src/library/scala/collection/parallel/ParSetLike.scala +++ b/src/library/scala/collection/parallel/ParSetLike.scala @@ -15,14 +15,6 @@ import scala.collection.SetLike import scala.collection.GenSetLike import scala.collection.GenSet import scala.collection.Set -import scala.collection.mutable.Builder - - - - - - - /** A template trait for parallel sets. This trait is mixed in with concrete * parallel sets to override the representation type. diff --git a/src/library/scala/collection/parallel/RemainsIterator.scala b/src/library/scala/collection/parallel/RemainsIterator.scala index 3150b0d763..732ebc3709 100644 --- a/src/library/scala/collection/parallel/RemainsIterator.scala +++ b/src/library/scala/collection/parallel/RemainsIterator.scala @@ -123,9 +123,10 @@ private[collection] trait AugmentedIterableIterator[+T] extends RemainsIterator[ def collect2combiner[S, That](pf: PartialFunction[T, S], cb: Combiner[S, That]): Combiner[S, That] = { //val cb = pbf(repr) + val runWith = pf.runWith(cb += _) while (hasNext) { val curr = next - if (pf.isDefinedAt(curr)) cb += pf(curr) + runWith(curr) } cb } diff --git a/src/library/scala/collection/parallel/Tasks.scala b/src/library/scala/collection/parallel/Tasks.scala index cec9e294c1..12f8012a5b 100644 --- a/src/library/scala/collection/parallel/Tasks.scala +++ b/src/library/scala/collection/parallel/Tasks.scala @@ -66,20 +66,10 @@ trait Task[R, +Tp] { private[parallel] def tryMerge(t: Tp @uncheckedVariance) { val that = t.asInstanceOf[Task[R, Tp]] - val local = result // ensure that any effects of modifying `result` are detected - // checkMerge(that) if (this.throwable == null && that.throwable == null) merge(t) mergeThrowables(that) } - private def checkMerge(that: Task[R, Tp] @uncheckedVariance) { - if (this.throwable == null && that.throwable == null && (this.result == null || that.result == null)) { - println("This: " + this + ", thr=" + this.throwable + "; merged with " + that + ", thr=" + that.throwable) - } else if (this.throwable != null || that.throwable != null) { - println("merging this: " + this + " with thr: " + this.throwable + " with " + that + ", thr=" + that.throwable) - } - } - private[parallel] def mergeThrowables(that: Task[_, _]) { if (this.throwable != null && that.throwable != null) { // merge exceptions, since there were multiple exceptions @@ -176,7 +166,6 @@ trait AdaptiveWorkStealingTasks extends Tasks { while (last.next != null) { // val lastresult = Option(last.body.result) - val beforelast = last last = last.next if (last.tryCancel()) { // println("Done with " + beforelast.body + ", next direct is " + last.body) diff --git a/src/library/scala/collection/parallel/immutable/ParIterable.scala b/src/library/scala/collection/parallel/immutable/ParIterable.scala index 142f07ff26..ec07e44c4d 100644 --- a/src/library/scala/collection/parallel/immutable/ParIterable.scala +++ b/src/library/scala/collection/parallel/immutable/ParIterable.scala @@ -15,8 +15,6 @@ import scala.collection.generic._ import scala.collection.parallel.ParIterableLike import scala.collection.parallel.Combiner -import scala.collection.GenIterable - /** A template trait for immutable parallel iterable collections. * diff --git a/src/library/scala/collection/parallel/immutable/ParNumericRange.scala.disabled b/src/library/scala/collection/parallel/immutable/ParNumericRange.scala.disabled deleted file mode 100644 index 5f9c9c3d3d..0000000000 --- a/src/library/scala/collection/parallel/immutable/ParNumericRange.scala.disabled +++ /dev/null @@ -1,128 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.collection.parallel.immutable - - - -import scala.collection.immutable.NumericRange -import scala.collection.parallel.Combiner -import scala.collection.generic.CanCombineFrom -import scala.collection.parallel.ParIterableIterator - - - -/** Parallel ranges for numeric types. - * - * $paralleliterableinfo - * - * $sideeffects - * - * @param range the sequential range this parallel range was obtained from - * - * @author Aleksandar Prokopec - * @since 2.9 - * - * @define Coll `immutable.ParRange` - * @define coll immutable parallel range - */ -@SerialVersionUID(1L) -class ParNumericRange[T](val range: NumericRange[T])(implicit num: Integral[T]) -extends ParSeq[T] - with Serializable -{ -self => - - def seq = range - - @inline final def length = range.length - - @inline final def apply(idx: Int) = range.apply(idx); - - def parallelIterator = new ParNumericRangeIterator with SCPI - - type SCPI = SignalContextPassingIterator[ParNumericRangeIterator] - - class ParNumericRangeIterator(range: NumericRange[T] = self.range, num: Integral[T] = self.num) - extends ParIterator { - me: SignalContextPassingIterator[ParNumericRangeIterator] => - override def toString = "ParNumericRangeIterator(over: " + range + ")" - private var ind = 0 - private val len = range.length - - final def remaining = len - ind - - final def hasNext = ind < len - - final def next = if (hasNext) { - val r = range.apply(ind) - ind += 1 - r - } else Iterator.empty.next - - private def rangeleft: NumericRange[T] = range.drop(ind) - - def dup = new ParNumericRangeIterator(rangeleft) with SCPI - - def split = { - val rleft = rangeleft - val elemleft = rleft.length - if (elemleft < 2) Seq(new ParNumericRangeIterator(rleft) with SCPI) - else Seq( - new ParNumericRangeIterator(rleft.take(elemleft / 2)) with SCPI, - new ParNumericRangeIterator(rleft.drop(elemleft / 2)) with SCPI - ) - } - - def psplit(sizes: Int*) = { - var rleft = rangeleft - for (sz <- sizes) yield { - val fronttaken = rleft.take(sz) - rleft = rleft.drop(sz) - new ParNumericRangeIterator(fronttaken) with SCPI - } - } - - /* accessors */ - - override def foreach[U](f: T => U): Unit = { - rangeleft.foreach(f) - ind = len - } - - override def reduce[U >: T](op: (U, U) => U): U = { - val r = rangeleft.reduceLeft(op) - ind = len - r - } - - /* transformers */ - - override def map2combiner[S, That](f: T => S, cb: Combiner[S, That]): Combiner[S, That] = { - while (hasNext) { - cb += f(next) - } - cb - } - } - -} - - -object ParNumericRange { - def apply[T](start: T, end: T, step: T, inclusive: Boolean)(implicit num: Integral[T]) = new ParNumericRange[T]( - if (inclusive) NumericRange.inclusive(start, end, step)(num) - else NumericRange.apply(start, end, step)(num) - ) -} - - - - - diff --git a/src/library/scala/collection/parallel/immutable/ParSeq.scala b/src/library/scala/collection/parallel/immutable/ParSeq.scala index aa19307387..b54a5f0205 100644 --- a/src/library/scala/collection/parallel/immutable/ParSeq.scala +++ b/src/library/scala/collection/parallel/immutable/ParSeq.scala @@ -18,9 +18,6 @@ import scala.collection.generic.CanCombineFrom import scala.collection.generic.ParFactory import scala.collection.parallel.ParSeqLike import scala.collection.parallel.Combiner -import scala.collection.GenSeq - - /** An immutable variant of `ParSeq`. * diff --git a/src/library/scala/collection/parallel/immutable/ParSet.scala b/src/library/scala/collection/parallel/immutable/ParSet.scala index 3622377a55..aba8486ab5 100644 --- a/src/library/scala/collection/parallel/immutable/ParSet.scala +++ b/src/library/scala/collection/parallel/immutable/ParSet.scala @@ -9,7 +9,6 @@ package scala.collection package parallel.immutable -import scala.collection.GenSet import scala.collection.generic._ import scala.collection.parallel.ParSetLike import scala.collection.parallel.Combiner diff --git a/src/library/scala/collection/parallel/mutable/ParArray.scala b/src/library/scala/collection/parallel/mutable/ParArray.scala index e4c8e5fae2..db4a59f6ba 100644 --- a/src/library/scala/collection/parallel/mutable/ParArray.scala +++ b/src/library/scala/collection/parallel/mutable/ParArray.scala @@ -181,10 +181,10 @@ self => override def fold[U >: T](z: U)(op: (U, U) => U): U = foldLeft[U](z)(op) - override def aggregate[S](z: S)(seqop: (S, T) => S, combop: (S, S) => S): S = foldLeft[S](z)(seqop) + override def aggregate[S](z: =>S)(seqop: (S, T) => S, combop: (S, S) => S): S = foldLeft[S](z)(seqop) override def sum[U >: T](implicit num: Numeric[U]): U = { - var s = sum_quick(num, arr, until, i, num.zero) + val s = sum_quick(num, arr, until, i, num.zero) i = until s } @@ -200,7 +200,7 @@ self => } override def product[U >: T](implicit num: Numeric[U]): U = { - var p = product_quick(num, arr, until, i, num.one) + val p = product_quick(num, arr, until, i, num.one) i = until p } @@ -405,9 +405,10 @@ self => private def collect2combiner_quick[S, That](pf: PartialFunction[T, S], a: Array[Any], cb: Builder[S, That], ntil: Int, from: Int) { var j = from + val runWith = pf.runWith(b => cb += b) while (j < ntil) { val curr = a(j).asInstanceOf[T] - if (pf.isDefinedAt(curr)) cb += pf(curr) + runWith(curr) j += 1 } } @@ -432,7 +433,7 @@ self => private def filter2combiner_quick[U >: T, This](pred: T => Boolean, cb: Builder[U, This], a: Array[Any], ntil: Int, from: Int) { var j = i while(j < ntil) { - var curr = a(j).asInstanceOf[T] + val curr = a(j).asInstanceOf[T] if (pred(curr)) cb += curr j += 1 } @@ -447,7 +448,7 @@ self => private def filterNot2combiner_quick[U >: T, This](pred: T => Boolean, cb: Builder[U, This], a: Array[Any], ntil: Int, from: Int) { var j = i while(j < ntil) { - var curr = a(j).asInstanceOf[T] + val curr = a(j).asInstanceOf[T] if (!pred(curr)) cb += curr j += 1 } @@ -579,8 +580,6 @@ self => /* operations */ - private def asTask[R, Tp](t: Any) = t.asInstanceOf[Task[R, Tp]] - private def buildsArray[S, That](c: Builder[S, That]) = c.isInstanceOf[ParArrayCombiner[_]] override def map[S, That](f: T => S)(implicit bf: CanBuildFrom[ParArray[T], S, That]) = if (buildsArray(bf(repr))) { diff --git a/src/library/scala/collection/parallel/mutable/ParFlatHashTable.scala b/src/library/scala/collection/parallel/mutable/ParFlatHashTable.scala index 8bc108a738..b151e45d65 100644 --- a/src/library/scala/collection/parallel/mutable/ParFlatHashTable.scala +++ b/src/library/scala/collection/parallel/mutable/ParFlatHashTable.scala @@ -38,10 +38,6 @@ trait ParFlatHashTable[T] extends scala.collection.mutable.FlatHashTable[T] { } } - private def checkbounds() = if (idx >= itertable.length) { - throw new IndexOutOfBoundsException(idx.toString) - } - def newIterator(index: Int, until: Int, totalsize: Int): IterableSplitter[T] def remaining = totalsize - traversed @@ -102,11 +98,5 @@ trait ParFlatHashTable[T] extends scala.collection.mutable.FlatHashTable[T] { } count } - - private def check() = if (table.slice(idx, until).count(_ != null) != remaining) { - println("Invariant broken: " + debugInformation) - assert(false) - } } - } diff --git a/src/library/scala/collection/parallel/mutable/ParHashMap.scala b/src/library/scala/collection/parallel/mutable/ParHashMap.scala index 11588e555b..541d75290b 100644 --- a/src/library/scala/collection/parallel/mutable/ParHashMap.scala +++ b/src/library/scala/collection/parallel/mutable/ParHashMap.scala @@ -166,9 +166,8 @@ private[mutable] abstract class ParHashMapCombiner[K, V](private val tableLoadFa extends scala.collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], DefaultEntry[K, V], ParHashMapCombiner[K, V]](ParHashMapCombiner.numblocks) with scala.collection.mutable.HashTable.HashUtils[K] { - private var mask = ParHashMapCombiner.discriminantmask - private var nonmasklen = ParHashMapCombiner.nonmasklength - private var seedvalue = 27 + private val nonmasklen = ParHashMapCombiner.nonmasklength + private val seedvalue = 27 def +=(elem: (K, V)) = { sz += 1 @@ -232,8 +231,7 @@ extends scala.collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], Defau def setSize(sz: Int) = tableSize = sz def insertEntry(/*block: Int, */e: DefaultEntry[K, V]) = { var h = index(elemHashCode(e.key)) - // assertCorrectBlock(h, block) - var olde = table(h).asInstanceOf[DefaultEntry[K, V]] + val olde = table(h).asInstanceOf[DefaultEntry[K, V]] // check if key already exists var ce = olde @@ -252,13 +250,6 @@ extends scala.collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], Defau true } else false } - private def assertCorrectBlock(h: Int, block: Int) { - val blocksize = table.length / (1 << ParHashMapCombiner.discriminantbits) - if (!(h >= block * blocksize && h < (block + 1) * blocksize)) { - println("trying to put " + h + " into block no.: " + block + ", range: [" + block * blocksize + ", " + (block + 1) * blocksize + ">") - assert(h >= block * blocksize && h < (block + 1) * blocksize) - } - } protected def createNewEntry[X](key: K, x: X) = ??? } @@ -288,7 +279,6 @@ extends scala.collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], Defau val chunksz = unrolled.size while (i < chunksz) { val elem = chunkarr(i) - // assertCorrectBlock(block, elem.key) if (t.insertEntry(elem)) insertcount += 1 i += 1 } @@ -297,13 +287,6 @@ extends scala.collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], Defau } insertcount } - private def assertCorrectBlock(block: Int, k: K) { - val hc = improve(elemHashCode(k), seedvalue) - if ((hc >>> nonmasklen) != block) { - println(hc + " goes to " + (hc >>> nonmasklen) + ", while expected block is " + block) - assert((hc >>> nonmasklen) == block) - } - } def split = { val fp = howmany / 2 List(new FillBlocks(buckets, table, offset, fp), new FillBlocks(buckets, table, offset + fp, howmany - fp)) diff --git a/src/library/scala/collection/parallel/mutable/ParHashSet.scala b/src/library/scala/collection/parallel/mutable/ParHashSet.scala index 3b1278f3be..f1377fb0a7 100644 --- a/src/library/scala/collection/parallel/mutable/ParHashSet.scala +++ b/src/library/scala/collection/parallel/mutable/ParHashSet.scala @@ -120,9 +120,8 @@ private[mutable] abstract class ParHashSetCombiner[T](private val tableLoadFacto extends scala.collection.parallel.BucketCombiner[T, ParHashSet[T], Any, ParHashSetCombiner[T]](ParHashSetCombiner.numblocks) with scala.collection.mutable.FlatHashTable.HashUtils[T] { //self: EnvironmentPassingCombiner[T, ParHashSet[T]] => - private var mask = ParHashSetCombiner.discriminantmask - private var nonmasklen = ParHashSetCombiner.nonmasklength - private var seedvalue = 27 + private val nonmasklen = ParHashSetCombiner.nonmasklength + private val seedvalue = 27 def +=(elem: T) = { sz += 1 @@ -264,12 +263,12 @@ with scala.collection.mutable.FlatHashTable.HashUtils[T] { (elemsIn + leftoversIn, elemsLeft concat leftoversLeft) } private def insertAll(atPos: Int, beforePos: Int, elems: UnrolledBuffer[Any]): (Int, UnrolledBuffer[Any]) = { - var leftovers = new UnrolledBuffer[Any] + val leftovers = new UnrolledBuffer[Any] var inserted = 0 var unrolled = elems.headPtr var i = 0 - var t = table + val t = table while (unrolled ne null) { val chunkarr = unrolled.array val chunksz = unrolled.size diff --git a/src/library/scala/collection/parallel/mutable/ParHashTable.scala b/src/library/scala/collection/parallel/mutable/ParHashTable.scala index 66ddef6a1e..5aa1dba17c 100644 --- a/src/library/scala/collection/parallel/mutable/ParHashTable.scala +++ b/src/library/scala/collection/parallel/mutable/ParHashTable.scala @@ -110,7 +110,7 @@ trait ParHashTable[K, Entry >: Null <: HashEntry[K, Entry]] extends scala.collec } else Seq(this.asInstanceOf[IterRepr]) private def convertToArrayBuffer(chainhead: Entry): mutable.ArrayBuffer[T] = { - var buff = mutable.ArrayBuffer[Entry]() + val buff = mutable.ArrayBuffer[Entry]() var curr = chainhead while (curr ne null) { buff += curr diff --git a/src/library/scala/collection/parallel/mutable/ParIterable.scala b/src/library/scala/collection/parallel/mutable/ParIterable.scala index 7090c510a0..d76e4b1745 100644 --- a/src/library/scala/collection/parallel/mutable/ParIterable.scala +++ b/src/library/scala/collection/parallel/mutable/ParIterable.scala @@ -12,8 +12,6 @@ package scala.collection.parallel.mutable import scala.collection.generic._ import scala.collection.parallel.ParIterableLike import scala.collection.parallel.Combiner -import scala.collection.GenIterable - /** A template trait for mutable parallel iterable collections. * diff --git a/src/library/scala/collection/parallel/mutable/ParMapLike.scala b/src/library/scala/collection/parallel/mutable/ParMapLike.scala index cdcfc59f8f..08bc706c8a 100644 --- a/src/library/scala/collection/parallel/mutable/ParMapLike.scala +++ b/src/library/scala/collection/parallel/mutable/ParMapLike.scala @@ -12,13 +12,10 @@ package mutable import scala.collection.generic._ -import scala.collection.mutable.Builder import scala.collection.mutable.Cloneable import scala.collection.generic.Growable import scala.collection.generic.Shrinkable - - /** A template trait for mutable parallel maps. This trait is to be mixed in * with concrete parallel maps to override the representation type. * diff --git a/src/library/scala/collection/parallel/mutable/ParSeq.scala b/src/library/scala/collection/parallel/mutable/ParSeq.scala index 95a4d4a13a..8a55ab83f1 100644 --- a/src/library/scala/collection/parallel/mutable/ParSeq.scala +++ b/src/library/scala/collection/parallel/mutable/ParSeq.scala @@ -17,12 +17,6 @@ import scala.collection.generic.CanCombineFrom import scala.collection.generic.ParFactory import scala.collection.parallel.ParSeqLike import scala.collection.parallel.Combiner -import scala.collection.GenSeq - - - - - /** A mutable variant of `ParSeq`. * diff --git a/src/library/scala/collection/parallel/mutable/ParSet.scala b/src/library/scala/collection/parallel/mutable/ParSet.scala index d8f821746c..ca41852512 100644 --- a/src/library/scala/collection/parallel/mutable/ParSet.scala +++ b/src/library/scala/collection/parallel/mutable/ParSet.scala @@ -13,11 +13,6 @@ package scala.collection.parallel.mutable import scala.collection.generic._ import scala.collection.parallel.Combiner -import scala.collection.GenSet - - - - /** A mutable variant of `ParSet`. * diff --git a/src/library/scala/collection/parallel/mutable/ParSetLike.scala b/src/library/scala/collection/parallel/mutable/ParSetLike.scala index 609888f1a9..0941229124 100644 --- a/src/library/scala/collection/parallel/mutable/ParSetLike.scala +++ b/src/library/scala/collection/parallel/mutable/ParSetLike.scala @@ -10,17 +10,11 @@ package scala.collection package parallel.mutable - - -import scala.collection.mutable.Set -import scala.collection.mutable.Builder import scala.collection.mutable.Cloneable import scala.collection.GenSetLike import scala.collection.generic.Growable import scala.collection.generic.Shrinkable - - /** A template trait for mutable parallel sets. This trait is mixed in with concrete * parallel sets to override the representation type. * diff --git a/src/library/scala/collection/parallel/mutable/ResizableParArrayCombiner.scala b/src/library/scala/collection/parallel/mutable/ResizableParArrayCombiner.scala index dc31d1bc25..0b9b51bc5b 100644 --- a/src/library/scala/collection/parallel/mutable/ResizableParArrayCombiner.scala +++ b/src/library/scala/collection/parallel/mutable/ResizableParArrayCombiner.scala @@ -26,7 +26,7 @@ trait ResizableParArrayCombiner[T] extends LazyCombiner[T, ParArray[T], ExposedA override def sizeHint(sz: Int) = if (chain.length == 1) chain(0).sizeHint(sz) // public method with private[mutable] type ExposedArrayBuffer in parameter type; cannot be overridden. - def newLazyCombiner(c: ArrayBuffer[ExposedArrayBuffer[T]]) = ResizableParArrayCombiner(c) + final def newLazyCombiner(c: ArrayBuffer[ExposedArrayBuffer[T]]) = ResizableParArrayCombiner(c) def allocateAndCopy = if (chain.size > 1) { val arrayseq = new ArraySeq[T](size) diff --git a/src/library/scala/collection/script/Message.scala b/src/library/scala/collection/script/Message.scala index 2ab7ea726a..7428cd2b81 100644 --- a/src/library/scala/collection/script/Message.scala +++ b/src/library/scala/collection/script/Message.scala @@ -69,7 +69,7 @@ class Script[A] extends ArrayBuffer[Message[A]] with Message[A] { override def toString(): String = { var res = "Script(" - var it = this.iterator + val it = this.iterator var i = 1 while (it.hasNext) { if (i > 1) diff --git a/src/library/scala/concurrent/FutureTaskRunner.scala b/src/library/scala/concurrent/FutureTaskRunner.scala index eeadaddb5e..cb4f8687f3 100644 --- a/src/library/scala/concurrent/FutureTaskRunner.scala +++ b/src/library/scala/concurrent/FutureTaskRunner.scala @@ -10,7 +10,7 @@ package scala.concurrent import scala.language.{implicitConversions, higherKinds} -/** The `FutureTaskRunner</code> trait is a base trait of task runners +/** The `FutureTaskRunner` trait is a base trait of task runners * that provide some sort of future abstraction. * * @author Philipp Haller diff --git a/src/library/scala/concurrent/JavaConversions.scala b/src/library/scala/concurrent/JavaConversions.scala index d6a7c1f1bb..573882ee34 100644 --- a/src/library/scala/concurrent/JavaConversions.scala +++ b/src/library/scala/concurrent/JavaConversions.scala @@ -41,10 +41,6 @@ object JavaConversions { exec.execute(task) } - def managedBlock(blocker: ManagedBlocker) { - blocker.block() - } - def shutdown() { // do nothing } diff --git a/src/library/scala/concurrent/impl/Future.scala b/src/library/scala/concurrent/impl/Future.scala index 8c2a77c75f..055ce6e4fa 100644 --- a/src/library/scala/concurrent/impl/Future.scala +++ b/src/library/scala/concurrent/impl/Future.scala @@ -12,7 +12,7 @@ package scala.concurrent.impl import scala.concurrent.ExecutionContext import scala.util.control.NonFatal -import scala.util.{Try, Success, Failure} +import scala.util.{ Success, Failure } private[concurrent] object Future { diff --git a/src/library/scala/io/Position.scala b/src/library/scala/io/Position.scala index daa4e103be..b96349803d 100644 --- a/src/library/scala/io/Position.scala +++ b/src/library/scala/io/Position.scala @@ -68,14 +68,6 @@ abstract class Position { } object Position extends Position { - /** The undefined position */ - @deprecated("This will be removed", "2.9.0") - final val NOPOS = 0 - - /** The first position in a source file */ - @deprecated("This will be removed", "2.9.0") - final val FIRSTPOS = encode(1, 1) - def checkInput(line: Int, column: Int) { if (line < 0) throw new IllegalArgumentException(line + " < 0") diff --git a/src/library/scala/math/BigDecimal.scala b/src/library/scala/math/BigDecimal.scala index 7c14ed3a9e..f3aabc2974 100644 --- a/src/library/scala/math/BigDecimal.scala +++ b/src/library/scala/math/BigDecimal.scala @@ -25,12 +25,6 @@ object BigDecimal { private val maxCached = 512 val defaultMathContext = MathContext.DECIMAL128 - @deprecated("Use Long.MinValue", "2.9.0") - val MinLong = new BigDecimal(BigDec valueOf Long.MinValue, defaultMathContext) - - @deprecated("Use Long.MaxValue", "2.9.0") - val MaxLong = new BigDecimal(BigDec valueOf Long.MaxValue, defaultMathContext) - /** Cache ony for defaultMathContext using BigDecimals in a small range. */ private lazy val cache = new Array[BigDecimal](maxCached - minCached + 1) diff --git a/src/library/scala/math/BigInt.scala b/src/library/scala/math/BigInt.scala index 441bf5aa4d..0cddd71721 100644 --- a/src/library/scala/math/BigInt.scala +++ b/src/library/scala/math/BigInt.scala @@ -23,12 +23,6 @@ object BigInt { private val cache = new Array[BigInt](maxCached - minCached + 1) private val minusOne = BigInteger.valueOf(-1) - @deprecated("Use Long.MinValue", "2.9.0") - val MinLong = BigInt(Long.MinValue) - - @deprecated("Use Long.MaxValue", "2.9.0") - val MaxLong = BigInt(Long.MaxValue) - /** Constructs a `BigInt` whose value is equal to that of the * specified integer value. * diff --git a/src/library/scala/math/ScalaNumericConversions.scala b/src/library/scala/math/ScalaNumericConversions.scala index 6ddf48d03b..59fc7f27b2 100644 --- a/src/library/scala/math/ScalaNumericConversions.scala +++ b/src/library/scala/math/ScalaNumericConversions.scala @@ -8,8 +8,6 @@ package scala.math -import java.{ lang => jl } - /** A slightly more specific conversion trait for classes which * extend ScalaNumber (which excludes value classes.) */ diff --git a/src/library/scala/package.scala b/src/library/scala/package.scala index d3f8df9110..15d6dce8a7 100644 --- a/src/library/scala/package.scala +++ b/src/library/scala/package.scala @@ -34,9 +34,6 @@ package object scala { override def toString = "object AnyRef" } - @deprecated("instead of `@serializable class C`, use `class C extends Serializable`", "2.9.0") - type serializable = annotation.serializable - @deprecated("instead of `@cloneable class C`, use `class C extends Cloneable`", "2.10.0") type cloneable = annotation.cloneable @@ -129,9 +126,8 @@ package object scala { type deprecatedName = annotation.deprecatedName type inline = annotation.inline type native = annotation.native - type noinline = noannotation.inline + type noinline = annotation.noinline type remote = annotation.remote - type serializable = annotation.serializable type specialized = annotation.specialized type transient = annotation.transient type throws = annotation.throws diff --git a/src/library/scala/parallel/package.scala.disabled b/src/library/scala/parallel/package.scala.disabled deleted file mode 100644 index 45f5470d03..0000000000 --- a/src/library/scala/parallel/package.scala.disabled +++ /dev/null @@ -1,178 +0,0 @@ -package scala - - - -import scala.concurrent.forkjoin._ - - -/** This package object contains various parallel operations. - * - * @define invokingPar - * Invoking a parallel computation creates a future which will - * hold the result of the computation once it completes. Querying - * the result of a future before its parallel computation has completed - * will block the caller. For all practical concerns, the dependency - * chain obtained by querying results of unfinished futures can have - * arbitrary lengths. However, care must be taken not to create a - * circular dependency, as this will result in a deadlock. - * - * Additionally, if the parallel computation performs a blocking call - * (e.g. an I/O operation or waiting for a lock) other than waiting for a future, - * it should do so by invoking the `block` method. This is another - * form of waiting that could potentially create a circular dependency, - * an the user should take care not to do this. - * - * Users should be aware that invoking a parallel computation has a - * certain overhead. Parallel computations should not be invoked for - * small computations, as this can lead to bad performance. A rule of the - * thumb is having parallel computations equivalent to a loop - * with 50000 arithmetic operations (at least). If a parallel computation - * is invoked within another parallel computation, then it should be - * computationally equivalent to a loop with 10000 arithmetic operations. - */ -package object parallel { - - private[scala] val forkjoinpool = new ForkJoinPool() - - private class Task[T](body: =>T) extends RecursiveTask[T] with Future[T] { - def compute = body - def apply() = join() - } - - private final def newTask[T](body: =>T) = new Task[T](body) - - private final def executeTask[T](task: RecursiveTask[T]) { - if (Thread.currentThread().isInstanceOf[ForkJoinWorkerThread]) task.fork - else forkjoinpool.execute(task) - } - - /* public methods */ - - /** Performs a call which can potentially block execution. - * - * Example: - * {{{ - * val lock = new ReentrantLock - * - * // ... do something ... - * - * blocking { - * if (!lock.hasLock) lock.lock() - * } - * }}} - * - * '''Note:''' calling methods that wait arbitrary amounts of time - * (e.g. for I/O operations or locks) may severely decrease performance - * or even result in deadlocks. This does not include waiting for - * results of futures. - */ - def blocking[T](body: =>T): T = { - if (Thread.currentThread().isInstanceOf[ForkJoinWorkerThread]) { - val blocker = new ForkJoinPool.ManagedBlocker { - @volatile var done = false - @volatile var result: Any = _ - def block() = { - result = body - done = true - true - } - def isReleasable() = done - } - ForkJoinPool.managedBlock(blocker, true) - blocker.result.asInstanceOf[T] - } else body - } - - /** Starts a parallel computation and returns a future. - * - * $invokingPar - * - * @tparam T the type of the result of the parallel computation - * @param body the computation to be invoked in parallel - * @return a future with the result - */ - def par[T](body: =>T): Future[T] = { - val task = newTask(body) - executeTask(task) - task - } - - /** Starts 2 parallel computations and returns a future. - * - * $invokingPar - * - * @tparam T1 the type of the result of 1st the parallel computation - * @tparam T2 the type of the result of 2nd the parallel computation - * @param b1 the 1st computation to be invoked in parallel - * @param b2 the 2nd computation to be invoked in parallel - * @return a tuple of futures corresponding to parallel computations - */ - def par[T1, T2](b1: =>T1, b2: =>T2): (Future[T1], Future[T2]) = { - val t1 = newTask(b1) - executeTask(t1) - val t2 = newTask(b2) - executeTask(t2) - (t1, t2) - } - - /** Starts 3 parallel computations and returns a future. - * - * $invokingPar - * - * @tparam T1 the type of the result of 1st the parallel computation - * @tparam T2 the type of the result of 2nd the parallel computation - * @tparam T3 the type of the result of 3rd the parallel computation - * @param b1 the 1st computation to be invoked in parallel - * @param b2 the 2nd computation to be invoked in parallel - * @param b3 the 3rd computation to be invoked in parallel - * @return a tuple of futures corresponding to parallel computations - */ - def par[T1, T2, T3](b1: =>T1, b2: =>T2, b3: =>T3): (Future[T1], Future[T2], Future[T3]) = { - val t1 = newTask(b1) - executeTask(t1) - val t2 = newTask(b2) - executeTask(t2) - val t3 = newTask(b3) - executeTask(t3) - (t1, t2, t3) - } - - /** Starts 4 parallel computations and returns a future. - * - * $invokingPar - * - * @tparam T1 the type of the result of 1st the parallel computation - * @tparam T2 the type of the result of 2nd the parallel computation - * @tparam T3 the type of the result of 3rd the parallel computation - * @tparam T4 the type of the result of 4th the parallel computation - * @param b1 the 1st computation to be invoked in parallel - * @param b2 the 2nd computation to be invoked in parallel - * @param b3 the 3rd computation to be invoked in parallel - * @param b4 the 4th computation to be invoked in parallel - * @return a tuple of futures corresponding to parallel computations - */ - def par[T1, T2, T3, T4](b1: =>T1, b2: =>T2, b3: =>T3, b4: =>T4): (Future[T1], Future[T2], Future[T3], Future[T4]) = { - val t1 = newTask(b1) - executeTask(t1) - val t2 = newTask(b2) - executeTask(t2) - val t3 = newTask(b3) - executeTask(t3) - val t4 = newTask(b4) - executeTask(t4) - (t1, t2, t3, t4) - } - -} - - - - - - - - - - - - diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index 1d8fe5e9ad..1a79e6da73 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -26,8 +26,7 @@ import java.lang.reflect.{ Modifier, Method => JMethod } * outside the API and subject to change or removal without notice. */ object ScalaRunTime { - def isArray(x: AnyRef): Boolean = isArray(x, 1) - def isArray(x: Any, atLevel: Int): Boolean = + def isArray(x: Any, atLevel: Int = 1): Boolean = x != null && isArrayClass(x.getClass, atLevel) private def isArrayClass(clazz: jClass[_], atLevel: Int): Boolean = diff --git a/src/library/scala/sys/SystemProperties.scala b/src/library/scala/sys/SystemProperties.scala index da9adb3dc2..294be5cd71 100644 --- a/src/library/scala/sys/SystemProperties.scala +++ b/src/library/scala/sys/SystemProperties.scala @@ -64,7 +64,6 @@ object SystemProperties { propertyHelp(p.key) = helpText p } - private def str(key: String, helpText: String) = addHelp(Prop[String](key), helpText) private def bool(key: String, helpText: String): BooleanProp = addHelp[BooleanProp]( if (key startsWith "java.") BooleanProp.valueIsTrue(key) else BooleanProp.keyExists(key), helpText diff --git a/src/library/scala/util/automata/WordBerrySethi.scala b/src/library/scala/util/automata/WordBerrySethi.scala index 12448f595d..2f4625da44 100644 --- a/src/library/scala/util/automata/WordBerrySethi.scala +++ b/src/library/scala/util/automata/WordBerrySethi.scala @@ -21,7 +21,7 @@ import scala.util.regexp.WordExp abstract class WordBerrySethi extends BaseBerrySethi { override val lang: WordExp - import lang.{ Alt, Eps, Letter, Meta, RegExp, Sequ, Star, _labelT } + import lang.{ Alt, Eps, Letter, RegExp, Sequ, Star, _labelT } protected var labels: mutable.HashSet[_labelT] = _ // don't let this fool you, only labelAt is a real, surjective mapping @@ -140,7 +140,6 @@ abstract class WordBerrySethi extends BaseBerrySethi { val delta1 = immutable.Map(deltaq.zipWithIndex map (_.swap): _*) val finalsArr = (0 until pos map (k => finals.getOrElse(k, 0))).toArray // 0 == not final - val initialsArr = initials.toArray val deltaArr: Array[mutable.Map[_labelT, immutable.BitSet]] = (0 until pos map { x => @@ -152,7 +151,6 @@ abstract class WordBerrySethi extends BaseBerrySethi { new NondetWordAutom[_labelT] { val nstates = pos val labels = WordBerrySethi.this.labels.toList - val initials = initialsArr val finals = finalsArr val delta = deltaArr val default = defaultArr diff --git a/src/library/scala/util/matching/Regex.scala b/src/library/scala/util/matching/Regex.scala index 716d746552..830710432c 100644 --- a/src/library/scala/util/matching/Regex.scala +++ b/src/library/scala/util/matching/Regex.scala @@ -131,7 +131,7 @@ import java.util.regex.{ Pattern, Matcher } * @author Martin Odersky * @version 1.1, 29/01/2008 * - * @param regex A string representing a regular expression + * @param pattern The compiled pattern * @param groupNames A mapping from names to indices in capture groups * * @define replacementString @@ -144,41 +144,67 @@ import java.util.regex.{ Pattern, Matcher } * to automatically escape these characters. */ @SerialVersionUID(-2094783597747625537L) -class Regex(regex: String, groupNames: String*) extends Serializable { +class Regex private[matching](val pattern: Pattern, groupNames: String*) extends Serializable { outer => import Regex._ - /** The compiled pattern */ - val pattern = Pattern.compile(regex) + /** + * @param regex A string representing a regular expression + * @param groupNames A mapping from names to indices in capture groups + */ + def this(regex: String, groupNames: String*) = this(Pattern.compile(regex), groupNames: _*) - /** Tries to match target (whole match) and returns the matching subgroups. - * if the pattern has no subgroups, then it returns an empty list on a - * successful match. - * - * Note, however, that if some subgroup has not been matched, a `null` will - * be returned for that subgroup. + /** Tries to match a [[java.lang.CharSequence]]. + * If the match succeeds, the result is a list of the matching + * groups (or a `null` element if a group did not match any input). + * If the pattern specifies no groups, then the result will be an empty list + * on a successful match. * + * This method attempts to match the entire input by default; to find the next + * matching subsequence, use an unanchored Regex. + * For example: * * {{{ * val p1 = "ab*c".r - * val p2 = "a(b*)c".r - * * val p1Matches = "abbbc" match { * case p1() => true * case _ => false * } - * + * val p2 = "a(b*)c".r * val numberOfB = "abbbc" match { * case p2(b) => Some(b.length) * case _ => None * } + * val p3 = "b*".r.unanchored + * val p3Matches = "abbbc" match { + * case p3() => true + * case _ => false + * } * }}} * - * @param target The string to match + * @param s The string to match * @return The matches */ + def unapplySeq(s: CharSequence): Option[Seq[String]] = { + val m = pattern matcher s + if (runMatcher(m)) Some(1 to m.groupCount map m.group) + else None + } + + /** Tries to match on a [[scala.util.matching.Regex.Match]]. + * A previously failed match results in None. + * If a successful match was made against the current pattern, then that result is used. + * Otherwise, this Regex is applied to the previously matched input, + * and the result of that match is used. + */ + def unapplySeq(m: Match): Option[Seq[String]] = + if (m.matched == null) None + else if (m.matcher.pattern == this.pattern) Some(1 to m.groupCount map m.group) + else unapplySeq(m.matched) + + @deprecated("Extracting a match result from anything but a CharSequence or Match is deprecated", "2.10.0") def unapplySeq(target: Any): Option[List[String]] = target match { case s: CharSequence => val m = pattern matcher s @@ -187,6 +213,8 @@ class Regex(regex: String, groupNames: String*) extends Serializable { case m: Match => unapplySeq(m.matched) case _ => None } + + // @see UnanchoredRegex protected def runMatcher(m: Matcher) = m.matches() /** Return all matches of this regexp in given character sequence as a [[scala.util.matching.Regex.MatchIterator]], @@ -200,7 +228,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @return A [[scala.util.matching.Regex.MatchIterator]] of all matches. * @example {{{for (words <- """\w+""".r findAllIn "A simple example.") yield words}}} */ - def findAllIn(source: java.lang.CharSequence) = new Regex.MatchIterator(source, this, groupNames) + def findAllIn(source: CharSequence) = new Regex.MatchIterator(source, this, groupNames) /** Return all matches of this regexp in given character sequence as a @@ -210,7 +238,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @return A [[scala.collection.Iterator]] of [[scala.util.matching.Regex.Match]] for all matches. * @example {{{for (words <- """\w+""".r findAllMatchIn "A simple example.") yield words.start}}} */ - def findAllMatchIn(source: java.lang.CharSequence): Iterator[Match] = { + def findAllMatchIn(source: CharSequence): Iterator[Match] = { val matchIterator = findAllIn(source) new Iterator[Match] { def hasNext = matchIterator.hasNext @@ -228,7 +256,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @return An [[scala.Option]] of the first matching string in the text. * @example {{{"""\w+""".r findFirstIn "A simple example." foreach println // prints "A"}}} */ - def findFirstIn(source: java.lang.CharSequence): Option[String] = { + def findFirstIn(source: CharSequence): Option[String] = { val m = pattern.matcher(source) if (m.find) Some(m.group) else None } @@ -245,7 +273,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @return A [[scala.Option]] of [[scala.util.matching.Regex.Match]] of the first matching string in the text. * @example {{{("""[a-z]""".r findFirstMatchIn "A simple example.") map (_.start) // returns Some(2), the index of the first match in the text}}} */ - def findFirstMatchIn(source: java.lang.CharSequence): Option[Match] = { + def findFirstMatchIn(source: CharSequence): Option[Match] = { val m = pattern.matcher(source) if (m.find) Some(new Match(source, m, groupNames)) else None } @@ -262,7 +290,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @return A [[scala.Option]] of the matched prefix. * @example {{{"""[a-z]""".r findPrefixOf "A simple example." // returns None, since the text does not begin with a lowercase letter}}} */ - def findPrefixOf(source: java.lang.CharSequence): Option[String] = { + def findPrefixOf(source: CharSequence): Option[String] = { val m = pattern.matcher(source) if (m.lookingAt) Some(m.group) else None } @@ -279,7 +307,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @return A [[scala.Option]] of the [[scala.util.matching.Regex.Match]] of the matched string. * @example {{{"""\w+""".r findPrefixMatchOf "A simple example." map (_.after) // returns Some(" simple example.")}}} */ - def findPrefixMatchOf(source: java.lang.CharSequence): Option[Match] = { + def findPrefixMatchOf(source: CharSequence): Option[Match] = { val m = pattern.matcher(source) if (m.lookingAt) Some(new Match(source, m, groupNames)) else None } @@ -293,7 +321,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @return The resulting string * @example {{{"""\d+""".r replaceAllIn ("July 15", "<NUMBER>") // returns "July <NUMBER>"}}} */ - def replaceAllIn(target: java.lang.CharSequence, replacement: String): String = { + def replaceAllIn(target: CharSequence, replacement: String): String = { val m = pattern.matcher(target) m.replaceAll(replacement) } @@ -316,7 +344,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @param replacer The function which maps a match to another string. * @return The target string after replacements. */ - def replaceAllIn(target: java.lang.CharSequence, replacer: Match => String): String = { + def replaceAllIn(target: CharSequence, replacer: Match => String): String = { val it = new Regex.MatchIterator(target, this, groupNames).replacementData it foreach (md => it replace replacer(md)) it.replaced @@ -343,7 +371,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @param replacer The function which optionally maps a match to another string. * @return The target string after replacements. */ - def replaceSomeIn(target: java.lang.CharSequence, replacer: Match => Option[String]): String = { + def replaceSomeIn(target: CharSequence, replacer: Match => Option[String]): String = { val it = new Regex.MatchIterator(target, this, groupNames).replacementData for (matchdata <- it ; replacement <- replacer(matchdata)) it replace replacement @@ -359,7 +387,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @param replacement The string that will replace the match * @return The resulting string */ - def replaceFirstIn(target: java.lang.CharSequence, replacement: String): String = { + def replaceFirstIn(target: CharSequence, replacement: String): String = { val m = pattern.matcher(target) m.replaceFirst(replacement) } @@ -370,7 +398,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @return The array of strings computed by splitting the * input around matches of this regexp */ - def split(toSplit: java.lang.CharSequence): Array[String] = + def split(toSplit: CharSequence): Array[String] = pattern.split(toSplit) /** Create a new Regex with the same pattern, but no requirement that @@ -390,9 +418,11 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * * @return The new unanchored regex */ - def unanchored: UnanchoredRegex = new Regex(regex, groupNames: _*) with UnanchoredRegex { override def anchored = outer } + def unanchored: UnanchoredRegex = new Regex(pattern, groupNames: _*) with UnanchoredRegex { override def anchored = outer } def anchored: Regex = this + def regex: String = pattern.pattern + /** The string defining the regular expression */ override def toString = regex } @@ -421,7 +451,7 @@ object Regex { trait MatchData { /** The source from where the match originated */ - val source: java.lang.CharSequence + val source: CharSequence /** The names of the groups, or some empty sequence if one defined */ val groupNames: Seq[String] @@ -459,25 +489,25 @@ object Regex { /** The char sequence before first character of match, * or `null` if nothing was matched */ - def before: java.lang.CharSequence = + def before: CharSequence = if (start >= 0) source.subSequence(0, start) else null /** The char sequence before first character of match in group `i`, * or `null` if nothing was matched for that group */ - def before(i: Int): java.lang.CharSequence = + def before(i: Int): CharSequence = if (start(i) >= 0) source.subSequence(0, start(i)) else null /** Returns char sequence after last character of match, * or `null` if nothing was matched */ - def after: java.lang.CharSequence = + def after: CharSequence = if (end >= 0) source.subSequence(end, source.length) else null /** The char sequence after last character of match in group `i`, * or `null` if nothing was matched for that group */ - def after(i: Int): java.lang.CharSequence = + def after(i: Int): CharSequence = if (end(i) >= 0) source.subSequence(end(i), source.length) else null @@ -501,8 +531,8 @@ object Regex { /** Provides information about a succesful match. */ - class Match(val source: java.lang.CharSequence, - matcher: Matcher, + class Match(val source: CharSequence, + private[matching] val matcher: Matcher, val groupNames: Seq[String]) extends MatchData { /** The index of the first matched character */ @@ -563,7 +593,7 @@ object Regex { /** A class to step through a sequence of regex matches */ - class MatchIterator(val source: java.lang.CharSequence, val regex: Regex, val groupNames: Seq[String]) + class MatchIterator(val source: CharSequence, val regex: Regex, val groupNames: Seq[String]) extends AbstractIterator[String] with Iterator[String] with MatchData { self => protected[Regex] val matcher = regex.pattern.matcher(source) @@ -620,7 +650,7 @@ object Regex { private[matching] trait Replacement { protected def matcher: Matcher - private var sb = new java.lang.StringBuffer + private val sb = new java.lang.StringBuffer def replaced = { val newsb = new java.lang.StringBuffer(sb) diff --git a/src/library/scala/util/parsing/combinator/JavaTokenParsers.scala b/src/library/scala/util/parsing/combinator/JavaTokenParsers.scala index 78817cfb67..89832d3fb2 100644 --- a/src/library/scala/util/parsing/combinator/JavaTokenParsers.scala +++ b/src/library/scala/util/parsing/combinator/JavaTokenParsers.scala @@ -21,11 +21,12 @@ import scala.annotation.migration * - `floatingPointNumber` */ trait JavaTokenParsers extends RegexParsers { - /** Anything starting with an ASCII alphabetic character or underscore, - * followed by zero or more repetitions of regex's `\w`. + /** Anything that is a valid Java identifier, according to + * <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.8">The Java Language Spec</a>. + * Generally, this means a letter, followed by zero or more letters or numbers. */ def ident: Parser[String] = - """[a-zA-Z_]\w*""".r + """\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*""".r /** An integer, without sign or with a negative sign. */ def wholeNumber: Parser[String] = """-?\d+""".r diff --git a/src/library/scala/util/parsing/combinator/PackratParsers.scala b/src/library/scala/util/parsing/combinator/PackratParsers.scala index 16705d45f9..cd0907e40f 100644 --- a/src/library/scala/util/parsing/combinator/PackratParsers.scala +++ b/src/library/scala/util/parsing/combinator/PackratParsers.scala @@ -8,7 +8,6 @@ package scala.util.parsing.combinator -import scala.util.parsing.combinator._ import scala.util.parsing.input.{ Reader, Position } import scala.collection.mutable import scala.language.implicitConversions diff --git a/src/library/scala/util/parsing/combinator/lexical/Scanners.scala b/src/library/scala/util/parsing/combinator/lexical/Scanners.scala index 5c23ad70cd..f6a8daabd9 100644 --- a/src/library/scala/util/parsing/combinator/lexical/Scanners.scala +++ b/src/library/scala/util/parsing/combinator/lexical/Scanners.scala @@ -6,13 +6,10 @@ ** |/ ** \* */ - - package scala.util.parsing package combinator package lexical -import token._ import input._ /** This component provides core functionality for lexical parsers. diff --git a/src/library/scala/util/parsing/combinator/lexical/StdLexical.scala b/src/library/scala/util/parsing/combinator/lexical/StdLexical.scala index f3491c096f..2fbc1ec136 100644 --- a/src/library/scala/util/parsing/combinator/lexical/StdLexical.scala +++ b/src/library/scala/util/parsing/combinator/lexical/StdLexical.scala @@ -50,7 +50,7 @@ class StdLexical extends Lexical with StdTokens { def identChar = letter | elem('_') // see `whitespace in `Scanners` - def whitespace: Parser[Any] = rep( + def whitespace: Parser[Any] = rep[Any]( whitespaceChar | '/' ~ '*' ~ comment | '/' ~ '/' ~ rep( chrExcept(EofCh, '\n') ) diff --git a/src/library/scala/util/parsing/combinator/testing/Tester.scala b/src/library/scala/util/parsing/combinator/testing/Tester.scala index 95730ee292..3cdab2a885 100644 --- a/src/library/scala/util/parsing/combinator/testing/Tester.scala +++ b/src/library/scala/util/parsing/combinator/testing/Tester.scala @@ -7,7 +7,6 @@ \* */ package scala.util.parsing.combinator.testing -import scala.util.parsing.combinator._ import scala.util.parsing.combinator.lexical.Lexical import scala.util.parsing.combinator.syntactical.TokenParsers diff --git a/src/library/scala/util/parsing/input/OffsetPosition.scala b/src/library/scala/util/parsing/input/OffsetPosition.scala index 01d9ea5cb8..6b00af4ce2 100644 --- a/src/library/scala/util/parsing/input/OffsetPosition.scala +++ b/src/library/scala/util/parsing/input/OffsetPosition.scala @@ -22,7 +22,7 @@ case class OffsetPosition(source: java.lang.CharSequence, offset: Int) extends P /** An index that contains all line starts, including first line, and eof. */ private lazy val index: Array[Int] = { - var lineStarts = new ArrayBuffer[Int] + val lineStarts = new ArrayBuffer[Int] lineStarts += 0 for (i <- 0 until source.length) if (source.charAt(i) == '\n') lineStarts += (i + 1) diff --git a/src/library/scala/util/parsing/json/JSON.scala b/src/library/scala/util/parsing/json/JSON.scala index 2f450ed864..8f951d519a 100644 --- a/src/library/scala/util/parsing/json/JSON.scala +++ b/src/library/scala/util/parsing/json/JSON.scala @@ -7,9 +7,6 @@ \* */ package scala.util.parsing.json -import scala.util.parsing.combinator._ -import scala.util.parsing.combinator.syntactical._ -import scala.util.parsing.combinator.lexical._ /** * This object provides a simple interface to the JSON parser class. diff --git a/src/library/scala/util/parsing/json/Lexer.scala b/src/library/scala/util/parsing/json/Lexer.scala index 991b5d5c6c..762c1352a7 100644 --- a/src/library/scala/util/parsing/json/Lexer.scala +++ b/src/library/scala/util/parsing/json/Lexer.scala @@ -11,7 +11,6 @@ package scala.util.parsing.json import scala.util.parsing.combinator._ -import scala.util.parsing.combinator.syntactical._ import scala.util.parsing.combinator.lexical._ import scala.util.parsing.input.CharArrayReader.EofCh diff --git a/src/library/scala/util/parsing/json/Parser.scala b/src/library/scala/util/parsing/json/Parser.scala index cb87866f07..bf1162000b 100644 --- a/src/library/scala/util/parsing/json/Parser.scala +++ b/src/library/scala/util/parsing/json/Parser.scala @@ -12,7 +12,6 @@ package scala.util.parsing.json import scala.util.parsing.combinator._ import scala.util.parsing.combinator.syntactical._ -import scala.util.parsing.combinator.lexical._ /** * A marker class for the JSON result types. diff --git a/src/library/scala/xml/Elem.scala b/src/library/scala/xml/Elem.scala index b9e665e292..fc32e45a5e 100755 --- a/src/library/scala/xml/Elem.scala +++ b/src/library/scala/xml/Elem.scala @@ -17,7 +17,7 @@ package scala.xml * @author Burak Emir <bqe@google.com> */ object Elem { - /** Build an Elem, setting its minimizeEmpty property to <code>true</code> if it has no children. Note that this + /** Build an Elem, setting its minimizeEmpty property to `true` if it has no children. Note that this * default may not be exactly what you want, as some XML dialects don't permit some elements to be minimized. * * @deprecated This factory method is retained for backward compatibility; please use the other one, with which you diff --git a/src/library/scala/xml/Node.scala b/src/library/scala/xml/Node.scala index 6b6c962692..dcd4c15969 100755 --- a/src/library/scala/xml/Node.scala +++ b/src/library/scala/xml/Node.scala @@ -55,7 +55,7 @@ abstract class Node extends NodeSeq { def scope: NamespaceBinding = TopScope /** - * convenience, same as <code>getNamespace(this.prefix)</code> + * convenience, same as `getNamespace(this.prefix)` */ def namespace = getNamespace(this.prefix) @@ -64,8 +64,8 @@ abstract class Node extends NodeSeq { * checks if scope is `'''null'''`. * * @param pre the prefix whose namespace name we would like to obtain - * @return the namespace if <code>scope != null</code> and prefix was - * found, else <code>null</code> + * @return the namespace if `scope != null` and prefix was + * found, else `null` */ def getNamespace(pre: String): String = if (scope eq null) null else scope.getURI(pre) @@ -74,8 +74,8 @@ abstract class Node extends NodeSeq { * Same as `attributes.getValue(key)` * * @param key of queried attribute. - * @return value of <code>UnprefixedAttribute</code> with given key - * in attributes, if it exists, otherwise <code>null</code>. + * @return value of `UnprefixedAttribute` with given key + * in attributes, if it exists, otherwise `null`. */ final def attribute(key: String): Option[Seq[Node]] = attributes.get(key) diff --git a/src/library/scala/xml/PrettyPrinter.scala b/src/library/scala/xml/PrettyPrinter.scala index 39ff8c35ec..f9157802c6 100755 --- a/src/library/scala/xml/PrettyPrinter.scala +++ b/src/library/scala/xml/PrettyPrinter.scala @@ -47,7 +47,6 @@ class PrettyPrinter(width: Int, step: Int) { val tmp = width - cur if (s.length <= tmp) return List(Box(ind, s)) - val sb = new StringBuilder() var i = s indexOf ' ' if (i > tmp || i == -1) throw new BrokenException() // cannot break diff --git a/src/library/scala/xml/XML.scala b/src/library/scala/xml/XML.scala index d101684459..ec5e5e9e1c 100755 --- a/src/library/scala/xml/XML.scala +++ b/src/library/scala/xml/XML.scala @@ -45,8 +45,6 @@ object MinimizeMode extends Enumeration { val Never = Value } -import Source._ - /** The object `XML` provides constants, and functions to load * and save XML elements. Use this when data binding is not desired, i.e. * when XML is handled using `Symbol` nodes. diff --git a/src/library/scala/xml/dtd/DocType.scala b/src/library/scala/xml/dtd/DocType.scala index 79f8f9fe8b..ce067bee79 100644 --- a/src/library/scala/xml/dtd/DocType.scala +++ b/src/library/scala/xml/dtd/DocType.scala @@ -15,7 +15,7 @@ package dtd * @author Burak Emir * * @param name name of this DOCTYPE - * @param extID None, or Some(external ID of this doctype) + * @param extID NoExternalID or the external ID of this doctype * @param intSubset sequence of internal subset declarations */ case class DocType(name: String, extID: ExternalID, intSubset: Seq[dtd.Decl]) @@ -32,3 +32,9 @@ case class DocType(name: String, extID: ExternalID, intSubset: Seq[dtd.Decl]) """<!DOCTYPE %s %s%s>""".format(name, extID.toString, intString) } } + +object DocType +{ + /** Creates a doctype with no external id, nor internal subset declarations. */ + def apply(name: String): DocType = apply(name, NoExternalID, Nil) +} diff --git a/src/library/scala/xml/dtd/ElementValidator.scala b/src/library/scala/xml/dtd/ElementValidator.scala index bfc85f48a9..66951bf390 100644 --- a/src/library/scala/xml/dtd/ElementValidator.scala +++ b/src/library/scala/xml/dtd/ElementValidator.scala @@ -61,7 +61,7 @@ class ElementValidator() extends Function1[Node,Boolean] { */ def check(md: MetaData): Boolean = { val len: Int = exc.length - var ok = new mutable.BitSet(adecls.length) + val ok = new mutable.BitSet(adecls.length) for (attr <- md) { def attrStr = attr.value.toString diff --git a/src/library/scala/xml/dtd/ExternalID.scala b/src/library/scala/xml/dtd/ExternalID.scala index 7a7463569e..e346f89d0a 100644 --- a/src/library/scala/xml/dtd/ExternalID.scala +++ b/src/library/scala/xml/dtd/ExternalID.scala @@ -73,3 +73,14 @@ case class PublicID(publicId: String, systemId: String) extends ExternalID { /** always empty */ def child = Nil } + +/** A marker used when a `DocType` contains no external id. + * + * @author Michael Bayne + */ +object NoExternalID extends ExternalID { + val publicId = null + val systemId = null + + override def toString = "" +} diff --git a/src/library/scala/xml/factory/XMLLoader.scala b/src/library/scala/xml/factory/XMLLoader.scala index 72e4c51b11..efa241e388 100644 --- a/src/library/scala/xml/factory/XMLLoader.scala +++ b/src/library/scala/xml/factory/XMLLoader.scala @@ -12,7 +12,7 @@ package factory import javax.xml.parsers.SAXParserFactory import parsing.{ FactoryAdapter, NoBindingFactoryAdapter } -import java.io.{ InputStream, Reader, StringReader, File, FileDescriptor, FileInputStream } +import java.io.{ InputStream, Reader, File, FileDescriptor } import java.net.URL /** Presents collection of XML loading methods which use the parser diff --git a/src/library/scala/xml/include/sax/EncodingHeuristics.scala b/src/library/scala/xml/include/sax/EncodingHeuristics.scala index 1340689cae..8d8ce5b290 100644 --- a/src/library/scala/xml/include/sax/EncodingHeuristics.scala +++ b/src/library/scala/xml/include/sax/EncodingHeuristics.scala @@ -6,10 +6,8 @@ ** |/ ** \* */ - package scala.xml package include.sax -import scala.xml.include._ import java.io.InputStream import scala.util.matching.Regex diff --git a/src/library/scala/xml/include/sax/XIncludeFilter.scala b/src/library/scala/xml/include/sax/XIncludeFilter.scala index 729769366e..103cddcb11 100644 --- a/src/library/scala/xml/include/sax/XIncludeFilter.scala +++ b/src/library/scala/xml/include/sax/XIncludeFilter.scala @@ -275,7 +275,7 @@ class XIncludeFilter extends XMLFilterImpl { try { val uc = source.openConnection() val in = new BufferedInputStream(uc.getInputStream()) - var encodingFromHeader = uc.getContentEncoding() + val encodingFromHeader = uc.getContentEncoding() var contentType = uc.getContentType() if (encodingFromHeader != null) encoding = encodingFromHeader diff --git a/src/library/scala/xml/include/sax/XIncluder.scala b/src/library/scala/xml/include/sax/XIncluder.scala index 5064d6b3d8..81c5613541 100644 --- a/src/library/scala/xml/include/sax/XIncluder.scala +++ b/src/library/scala/xml/include/sax/XIncluder.scala @@ -6,11 +6,9 @@ ** |/ ** \* */ - package scala.xml package include.sax -import scala.xml.include._ import scala.collection.mutable import org.xml.sax.{ ContentHandler, XMLReader, Locator, Attributes } import org.xml.sax.ext.LexicalHandler diff --git a/src/library/scala/xml/parsing/MarkupParser.scala b/src/library/scala/xml/parsing/MarkupParser.scala index f9ff54d054..6b8f58dca3 100755 --- a/src/library/scala/xml/parsing/MarkupParser.scala +++ b/src/library/scala/xml/parsing/MarkupParser.scala @@ -154,7 +154,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests var info_enc: Option[String] = None var info_stdl: Option[Boolean] = None - var m = xmlProcInstr() + val m = xmlProcInstr() var n = 0 if (isProlog) @@ -303,10 +303,8 @@ trait MarkupParser extends MarkupParserCommon with TokenTests var scope: NamespaceBinding = pscope var aMap: MetaData = Null while (isNameStart(ch)) { - val pos = this.pos - val qname = xName - val _ = xEQ + xEQ // side effect val value = xAttributeValue() Utility.prefix(qname) match { @@ -423,7 +421,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests * content1 ::= '<' content1 | '&' charref ... * }}} */ def content(pscope: NamespaceBinding): NodeSeq = { - var ts = new NodeBuffer + val ts = new NodeBuffer var exit = eof // todo: optimize seq repr. def done = new NodeSeq { val theSeq = ts.toList } @@ -582,7 +580,6 @@ trait MarkupParser extends MarkupParserCommon with TokenTests var exit = false while (! exit) { putChar(ch) - val opos = pos nextch exit = eof || ( ch == '<' ) || ( ch == '&' ) @@ -828,7 +825,6 @@ trait MarkupParser extends MarkupParserCommon with TokenTests * }}} */ def entityDecl() = { var isParameterEntity = false - var entdef: EntityDef = null xToken("NTITY") xSpace if ('%' == ch) { diff --git a/src/library/scala/xml/parsing/MarkupParserCommon.scala b/src/library/scala/xml/parsing/MarkupParserCommon.scala index da640484e0..43ec539931 100644 --- a/src/library/scala/xml/parsing/MarkupParserCommon.scala +++ b/src/library/scala/xml/parsing/MarkupParserCommon.scala @@ -10,7 +10,6 @@ package scala.xml package parsing import scala.io.Source -import scala.xml.dtd._ import scala.annotation.switch import Utility.Escapes.{ pairs => unescape } diff --git a/src/library/scala/xml/persistent/SetStorage.scala b/src/library/scala/xml/persistent/SetStorage.scala index 20a5bb6767..d16c71c9f7 100644 --- a/src/library/scala/xml/persistent/SetStorage.scala +++ b/src/library/scala/xml/persistent/SetStorage.scala @@ -20,16 +20,14 @@ import java.io.File */ class SetStorage(file: File) extends CachedFileStorage(file) { - private var theSet: mutable.HashSet[Node] = new mutable.HashSet[Node] + private val theSet = mutable.HashSet[Node]() // initialize { val it = super.initialNodes dirty = it.hasNext - for(x <- it) { - theSet += x; - } + theSet ++= it } /* forwarding methods to hashset*/ diff --git a/src/library/scala/xml/transform/RewriteRule.scala b/src/library/scala/xml/transform/RewriteRule.scala index 1dca495a10..13210a6fd2 100644 --- a/src/library/scala/xml/transform/RewriteRule.scala +++ b/src/library/scala/xml/transform/RewriteRule.scala @@ -11,8 +11,8 @@ package scala.xml package transform -/** a RewriteRule, when applied to a term, yields either - * the resulting of rewriting or the term itself it the rule +/** A RewriteRule, when applied to a term, yields either + * the result of rewriting the term or the term itself if the rule * is not applied. * * @author Burak Emir diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/AssemblyBuilder.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/AssemblyBuilder.scala index 3110ccd1ce..6bf4c7d1da 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/emit/AssemblyBuilder.scala +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/AssemblyBuilder.scala @@ -75,9 +75,6 @@ class AssemblyBuilder(name: AssemblyName) //########################################################################## // protected members - // the access properties - Save, Run, RunAndSave - private var access : Int = _ - // all extern assemblies used in this assembly builder protected var externAssemblies = scala.collection.mutable.Set.empty[Assembly] diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/ILGenerator.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/ILGenerator.scala index 2aa9a99054..63ecbfd353 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/emit/ILGenerator.scala +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/ILGenerator.scala @@ -452,7 +452,7 @@ import ILGenerator._ private var locals: Int = 0 // stack of label for exception mechanism - private var excStack: ExceptionStack = new ExceptionStack() + private val excStack: ExceptionStack = new ExceptionStack() // the method info owner of this ILGenerator var owner: MethodBase = _owner diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/ILPrinterVisitor.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/ILPrinterVisitor.scala index 0ed5e3f3bb..413b08ddd8 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/emit/ILPrinterVisitor.scala +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/ILPrinterVisitor.scala @@ -96,7 +96,7 @@ abstract class ILPrinterVisitor extends Visitor { protected def println(s: String){ print(s); println() } protected def println(o: Object){ print(o); println() } protected def printName(name: String) { - var ch = name.charAt(0) + val ch = name.charAt(0) //if (Character.isLetter(ch) && Character.isLowerCase(ch)) { if ((ch != '.') && (ch != '!')) { print('\''); print(name); print('\'') @@ -174,7 +174,6 @@ abstract class ILPrinterVisitor extends Visitor { print(constraintFlags(tVar)) if(tVar.Constraints.length > 0) { print('(') - val lastCnstrtIdx = tVar.Constraints.length - 1 for (ic <- 0 until tVar.Constraints.length) { val cnstrt = tVar.Constraints(ic) printReference(cnstrt) @@ -211,7 +210,7 @@ abstract class ILPrinterVisitor extends Visitor { print(" extends ") printReference(`type`.BaseType()) } - var ifaces: Array[Type] = `type`.getInterfaces() + val ifaces: Array[Type] = `type`.getInterfaces() if (ifaces.length > 0) { println() print(" implements ") @@ -331,7 +330,7 @@ abstract class ILPrinterVisitor extends Visitor { def msilSyntaxDouble(valDou: java.lang.Double) : String = { // !!! check if encoding is correct - var bits = java.lang.Double.doubleToRawLongBits(valDou.doubleValue()) + val bits = java.lang.Double.doubleToRawLongBits(valDou.doubleValue()) /* see p. 170 in Lidin's book Expert .NET 2.0 IL Assembler */ /* Note: no value is equal to Nan, including NaN. Thus, x == Double.NaN always evaluates to false. */ val res = if (valDou.isNaN) "0xffffffffffffffff /* NaN */ " /* TODO this is 'quiet NaN, http://www.savrola.com/resources/NaN.html , what's the difference with a 'signaling NaN'?? */ @@ -452,7 +451,7 @@ abstract class ILPrinterVisitor extends Visitor { */ @throws(classOf[IOException]) def caseOpCode(opCode: OpCode) { - var opString = opCode.toString() + val opString = opCode.toString() print(opString) pad(14 - opString.length()) @@ -661,7 +660,7 @@ abstract class ILPrinterVisitor extends Visitor { print(' '); printReference(method.DeclaringType) print("::"); printName(method.Name) - var params = method.GetParameters() + val params = method.GetParameters() print("(") for (i <- 0 until params.length) { if (i > 0) print(", ") @@ -744,7 +743,7 @@ abstract class ILPrinterVisitor extends Visitor { } def printAttributes(icap: ICustomAttributeProvider) { - var attrs = icap.GetCustomAttributes(false) + val attrs = icap.GetCustomAttributes(false) for (i <- 0 until attrs.length) { print(".custom ") printSignature((attrs(i).asInstanceOf[Attribute]).getConstructor()) @@ -767,7 +766,7 @@ object ILPrinterVisitor { def hasControlChars(str: String): Boolean = { for(i <- 0 until str.length()) { - var ch = str.charAt(i) + val ch = str.charAt(i) ch match { case '\b' => case '\t' => @@ -789,7 +788,7 @@ object ILPrinterVisitor { case e : java.io.UnsupportedEncodingException => throw new RuntimeException(e) } } - var str = new StringBuffer(s) + val str = new StringBuffer(s) var ss = EMPTY var i = 0 while(i < str.length()) { @@ -834,7 +833,7 @@ object ILPrinterVisitor { final var primitive = scala.collection.mutable.Map.empty[Type, String] def addPrimitive(name: String, sig: String) { - var `type` = + val `type` = Type.GetType(name) assert(`type` != null, "Cannot lookup primitive type " + `type`) primitive.put(`type`, sig) diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/Label.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/Label.scala index 22c1b1150b..a80ea72323 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/emit/Label.scala +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/Label.scala @@ -107,16 +107,15 @@ object Label { //######################################################################## // Special Labels - final class SpecialLabel(_kind: Label.Kind) extends Label { - private final var kind: Label.Kind = _kind + final class SpecialLabel(kind: Label.Kind) extends Label { def isInitialized() = true - def getAddress(): Int = { throw new RuntimeException("" + kind.toString()) } - def getStacksize(): Int = { throw new RuntimeException("" + kind.toString()) } - def setStacksize(stacksize: Int) { throw new RuntimeException(kind.toString()) } - def incStacksize() { throw new RuntimeException(kind.toString()) } + def getAddress(): Int = { throw new RuntimeException("" + kind) } + def getStacksize(): Int = { throw new RuntimeException("" + kind) } + def setStacksize(stacksize: Int) { throw new RuntimeException("" + kind) } + def incStacksize() { throw new RuntimeException("" + kind) } def getKind(): Kind = kind - def mergeWith(that: Label) { throw new RuntimeException(kind.toString()) } - override def toString(): String = "Label(" + kind.toString() + ")" + def mergeWith(that: Label) { throw new RuntimeException("" + kind) } + override def toString() = s"Label($kind)" } final val NewScope: Label = new SpecialLabel(Kind.NewScope) diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/ModuleBuilder.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/ModuleBuilder.scala index 981e855e0e..2319d5ca27 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/emit/ModuleBuilder.scala +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/ModuleBuilder.scala @@ -73,7 +73,7 @@ class ModuleBuilder(name: String, fullname: String, scopeName: String, assembly: baseType: Type, interfaces: Array[Type]): TypeBuilder = { - var t: Type = GetType(typeName) // Module.GetType(String) + val t: Type = GetType(typeName) // Module.GetType(String) if (t != null) throw new RuntimeException ("Type [" + Assembly + "]" + typeName + "' already exists!") diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/MultipleFilesILPrinterVisitor.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/MultipleFilesILPrinterVisitor.scala index 55c52109b6..bbbbf40508 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/emit/MultipleFilesILPrinterVisitor.scala +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/MultipleFilesILPrinterVisitor.scala @@ -41,7 +41,7 @@ final class MultipleFilesILPrinterVisitor(destPath: String, sourceFilesPath: Str scala.util.Sorting.quickSort(as)(assemblyNameComparator) // Arrays.sort(as, assemblyNameComparator) // print each module - var m: Array[Module] = assemblyBuilder.GetModules() + val m: Array[Module] = assemblyBuilder.GetModules() nomembers = true for(i <- 0 until m.length) { print(m(i).asInstanceOf[ModuleBuilder]) @@ -68,10 +68,10 @@ final class MultipleFilesILPrinterVisitor(destPath: String, sourceFilesPath: Str if (!module.globalsCreated) module.CreateGlobalFunctions() - var m: Array[MethodInfo] = module.GetMethods() + val m: Array[MethodInfo] = module.GetMethods() // "Types" contain all the classes - var t: Array[Type] = module.GetTypes() + val t: Array[Type] = module.GetTypes() for(i <- 0 until t.length) { val tBuilder = t(i).asInstanceOf[TypeBuilder] val sourceFilename = tBuilder.sourceFilename @@ -108,7 +108,7 @@ final class MultipleFilesILPrinterVisitor(destPath: String, sourceFilesPath: Str // now write the global methods (typically contains the "main" method) if(!nomembers) { - var globalMethods: File = new File(destPath, ILPrinterVisitor.currAssembly.GetName().Name + ".msil") + val globalMethods: File = new File(destPath, ILPrinterVisitor.currAssembly.GetName().Name + ".msil") val append = assemblyBuilder.generatedFiles.contains(globalMethods.getPath) out = new PrintWriter(new BufferedWriter(new FileWriter(globalMethods, append))) diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/SingleFileILPrinterVisitor.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/SingleFileILPrinterVisitor.scala index 5d59d4d25a..50e9f45373 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/emit/SingleFileILPrinterVisitor.scala +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/SingleFileILPrinterVisitor.scala @@ -48,7 +48,7 @@ final class SingleFileILPrinterVisitor(_fileName: String) extends ILPrinterVisit printAssemblyBoilerplate() // print each module - var m: Array[Module] = assemblyBuilder.GetModules() + val m: Array[Module] = assemblyBuilder.GetModules() nomembers = true for(i <- 0 until m.length) { print(m(i).asInstanceOf[ModuleBuilder]) @@ -78,12 +78,12 @@ final class SingleFileILPrinterVisitor(_fileName: String) extends ILPrinterVisit if (!module.globalsCreated) module.CreateGlobalFunctions() - var m: Array[MethodInfo] = module.GetMethods() + val m: Array[MethodInfo] = module.GetMethods() for(i <- 0 until m.length) { print(m(i).asInstanceOf[MethodBuilder]) } - var t: Array[Type] = module.GetTypes() + val t: Array[Type] = module.GetTypes() for(i <- 0 until t.length) { print(t(i).asInstanceOf[TypeBuilder]) } diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/TypeBuilder.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/TypeBuilder.scala index 57dc883898..0b0b16da65 100644 --- a/src/msil/ch/epfl/lamp/compiler/msil/emit/TypeBuilder.scala +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/TypeBuilder.scala @@ -221,7 +221,7 @@ class TypeBuilder (module: Module, attributes: Int, fullName: String, baseType: object TypeBuilder { def types2String(types: Array[Type]): String = { - var s = new StringBuffer("(") + val s = new StringBuffer("(") for(i <- 0 until types.length) { if (i > 0) s.append(", ") s.append(types(i)) diff --git a/src/partest/scala/tools/partest/CompilerTest.scala b/src/partest/scala/tools/partest/CompilerTest.scala index d73d99bc89..bb0732dcc6 100644 --- a/src/partest/scala/tools/partest/CompilerTest.scala +++ b/src/partest/scala/tools/partest/CompilerTest.scala @@ -21,7 +21,7 @@ abstract class CompilerTest extends DirectTest { lazy val global: Global = newCompiler() lazy val units = compilationUnits(global)(sources: _ *) import global._ - import definitions._ + import definitions.{ compilerTypeFromTag } override def extraSettings = "-usejavacp -d " + testOutput.path @@ -32,7 +32,6 @@ abstract class CompilerTest extends DirectTest { def sources: List[String] = List(code) // Utility functions - class MkType(sym: Symbol) { def apply[M](implicit t: ru.TypeTag[M]): Type = if (sym eq NoSymbol) NoType diff --git a/src/partest/scala/tools/partest/PartestDefaults.scala b/src/partest/scala/tools/partest/PartestDefaults.scala index b27ce6ff75..e3f1cb8bd9 100644 --- a/src/partest/scala/tools/partest/PartestDefaults.scala +++ b/src/partest/scala/tools/partest/PartestDefaults.scala @@ -8,8 +8,6 @@ import java.lang.Runtime.getRuntime object PartestDefaults { import nsc.Properties._ - private def wrapAccessControl[T](body: => Option[T]): Option[T] = - try body catch { case _: java.security.AccessControlException => None } def testRootName = propOrNone("partest.root") def srcDirName = propOrElse("partest.srcdir", "files") diff --git a/src/partest/scala/tools/partest/PartestTask.scala b/src/partest/scala/tools/partest/PartestTask.scala index d9f2bfe765..41d69a5448 100644 --- a/src/partest/scala/tools/partest/PartestTask.scala +++ b/src/partest/scala/tools/partest/PartestTask.scala @@ -182,7 +182,6 @@ class PartestTask extends Task with CompilationPathProperty { private var javaccmd: Option[File] = None private var showDiff: Boolean = false private var showLog: Boolean = false - private var runFailed: Boolean = false private var posFiles: Option[FileSet] = None private var negFiles: Option[FileSet] = None private var runFiles: Option[FileSet] = None @@ -345,7 +344,6 @@ class PartestTask extends Task with CompilationPathProperty { antFileManager.showDiff = showDiff antFileManager.showLog = showLog - antFileManager.failed = runFailed antFileManager.CLASSPATH = ClassPath.join(classpath.list: _*) antFileManager.LATEST_LIB = scalaLibrary.getAbsolutePath antFileManager.LATEST_REFLECT = scalaReflect.getAbsolutePath diff --git a/src/partest/scala/tools/partest/ScaladocModelTest.scala b/src/partest/scala/tools/partest/ScaladocModelTest.scala index e7134d0271..acaddff944 100644 --- a/src/partest/scala/tools/partest/ScaladocModelTest.scala +++ b/src/partest/scala/tools/partest/ScaladocModelTest.scala @@ -5,8 +5,6 @@ package scala.tools.partest -import scala.tools.partest._ -import java.io._ import scala.tools.nsc._ import scala.tools.nsc.util.CommandLineParser import scala.tools.nsc.doc.{Settings, DocFactory, Universe} @@ -87,7 +85,7 @@ abstract class ScaladocModelTest extends DirectTest { settings = new Settings(_ => ()) settings.scaladocQuietRun = true // yaay, no more "model contains X documentable templates"! val args = extraSettings + " " + scaladocSettings - val command = new ScalaDoc.Command((CommandLineParser tokenize (args)), settings) + new ScalaDoc.Command((CommandLineParser tokenize (args)), settings) // side-effecting, I think val docFact = new DocFactory(new ConsoleReporter(settings), settings) docFact } diff --git a/src/partest/scala/tools/partest/SecurityTest.scala b/src/partest/scala/tools/partest/SecurityTest.scala index 2d6f61d0b1..1f1c8a95ea 100644 --- a/src/partest/scala/tools/partest/SecurityTest.scala +++ b/src/partest/scala/tools/partest/SecurityTest.scala @@ -10,23 +10,10 @@ import java.util._ abstract class SecurityTest extends App { def throwIt(x: Any) = throw new AccessControlException("" + x) - - def readPerm(p: PropertyPermission) = p.getActions contains "read" - def writePerm(p: PropertyPermission) = p.getActions contains "write" def propertyCheck(p: PropertyPermission): Unit = throwIt(p) def check(perm: Permission): Unit = perm match { case p: PropertyPermission => propertyCheck(p) case _ => () } - - lazy val sm = new SecurityManager { - // these two are the choke points for all permissions checks - override def checkPermission(perm: Permission): Unit = check(perm) - override def checkPermission(perm: Permission, context: Object): Unit = check(perm) - } - def securityOn(): Boolean = { - try { System.setSecurityManager(sm) ; true } - catch { case _: SecurityException => false } - } } diff --git a/src/partest/scala/tools/partest/TestUtil.scala b/src/partest/scala/tools/partest/TestUtil.scala index 9bfd444180..5c177ac962 100644 --- a/src/partest/scala/tools/partest/TestUtil.scala +++ b/src/partest/scala/tools/partest/TestUtil.scala @@ -24,14 +24,6 @@ trait TestUtil { } def nanos(body: => Unit): Long = alsoNanos(body)._1 - def verifySpeed(body1: => Unit, body2: => Unit, acceptableMultiple: Double) = { - val t1 = nanos(body1).toDouble - val t2 = nanos(body2).toDouble - val mult = if (t1 > t2) t1 / t2 else t2 / t1 - - assert(mult <= acceptableMultiple, "Performance difference too great: multiple = " + mult) - } - def intercept[T <: Exception : ClassTag](code: => Unit): Unit = try { code @@ -41,6 +33,6 @@ trait TestUtil { } } +// Used in tests. object TestUtil extends TestUtil { - } diff --git a/src/partest/scala/tools/partest/instrumented/Instrumentation.scala b/src/partest/scala/tools/partest/instrumented/Instrumentation.scala index 8a284b313b..18dd740208 100644 --- a/src/partest/scala/tools/partest/instrumented/Instrumentation.scala +++ b/src/partest/scala/tools/partest/instrumented/Instrumentation.scala @@ -78,6 +78,7 @@ object Instrumentation { !t.className.startsWith("scala/util/DynamicVariable") } + // Used in tests. def printStatistics(stats: Statistics = getStatistics, filter: MethodCallTrace => Boolean = standardFilter): Unit = { val stats = getStatistics println("Method call statistics:") diff --git a/src/partest/scala/tools/partest/javaagent/ASMTransformer.java b/src/partest/scala/tools/partest/javaagent/ASMTransformer.java index 494a5a99be..b6bec2f598 100644 --- a/src/partest/scala/tools/partest/javaagent/ASMTransformer.java +++ b/src/partest/scala/tools/partest/javaagent/ASMTransformer.java @@ -26,9 +26,35 @@ public class ASMTransformer implements ClassFileTransformer { className.startsWith("instrumented/")); } - public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { + public byte[] transform(final ClassLoader classLoader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { if (shouldTransform(className)) { - ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) { + // this is copied verbatim from the superclass, + // except that we use the outer class loader + @Override protected String getCommonSuperClass(final String type1, final String type2) { + Class<?> c, d; + try { + c = Class.forName(type1.replace('/', '.'), false, classLoader); + d = Class.forName(type2.replace('/', '.'), false, classLoader); + } catch (Exception e) { + throw new RuntimeException(e.toString()); + } + if (c.isAssignableFrom(d)) { + return type1; + } + if (d.isAssignableFrom(c)) { + return type2; + } + if (c.isInterface() || d.isInterface()) { + return "java/lang/Object"; + } else { + do { + c = c.getSuperclass(); + } while (!c.isAssignableFrom(d)); + return c.getName().replace('.', '/'); + } + } + }; ProfilerVisitor visitor = new ProfilerVisitor(writer); ClassReader reader = new ClassReader(classfileBuffer); reader.accept(visitor, 0); diff --git a/src/partest/scala/tools/partest/nest/CompileManager.scala b/src/partest/scala/tools/partest/nest/CompileManager.scala index 188ebf66ed..3f005d143e 100644 --- a/src/partest/scala/tools/partest/nest/CompileManager.scala +++ b/src/partest/scala/tools/partest/nest/CompileManager.scala @@ -71,7 +71,6 @@ class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler { } private def updatePluginPath(options: String): String = { - val dir = fileManager.testRootDir def absolutize(path: String) = Path(path) match { case x if x.isAbsolute => x.path case x => (fileManager.testRootDir / x).toAbsolute.path diff --git a/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala b/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala index 08e709de90..7000e8280b 100644 --- a/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala +++ b/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala @@ -18,8 +18,6 @@ import io.{ Path, Directory } import File.pathSeparator import ClassPath.{ join } import PathResolver.{ Environment, Defaults } -import RunnerUtils._ - class ConsoleFileManager extends FileManager { var testBuild: Option[String] = PartestDefaults.testBuild @@ -81,7 +79,6 @@ class ConsoleFileManager extends FileManager { testClassesDir = Path(testClasses.get).toCanonical.toDirectory NestUI.verbose("Running with classes in "+testClassesDir) - latestFile = testClassesDir.parent / "bin" latestLibFile = testClassesDir / "library" latestActorsFile = testClassesDir / "library" / "actors" latestReflectFile = testClassesDir / "reflect" @@ -92,7 +89,6 @@ class ConsoleFileManager extends FileManager { else if (testBuild.isDefined) { val dir = Path(testBuild.get) NestUI.verbose("Running on "+dir) - latestFile = dir / "bin" latestLibFile = dir / "lib/scala-library.jar" latestActorsFile = dir / "lib/scala-actors.jar" latestReflectFile = dir / "lib/scala-reflect.jar" @@ -103,7 +99,6 @@ class ConsoleFileManager extends FileManager { else { def setupQuick() { NestUI.verbose("Running build/quick") - latestFile = prefixFile("build/quick/bin") latestLibFile = prefixFile("build/quick/classes/library") latestActorsFile = prefixFile("build/quick/classes/library/actors") latestReflectFile = prefixFile("build/quick/classes/reflect") @@ -114,7 +109,6 @@ class ConsoleFileManager extends FileManager { def setupInst() { NestUI.verbose("Running dist (installed)") val p = testParent.getParentFile - latestFile = prefixFileWith(p, "bin") latestLibFile = prefixFileWith(p, "lib/scala-library.jar") latestActorsFile = prefixFileWith(p, "lib/scala-actors.jar") latestReflectFile = prefixFileWith(p, "lib/scala-reflect.jar") @@ -124,7 +118,6 @@ class ConsoleFileManager extends FileManager { def setupDist() { NestUI.verbose("Running dists/latest") - latestFile = prefixFile("dists/latest/bin") latestLibFile = prefixFile("dists/latest/lib/scala-library.jar") latestActorsFile = prefixFile("dists/latest/lib/scala-actors.jar") latestReflectFile = prefixFile("dists/latest/lib/scala-reflect.jar") @@ -134,7 +127,6 @@ class ConsoleFileManager extends FileManager { def setupPack() { NestUI.verbose("Running build/pack") - latestFile = prefixFile("build/pack/bin") latestLibFile = prefixFile("build/pack/lib/scala-library.jar") latestActorsFile = prefixFile("build/pack/lib/scala-actors.jar") latestReflectFile = prefixFile("build/pack/lib/scala-reflect.jar") @@ -142,11 +134,6 @@ class ConsoleFileManager extends FileManager { latestPartestFile = prefixFile("build/pack/lib/scala-partest.jar") } - val dists = testParent / "dists" - val build = testParent / "build" - // in case of an installed dist, testRootDir is one level deeper - val bin = testParent.parent / "bin" - def mostRecentOf(base: String, names: String*) = names map (x => prefixFile(base + "/" + x).lastModified) reduceLeft (_ max _) @@ -182,7 +169,6 @@ class ConsoleFileManager extends FileManager { var LATEST_PARTEST: String = "" var LATEST_ACTORS: String = "" - var latestFile: File = _ var latestLibFile: File = _ var latestActorsFile: File = _ var latestReflectFile: File = _ @@ -194,8 +180,6 @@ class ConsoleFileManager extends FileManager { // initialize above fields findLatest() - var testFiles: List[io.Path] = Nil - def getFiles(kind: String, cond: Path => Boolean): List[File] = { def ignoreDir(p: Path) = List("svn", "obj") exists (p hasExtension _) @@ -204,9 +188,7 @@ class ConsoleFileManager extends FileManager { if (dir.isDirectory) NestUI.verbose("look in %s for tests" format dir) else NestUI.failure("Directory '%s' not found" format dir) - val files = - if (testFiles.nonEmpty) testFiles filter (_.parent isSame dir) - else dir.list filterNot ignoreDir filter cond toList + val files = dir.list filterNot ignoreDir filter cond toList ( if (failed) files filter (x => logFileExists(x, kind)) else files ) map (_.jfile) } diff --git a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala index e016fb7c92..d146618d0e 100644 --- a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala +++ b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala @@ -11,7 +11,6 @@ package nest import java.io.{File, PrintStream, FileOutputStream, BufferedReader, InputStreamReader, StringWriter, PrintWriter} import utils.Properties._ -import RunnerUtils._ import scala.tools.nsc.Properties.{ versionMsg, setProp } import scala.tools.nsc.util.CommandLineParser import scala.tools.nsc.io @@ -26,8 +25,6 @@ class ConsoleRunner extends DirectRunner { private def antFilter(p: Path) = p.isFile && (p endsWith "build.xml") val testSets = { - val pathFilter: Path => Boolean = x => x.isDirectory || (x hasExtension "scala") - List( TestSet("pos", stdFilter, "Testing compiler (on files whose compilation should succeed)"), TestSet("neg", stdFilter, "Testing compiler (on files whose compilation should fail)"), @@ -54,8 +51,6 @@ class ConsoleRunner extends DirectRunner { private val testSetArgs = testSets map ("--" + _.kind) private val testSetArgMap = testSetArgs zip testSets toMap - def denotesTestSet(arg: String) = testSetArgs contains arg - private def printVersion() { NestUI outline (versionMsg + "\n") } private val unaryArgs = List( @@ -70,10 +65,11 @@ class ConsoleRunner extends DirectRunner { // true if a test path matches the --grep expression. private def pathMatchesExpr(path: Path, expr: String) = { def pred(p: Path) = file2String(p.toFile) contains expr - def srcs = path.toDirectory.deepList() filter (_.hasExtension("scala", "java")) + def greppable(f: Path) = f.isFile && (f hasExtension ("scala", "java")) + def any(d: Path) = d.toDirectory.deepList() exists (f => greppable(f) && pred(f)) (path.isFile && pred(path)) || - (path.isDirectory && srcs.exists(pred)) || + (path.isDirectory && any(path)) || (pred(path changeExtension "check")) } @@ -94,8 +90,6 @@ class ConsoleRunner extends DirectRunner { else if (parsed isSet "--pack") new ConsoleFileManager("build/pack") else new ConsoleFileManager // auto detection, see ConsoleFileManager.findLatest - def argNarrowsTests(x: String) = denotesTestSet(x) || denotesTestPath(x) - NestUI._verbose = parsed isSet "--verbose" fileManager.showDiff = true // parsed isSet "--show-diff" @@ -121,7 +115,7 @@ class ConsoleRunner extends DirectRunner { val grepOption = parsed get "--grep" val grepPaths = grepOption.toList flatMap { expr => val subjectDirs = testSetKinds map (srcDir / _ toDirectory) - val testPaths = subjectDirs flatMap (_.files filter stdFilter) + val testPaths = subjectDirs flatMap (_.list filter stdFilter) val paths = testPaths filter (p => pathMatchesExpr(p, expr)) if (paths.isEmpty) diff --git a/src/partest/scala/tools/partest/nest/DirectRunner.scala b/src/partest/scala/tools/partest/nest/DirectRunner.scala index 32ef8b41ea..3aaf784cad 100644 --- a/src/partest/scala/tools/partest/nest/DirectRunner.scala +++ b/src/partest/scala/tools/partest/nest/DirectRunner.scala @@ -14,7 +14,6 @@ import scala.tools.nsc.util.ScalaClassLoader import scala.tools.nsc.io.Path import scala.collection.{ mutable, immutable } import java.util.concurrent._ -import scala.collection.convert.decorateAll._ case class TestRunParams(val scalaCheckParentClassLoader: ScalaClassLoader) diff --git a/src/partest/scala/tools/partest/nest/FileManager.scala b/src/partest/scala/tools/partest/nest/FileManager.scala index 2823967ecf..a4c4e7e6a6 100644 --- a/src/partest/scala/tools/partest/nest/FileManager.scala +++ b/src/partest/scala/tools/partest/nest/FileManager.scala @@ -13,7 +13,6 @@ import java.io.{File, FilenameFilter, IOException, StringWriter, FileReader, PrintWriter, FileWriter} import java.net.URI import scala.tools.nsc.io.{ Path, Directory, File => SFile } -import scala.sys.process._ import scala.collection.mutable trait FileUtil { @@ -73,17 +72,11 @@ trait FileManager extends FileUtil { var SCALAC_OPTS = PartestDefaults.scalacOpts.split(' ').toSeq var JAVA_OPTS = PartestDefaults.javaOpts var timeout = PartestDefaults.timeout - // how can 15 minutes not be enough? What are you doing, run/lisp.scala? - // You complete in 11 seconds on my machine. - var oneTestTimeout = 60 * 60 * 1000 /** Only when --debug is given. */ lazy val testTimings = new mutable.HashMap[String, Long] def recordTestTiming(name: String, milliseconds: Long) = synchronized { testTimings(name) = milliseconds } - def showTestTimings() { - testTimings.toList sortBy (-_._2) foreach { case (k, v) => println("%s: %s".format(k, v)) } - } def getLogFile(dir: File, fileBase: String, kind: String): File = new File(dir, fileBase + "-" + kind + ".log") diff --git a/src/partest/scala/tools/partest/nest/NestUI.scala b/src/partest/scala/tools/partest/nest/NestUI.scala index 70db6d0ed1..ab90d387d0 100644 --- a/src/partest/scala/tools/partest/nest/NestUI.scala +++ b/src/partest/scala/tools/partest/nest/NestUI.scala @@ -54,9 +54,6 @@ object NestUI { } def warning(msg: String) = print(_warning + msg + _default) - def warning(msg: String, wr: PrintWriter) = synchronized { - wr.print(_warning + msg + _default) - } def normal(msg: String) = print(_default + msg) def normal(msg: String, wr: PrintWriter) = synchronized { @@ -104,7 +101,6 @@ object NestUI { } var _verbose = false - var _debug = false def verbose(msg: String) { if (_verbose) { @@ -112,10 +108,4 @@ object NestUI { println(msg) } } - def debug(msg: String) { - if (isPartestDebug) { - outline("debug: ") - println(msg) - } - } } diff --git a/src/partest/scala/tools/partest/nest/PathSettings.scala b/src/partest/scala/tools/partest/nest/PathSettings.scala index a42c2219b1..02651c527b 100644 --- a/src/partest/scala/tools/partest/nest/PathSettings.scala +++ b/src/partest/scala/tools/partest/nest/PathSettings.scala @@ -9,7 +9,6 @@ import scala.tools.nsc.Properties.{ setProp, propOrEmpty, propOrNone, propOrElse import scala.tools.nsc.util.ClassPath import scala.tools.nsc.io import io.{ Path, File, Directory } -import RunnerUtils._ object PathSettings { import PartestDefaults.{ testRootDir, srcDirName } diff --git a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala index 5cb8589d66..4b0ed1f82a 100644 --- a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala +++ b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala @@ -3,8 +3,6 @@ * @author Philipp Haller */ -// $Id$ - package scala.tools.partest package nest @@ -12,7 +10,6 @@ import scala.tools.nsc.Properties.{ setProp, propOrEmpty } import scala.tools.nsc.util.ClassPath import scala.tools.nsc.io import io.Path -import RunnerUtils._ import java.net.URLClassLoader /* This class is used to load an instance of DirectRunner using @@ -28,6 +25,12 @@ class ReflectiveRunner { // was used to start the runner. val sepRunnerClassName = "scala.tools.partest.nest.ConsoleRunner" + private def searchPath(option: String, as: List[String]): Option[String] = as match { + case `option` :: r :: _ => Some(r) + case _ :: rest => searchPath(option, rest) + case Nil => None + } + def main(args: String) { val argList = (args.split("\\s")).toList diff --git a/src/partest/scala/tools/partest/nest/RunnerManager.scala b/src/partest/scala/tools/partest/nest/RunnerManager.scala index c5e944fbc0..f2ce19a950 100644 --- a/src/partest/scala/tools/partest/nest/RunnerManager.scala +++ b/src/partest/scala/tools/partest/nest/RunnerManager.scala @@ -260,13 +260,12 @@ class RunnerManager(kind: String, val fileManager: FileManager, params: TestRunP runCommand(cmd, logFile) } - private def getCheckFilePath(dir: File, suffix: String = "") = { + private def getCheckFilePath(dir: File, suffix: String) = { def chkFile(s: String) = (Directory(dir) / "%s%s.check".format(fileBase, s)).toFile if (chkFile("").isFile || suffix == "") chkFile("") else chkFile("-" + suffix) } - private def getCheckFile(dir: File) = Some(getCheckFilePath(dir, kind)) filter (_.canRead) private def compareOutput(dir: File, logFile: File): String = { val checkFile = getCheckFilePath(dir, kind) @@ -287,15 +286,10 @@ class RunnerManager(kind: String, val fileManager: FileManager, params: TestRunP def newTestWriters() = { val swr = new StringWriter val wr = new PrintWriter(swr, true) - // diff = "" ((swr, wr)) } - def fail(what: Any) = { - NestUI.verbose("scalac: compilation of "+what+" failed\n") - false - } def diffCheck(testFile: File, diff: String) = { testDiff = diff testDiff == "" @@ -341,10 +335,34 @@ class RunnerManager(kind: String, val fileManager: FileManager, params: TestRunP val (scalaFiles, javaFiles) = g partition isScala val allFiles = javaFiles ++ scalaFiles + /* The test can contain both java and scala files, each of which should be compiled with the corresponding + * compiler. Since the source files can reference each other both ways (java referencing scala classes and + * vice versa, the partest compilation routine attempts to reach a "bytecode fixpoint" between the two + * compilers -- that's when bytecode generated by each compiler implements the signatures expected by the other. + * + * In theory this property can't be guaranteed, as neither compiler can know what signatures the other + * compiler expects and how to implement them. (see SI-1240 for the full story) + * + * In practice, this happens in 3 steps: + * STEP1: feed all the files to scalac + * it will parse java files and obtain their expected signatures and generate bytecode for scala files + * STEP2: feed the java files to javac + * it will generate the bytecode for the java files and link to the scalac-generated bytecode for scala + * STEP3: only if there are both scala and java files, recompile the scala sources so they link to the correct + * java signatures, in case the signatures deduced by scalac from the source files were wrong. Since the + * bytecode for java is already in place, we only feed the scala files to scalac so it will take the + * java signatures from the existing javac-generated bytecode + */ List(1, 2, 3).foldLeft(CompileSuccess: CompilationOutcome) { - case (CompileSuccess, 1) if scalaFiles.nonEmpty => compileMgr.attemptCompile(Some(outDir), allFiles, kind, logFile) // java + scala - case (CompileSuccess, 2) if javaFiles.nonEmpty => javac(outDir, javaFiles, logFile) // java - case (CompileSuccess, 3) if scalaFiles.nonEmpty => compileMgr.attemptCompile(Some(outDir), scalaFiles, kind, logFile) // scala + case (CompileSuccess, 1) if scalaFiles.nonEmpty => + compileMgr.attemptCompile(Some(outDir), allFiles, kind, logFile) + case (CompileSuccess, 2) if javaFiles.nonEmpty => + javac(outDir, javaFiles, logFile) + case (CompileSuccess, 3) if scalaFiles.nonEmpty && javaFiles.nonEmpty => + // TODO: Do we actually need this? SI-1240 is known to require this, but we don't know if other tests + // require it: https://groups.google.com/forum/?fromgroups#!topic/scala-internals/rFDKAcOKciU + compileMgr.attemptCompile(Some(outDir), scalaFiles, kind, logFile) + case (outcome, _) => outcome } } @@ -832,9 +850,8 @@ class RunnerManager(kind: String, val fileManager: FileManager, params: TestRunP if (fileManager.failed && !runner.logFile.canRead) return TestState.Ok - // sys addShutdownHook cleanup() - val ((success, ctx), elapsed) = timed(runner.run()) - val state = if (success) TestState.Ok else TestState.Fail + val (success, ctx) = runner.run() + val state = if (success) TestState.Ok else TestState.Fail runner.reportResult(ctx.writers) state diff --git a/src/partest/scala/tools/partest/nest/RunnerUtils.scala b/src/partest/scala/tools/partest/nest/RunnerUtils.scala deleted file mode 100644 index 6707a9338a..0000000000 --- a/src/partest/scala/tools/partest/nest/RunnerUtils.scala +++ /dev/null @@ -1,29 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - * @author Philipp Haller - */ - -// $Id$ - -package scala.tools.partest -package nest - -object RunnerUtils { - def splitArgs(str: String) = str split "\\s" filterNot (_ == "") toList - - def searchPath(option: String, as: List[String]): Option[String] = as match { - case `option` :: r :: _ => Some(r) - case _ :: rest => searchPath(option, rest) - case Nil => None - } - - def searchAndRemovePath(option: String, as: List[String]) = (as indexOf option) match { - case -1 => (None, as) - case idx => (Some(as(idx + 1)), (as take idx) ::: (as drop (idx + 2))) - } - - def searchAndRemoveOption(option: String, as: List[String]) = (as indexOf option) match { - case -1 => (false, as) - case idx => (true, (as take idx) ::: (as drop (idx + 1))) - } -} diff --git a/src/partest/scala/tools/partest/package.scala b/src/partest/scala/tools/partest/package.scala index d38ce692d7..2b2ce2e435 100644 --- a/src/partest/scala/tools/partest/package.scala +++ b/src/partest/scala/tools/partest/package.scala @@ -12,11 +12,7 @@ import scala.sys.process.javaVmArguments import java.util.concurrent.Callable package partest { - class TestState { - def isOk = this eq TestState.Ok - def isFail = this eq TestState.Fail - def isTimeout = this eq TestState.Timeout - } + class TestState { } object TestState { val Ok = new TestState val Fail = new TestState @@ -43,9 +39,8 @@ package object partest { def callable[T](body: => T): Callable[T] = new Callable[T] { override def call() = body } - def path2String(path: String) = file2String(new JFile(path)) def file2String(f: JFile) = - try SFile(f).slurp() + try SFile(f).slurp(scala.io.Codec.UTF8) catch { case _: FileNotFoundException => "" } def basename(name: String): String = Path(name).stripExtension @@ -74,7 +69,6 @@ package object partest { def isPartestDebug: Boolean = propOrEmpty("partest.debug") == "true" - import scala.language.experimental.macros /** diff --git a/src/partest/scala/tools/partest/utils/PrintMgr.scala b/src/partest/scala/tools/partest/utils/PrintMgr.scala deleted file mode 100644 index d25be87c1e..0000000000 --- a/src/partest/scala/tools/partest/utils/PrintMgr.scala +++ /dev/null @@ -1,52 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala Parallel Testing ** -** / __/ __// _ | / / / _ | (c) 2007-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -// $Id$ - -package scala.tools.partest -package utils - -/** - * @author Thomas Hofer - */ -object PrintMgr { - - val NONE = 0 - val SOME = 1 - val MANY = 2 - - var outline = "" - var success = "" - var failure = "" - var warning = "" - var default = "" - - def initialization(number: Int) = number match { - case MANY => - outline = Console.BOLD + Console.BLACK - success = Console.BOLD + Console.GREEN - failure = Console.BOLD + Console.RED - warning = Console.BOLD + Console.YELLOW - default = Console.RESET - case SOME => - outline = Console.BOLD + Console.BLACK - success = Console.RESET - failure = Console.BOLD + Console.BLACK - warning = Console.BOLD + Console.BLACK - default = Console.RESET - case _ => - } - - def printOutline(msg: String) = print(outline + msg + default) - - def printSuccess(msg: String) = print(success + msg + default) - - def printFailure(msg: String) = print(failure + msg + default) - - def printWarning(msg: String) = print(warning + msg + default) -} diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala index 85ddcc6523..76df76cdc8 100644 --- a/src/reflect/scala/reflect/api/Printers.scala +++ b/src/reflect/scala/reflect/api/Printers.scala @@ -166,7 +166,7 @@ trait Printers { self: Universe => protected def render(what: Any, mkPrinter: PrintWriter => TreePrinter, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None): String = { val buffer = new StringWriter() val writer = new PrintWriter(buffer) - var printer = mkPrinter(writer) + val printer = mkPrinter(writer) printTypes.value.map(printTypes => if (printTypes) printer.withTypes else printer.withoutTypes) printIds.value.map(printIds => if (printIds) printer.withIds else printer.withoutIds) printKinds.value.map(printKinds => if (printKinds) printer.withKinds else printer.withoutKinds) diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index 7c12b5979d..da50c55fe1 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -6,7 +6,6 @@ package scala.reflect package internal -import util._ import pickling.ByteCodecs import scala.annotation.tailrec import scala.collection.immutable.ListMap @@ -288,10 +287,6 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => /** Check whether any of the arguments mention a symbol */ def refsSymbol(sym: Symbol) = hasArgWhich(_.symbol == sym) - /** Change all ident's with Symbol "from" to instead use symbol "to" */ - def substIdentSyms(from: Symbol, to: Symbol) = - AnnotationInfo(atp, args map (_ substituteSymbols (List(from), List(to))), assocs) setPos pos - def stringArg(index: Int) = constantAtIndex(index) map (_.stringValue) def intArg(index: Int) = constantAtIndex(index) map (_.intValue) def symbolArg(index: Int) = argAtIndex(index) collect { @@ -325,14 +320,14 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => implicit val AnnotationTag = ClassTag[AnnotationInfo](classOf[AnnotationInfo]) object UnmappableAnnotation extends CompleteAnnotationInfo(NoType, Nil, Nil) - + /** Extracts symbol of thrown exception from AnnotationInfo. - * + * * Supports both “old-style” `@throws(classOf[Exception])` * as well as “new-stye” `@throws[Exception]("cause")` annotations. */ object ThrownException { - def unapply(ann: AnnotationInfo): Option[Symbol] = + def unapply(ann: AnnotationInfo): Option[Symbol] = ann match { case AnnotationInfo(tpe, _, _) if tpe.typeSymbol != ThrowsClass => None diff --git a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala index d72f08674e..6bf12f06de 100644 --- a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala +++ b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala @@ -115,7 +115,7 @@ trait BaseTypeSeqs { def map(f: Type => Type): BaseTypeSeq = { // inlined `elems map f` for performance val len = length - var arr = new Array[Type](len) + val arr = new Array[Type](len) var i = 0 while (i < len) { arr(i) = f(elems(i)) @@ -158,7 +158,7 @@ trait BaseTypeSeqs { val parents = tp.parents // Console.println("computing baseTypeSeq of " + tsym.tpe + " " + parents)//DEBUG val buf = new mutable.ListBuffer[Type] - buf += tsym.tpe + buf += tsym.tpe_* var btsSize = 1 if (parents.nonEmpty) { val nparents = parents.length diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index 9f41f0336e..9da6ad652a 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -1,8 +1,6 @@ package scala.reflect package internal -import Flags._ - trait BuildUtils { self: SymbolTable => class BuildImpl extends BuildApi { diff --git a/src/reflect/scala/reflect/internal/ClassfileConstants.scala b/src/reflect/scala/reflect/internal/ClassfileConstants.scala index 7ccb661426..2ab3caa19d 100644 --- a/src/reflect/scala/reflect/internal/ClassfileConstants.scala +++ b/src/reflect/scala/reflect/internal/ClassfileConstants.scala @@ -342,7 +342,7 @@ object ClassfileConstants { case JAVA_ACC_PRIVATE => PRIVATE case JAVA_ACC_PROTECTED => PROTECTED case JAVA_ACC_FINAL => FINAL - case JAVA_ACC_SYNTHETIC => SYNTHETIC + case JAVA_ACC_SYNTHETIC => SYNTHETIC | ARTIFACT // maybe should be just artifact? case JAVA_ACC_STATIC => STATIC case JAVA_ACC_ABSTRACT => if (isAnnotation) 0L else if (isClass) ABSTRACT else DEFERRED case JAVA_ACC_INTERFACE => if (isAnnotation) 0L else TRAIT | INTERFACE | ABSTRACT @@ -372,7 +372,7 @@ object ClassfileConstants { } def methodFlags(jflags: Int): Long = { initFields(jflags) - translateFlags(jflags, if ((jflags & JAVA_ACC_BRIDGE) != 0) BRIDGE else 0) + translateFlags(jflags, if ((jflags & JAVA_ACC_BRIDGE) != 0) BRIDGE | ARTIFACT else 0) } } object FlagTranslation extends FlagTranslation { } @@ -380,11 +380,4 @@ object ClassfileConstants { def toScalaMethodFlags(flags: Int): Long = FlagTranslation methodFlags flags def toScalaClassFlags(flags: Int): Long = FlagTranslation classFlags flags def toScalaFieldFlags(flags: Int): Long = FlagTranslation fieldFlags flags - - @deprecated("Use another method in this object", "2.10.0") - def toScalaFlags(flags: Int, isClass: Boolean = false, isField: Boolean = false): Long = ( - if (isClass) toScalaClassFlags(flags) - else if (isField) toScalaFieldFlags(flags) - else toScalaMethodFlags(flags) - ) } diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 2a7b55cb5a..9a846179b9 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -9,7 +9,6 @@ package internal import scala.annotation.{ switch, meta } import scala.collection.{ mutable, immutable } import Flags._ -import PartialFunction._ import scala.reflect.api.{Universe => ApiUniverse} trait Definitions extends api.StandardDefinitions { @@ -31,7 +30,7 @@ trait Definitions extends api.StandardDefinitions { val clazz = owner.newClassSymbol(name, NoPosition, flags) clazz setInfoAndEnter ClassInfoType(parents, newScope, clazz) } - private def newMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long = 0L): MethodSymbol = { + private def newMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long): MethodSymbol = { val msym = owner.newMethod(name.encode, NoPosition, flags) val params = msym.newSyntheticValueParams(formals) msym setInfo MethodType(params, restpe) @@ -149,7 +148,6 @@ trait Definitions extends api.StandardDefinitions { FloatClass, DoubleClass ) - def ScalaValueClassCompanions: List[Symbol] = ScalaValueClasses map (_.companionSymbol) def ScalaPrimitiveValueClasses: List[ClassSymbol] = ScalaValueClasses } @@ -157,9 +155,6 @@ trait Definitions extends api.StandardDefinitions { private var isInitialized = false def isDefinitionsInitialized = isInitialized - // symbols related to packages - var emptypackagescope: Scope = null //debug - @deprecated("Moved to rootMirror.RootPackage", "2.10.0") val RootPackage: ModuleSymbol = rootMirror.RootPackage @@ -181,8 +176,6 @@ trait Definitions extends api.StandardDefinitions { lazy val RuntimePackage = getRequiredPackage("scala.runtime") lazy val RuntimePackageClass = RuntimePackage.moduleClass.asClass - lazy val JavaLangEnumClass = requiredClass[java.lang.Enum[_]] - // convenient one-argument parameter lists lazy val anyparam = List(AnyClass.tpe) lazy val anyvalparam = List(AnyValClass.typeConstructor) @@ -223,7 +216,7 @@ trait Definitions extends api.StandardDefinitions { def fullyInitializeSymbol(sym: Symbol): Symbol = { sym.initialize fullyInitializeType(sym.info) - fullyInitializeType(sym.tpe) + fullyInitializeType(sym.tpe_*) sym } def fullyInitializeType(tp: Type): Type = { @@ -235,14 +228,32 @@ trait Definitions extends api.StandardDefinitions { scope.sorted foreach fullyInitializeSymbol scope } + /** Is this symbol a member of Object or Any? */ + def isUniversalMember(sym: Symbol) = ( + (sym ne NoSymbol) + && (ObjectClass isSubClass sym.owner) + ) + + /** Is this symbol unimportable? Unimportable symbols include: + * - constructors, because <init> is not a real name + * - private[this] members, which cannot be referenced from anywhere else + * - members of Any or Object, because every instance will inherit a + * definition which supersedes the imported one + */ + def isUnimportable(sym: Symbol) = ( + (sym eq NoSymbol) + || sym.isConstructor + || sym.isPrivateLocal + || isUniversalMember(sym) + ) + def isImportable(sym: Symbol) = !isUnimportable(sym) + /** Is this type equivalent to Any, AnyVal, or AnyRef? */ def isTrivialTopType(tp: Type) = ( tp =:= AnyClass.tpe || tp =:= AnyValClass.tpe || tp =:= AnyRefClass.tpe ) - /** Does this type have a parent which is none of Any, AnyVal, or AnyRef? */ - def hasNonTrivialParent(tp: Type) = tp.parents exists (t => !isTrivialTopType(tp)) private def fixupAsAnyTrait(tpe: Type): Type = tpe match { case ClassInfoType(parents, decls, clazz) => @@ -253,7 +264,6 @@ trait Definitions extends api.StandardDefinitions { } case PolyType(tparams, restpe) => PolyType(tparams, fixupAsAnyTrait(restpe)) -// case _ => tpe } // top types @@ -312,6 +322,9 @@ trait Definitions extends api.StandardDefinitions { lazy val ThrowableClass = getClassByName(sn.Throwable) lazy val UninitializedErrorClass = requiredClass[UninitializedFieldError] + lazy val NPEConstructor = getMemberMethod(NullPointerExceptionClass, nme.CONSTRUCTOR) suchThat (_.paramss.flatten.isEmpty) + lazy val UninitializedFieldConstructor = UninitializedErrorClass.primaryConstructor + // fundamental reference classes lazy val PartialFunctionClass = requiredClass[PartialFunction[_,_]] lazy val AbstractPartialFunctionClass = requiredClass[scala.runtime.AbstractPartialFunction[_,_]] @@ -335,14 +348,11 @@ trait Definitions extends api.StandardDefinitions { lazy val UnqualifiedOwners = UnqualifiedModules.toSet ++ UnqualifiedModules.map(_.moduleClass) lazy val PredefModule = requiredModule[scala.Predef.type] - lazy val PredefModuleClass = PredefModule.moduleClass - - def Predef_classOf = getMemberMethod(PredefModule, nme.classOf) - def Predef_identity = getMemberMethod(PredefModule, nme.identity) - def Predef_conforms = getMemberMethod(PredefModule, nme.conforms) - def Predef_wrapRefArray = getMemberMethod(PredefModule, nme.wrapRefArray) - def Predef_??? = getMemberMethod(PredefModule, nme.???) - def Predef_implicitly = getMemberMethod(PredefModule, nme.implicitly) + def Predef_classOf = getMemberMethod(PredefModule, nme.classOf) + def Predef_wrapRefArray = getMemberMethod(PredefModule, nme.wrapRefArray) + def Predef_wrapArray(tp: Type) = getMemberMethod(PredefModule, wrapArrayMethodName(tp)) + def Predef_??? = getMemberMethod(PredefModule, nme.???) + def Predef_implicitly = getMemberMethod(PredefModule, nme.implicitly) /** Is `sym` a member of Predef with the given name? * Note: DON't replace this by sym == Predef_conforms/etc, as Predef_conforms is a `def` @@ -358,7 +368,6 @@ trait Definitions extends api.StandardDefinitions { lazy val SpecializableModule = requiredModule[Specializable] lazy val GroupOfSpecializable = getMemberClass(SpecializableModule, tpnme.Group) - lazy val ConsoleModule = requiredModule[scala.Console.type] lazy val ScalaRunTimeModule = requiredModule[scala.runtime.ScalaRunTime.type] lazy val SymbolModule = requiredModule[scala.Symbol.type] lazy val Symbol_apply = getMemberMethod(SymbolModule, nme.apply) @@ -368,9 +377,7 @@ trait Definitions extends api.StandardDefinitions { def arrayLengthMethod = getMemberMethod(ScalaRunTimeModule, nme.array_length) def arrayCloneMethod = getMemberMethod(ScalaRunTimeModule, nme.array_clone) def ensureAccessibleMethod = getMemberMethod(ScalaRunTimeModule, nme.ensureAccessible) - def scalaRuntimeSameElements = getMemberMethod(ScalaRunTimeModule, nme.sameElements) def arrayClassMethod = getMemberMethod(ScalaRunTimeModule, nme.arrayClass) - def arrayElementClassMethod = getMemberMethod(ScalaRunTimeModule, nme.arrayElementClass) // classes with special meanings lazy val StringAddClass = requiredClass[scala.runtime.StringAdd] @@ -381,11 +388,6 @@ trait Definitions extends api.StandardDefinitions { lazy val TraitSetterAnnotationClass = requiredClass[scala.runtime.TraitSetter] lazy val DelayedInitClass = requiredClass[scala.DelayedInit] def delayedInitMethod = getMemberMethod(DelayedInitClass, nme.delayedInit) - // a dummy value that communicates that a delayedInit call is compiler-generated - // from phase UnCurry to phase Constructors - // !!! This is not used anywhere (it was checked in that way.) - // def delayedInitArgVal = EmptyPackageClass.newValue(NoPosition, nme.delayedInitArg) - // .setInfo(UnitClass.tpe) lazy val TypeConstraintClass = requiredClass[scala.annotation.TypeConstraint] lazy val SingletonClass = enterNewClass(ScalaPackageClass, tpnme.Singleton, anyparam, ABSTRACT | TRAIT | FINAL) @@ -407,7 +409,8 @@ trait Definitions extends api.StandardDefinitions { def isScalaRepeatedParamType(tp: Type) = tp.typeSymbol == RepeatedParamClass def isJavaRepeatedParamType(tp: Type) = tp.typeSymbol == JavaRepeatedParamClass def isRepeatedParamType(tp: Type) = isScalaRepeatedParamType(tp) || isJavaRepeatedParamType(tp) - def isRepeated(param: Symbol) = isRepeatedParamType(param.tpe) + def isRepeated(param: Symbol) = isRepeatedParamType(param.tpe_*) + def isByName(param: Symbol) = isByNameParamType(param.tpe_*) def isCastSymbol(sym: Symbol) = sym == Any_asInstanceOf || sym == Object_asInstanceOf def isJavaVarArgsMethod(m: Symbol) = m.isMethod && isJavaVarArgs(m.info.params) @@ -432,10 +435,6 @@ trait Definitions extends api.StandardDefinitions { case _ => tp } - def isPrimitiveArray(tp: Type) = tp match { - case TypeRef(_, ArrayClass, arg :: Nil) => isPrimitiveValueClass(arg.typeSymbol) - case _ => false - } def isReferenceArray(tp: Type) = tp match { case TypeRef(_, ArrayClass, arg :: Nil) => arg <:< AnyRefClass.tpe case _ => false @@ -445,11 +444,8 @@ trait Definitions extends api.StandardDefinitions { case _ => false } - lazy val MatchingStrategyClass = getRequiredClass("scala.MatchingStrategy") - // collections classes lazy val ConsClass = requiredClass[scala.collection.immutable.::[_]] - lazy val IterableClass = requiredClass[scala.collection.Iterable[_]] lazy val IteratorClass = requiredClass[scala.collection.Iterator[_]] lazy val ListClass = requiredClass[scala.collection.immutable.List[_]] lazy val SeqClass = requiredClass[scala.collection.Seq[_]] @@ -460,12 +456,12 @@ trait Definitions extends api.StandardDefinitions { lazy val List_apply = getMemberMethod(ListModule, nme.apply) lazy val NilModule = requiredModule[scala.collection.immutable.Nil.type] lazy val SeqModule = requiredModule[scala.collection.Seq.type] - lazy val IteratorModule = requiredModule[scala.collection.Iterator.type] - lazy val Iterator_apply = getMemberMethod(IteratorModule, nme.apply) // arrays and their members lazy val ArrayModule = requiredModule[scala.Array.type] lazy val ArrayModule_overloadedApply = getMemberMethod(ArrayModule, nme.apply) + def ArrayModule_genericApply = ArrayModule_overloadedApply.suchThat(_.paramss.flatten.last.tpe.typeSymbol == ClassTagClass) // [T: ClassTag](xs: T*): Array[T] + def ArrayModule_apply(tp: Type) = ArrayModule_overloadedApply.suchThat(_.tpe.resultType =:= arrayType(tp)) // (p1: AnyVal1, ps: AnyVal1*): Array[AnyVal1] lazy val ArrayClass = getRequiredClass("scala.Array") // requiredClass[scala.Array[_]] lazy val Array_apply = getMemberMethod(ArrayClass, nme.apply) lazy val Array_update = getMemberMethod(ArrayClass, nme.update) @@ -474,9 +470,7 @@ trait Definitions extends api.StandardDefinitions { // reflection / structural types lazy val SoftReferenceClass = requiredClass[java.lang.ref.SoftReference[_]] - lazy val WeakReferenceClass = requiredClass[java.lang.ref.WeakReference[_]] lazy val MethodClass = getClassByName(sn.MethodAsObject) - def methodClass_setAccessible = getMemberMethod(MethodClass, nme.setAccessible) lazy val EmptyMethodCacheClass = requiredClass[scala.runtime.EmptyMethodCache] lazy val MethodCacheClass = requiredClass[scala.runtime.MethodCache] def methodCache_find = getMemberMethod(MethodCacheClass, nme.find_) @@ -500,7 +494,6 @@ trait Definitions extends api.StandardDefinitions { lazy val ExprClass = if (ExprsClass != NoSymbol) getMemberClass(ExprsClass, tpnme.Expr) else NoSymbol def ExprSplice = if (ExprsClass != NoSymbol) getMemberMethod(ExprClass, nme.splice) else NoSymbol def ExprValue = if (ExprsClass != NoSymbol) getMemberMethod(ExprClass, nme.value) else NoSymbol - lazy val ExprModule = if (ExprsClass != NoSymbol) getMemberModule(ExprsClass, nme.Expr) else NoSymbol lazy val ClassTagModule = requiredModule[scala.reflect.ClassTag[_]] lazy val ClassTagClass = requiredClass[scala.reflect.ClassTag[_]] @@ -526,7 +519,6 @@ trait Definitions extends api.StandardDefinitions { def MacroContextPrefix = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.prefix) else NoSymbol def MacroContextPrefixType = if (MacroContextClass != NoSymbol) getTypeMember(MacroContextClass, tpnme.PrefixType) else NoSymbol def MacroContextUniverse = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.universe) else NoSymbol - def MacroContextMirror = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.mirror) else NoSymbol lazy val MacroImplAnnotation = requiredClass[scala.reflect.macros.internal.macroImpl] lazy val StringContextClass = requiredClass[scala.StringContext] @@ -536,17 +528,19 @@ trait Definitions extends api.StandardDefinitions { lazy val ScalaLongSignatureAnnotation = requiredClass[scala.reflect.ScalaLongSignature] // Option classes - lazy val OptionClass: ClassSymbol = requiredClass[Option[_]] - lazy val SomeClass: ClassSymbol = requiredClass[Some[_]] - lazy val NoneModule: ModuleSymbol = requiredModule[scala.None.type] - lazy val SomeModule: ModuleSymbol = requiredModule[scala.Some.type] + lazy val OptionClass: ClassSymbol = requiredClass[Option[_]] + lazy val OptionModule: ModuleSymbol = requiredModule[scala.Option.type] + lazy val Option_apply = getMemberMethod(OptionModule, nme.apply) + lazy val SomeClass: ClassSymbol = requiredClass[Some[_]] + lazy val NoneModule: ModuleSymbol = requiredModule[scala.None.type] + lazy val SomeModule: ModuleSymbol = requiredModule[scala.Some.type] def compilerTypeFromTag(tt: ApiUniverse # WeakTypeTag[_]): Type = tt.in(rootMirror).tpe def compilerSymbolFromTag(tt: ApiUniverse # WeakTypeTag[_]): Symbol = tt.in(rootMirror).tpe.typeSymbol // The given symbol represents either String.+ or StringAdd.+ def isStringAddition(sym: Symbol) = sym == String_+ || sym == StringAdd_+ - def isArrowAssoc(sym: Symbol) = ArrowAssocClass.tpe.decls.toList contains sym + def isArrowAssoc(sym: Symbol) = sym.owner == ArrowAssocClass // The given symbol is a method with the right name and signature to be a runnable java program. def isJavaMainMethod(sym: Symbol) = (sym.name == nme.main) && (sym.info match { @@ -556,12 +550,6 @@ trait Definitions extends api.StandardDefinitions { // The given class has a main method. def hasJavaMainMethod(sym: Symbol): Boolean = (sym.tpe member nme.main).alternatives exists isJavaMainMethod - def hasJavaMainMethod(path: String): Boolean = - hasJavaMainMethod(getModuleIfDefined(path)) - - def isOptionType(tp: Type) = tp.typeSymbol isSubClass OptionClass - def isSomeType(tp: Type) = tp.typeSymbol eq SomeClass - def isNoneType(tp: Type) = tp.typeSymbol eq NoneModule // Product, Tuple, Function, AbstractFunction private def mkArityArray(name: String, arity: Int, countFrom: Int): Array[ClassSymbol] = { @@ -584,7 +572,6 @@ trait Definitions extends api.StandardDefinitions { /** Creators for TupleN, ProductN, FunctionN. */ def tupleType(elems: List[Type]) = aritySpecificType(TupleClass, elems) - def productType(elems: List[Type]) = aritySpecificType(ProductClass, elems) def functionType(formals: List[Type], restpe: Type) = aritySpecificType(FunctionClass, formals, restpe) def abstractFunctionType(formals: List[Type], restpe: Type) = aritySpecificType(AbstractFunctionClass, formals, restpe) @@ -603,10 +590,6 @@ trait Definitions extends api.StandardDefinitions { else nme.genericWrapArray } - @deprecated("Use isTupleType", "2.10.0") - def isTupleTypeOrSubtype(tp: Type) = isTupleType(tp) - - def tupleField(n: Int, j: Int) = getMemberValue(TupleClass(n), nme.productAccessorName(j)) // NOTE: returns true for NoSymbol since it's included in the TupleClass array -- is this intensional? def isTupleSymbol(sym: Symbol) = TupleClass contains unspecializedSymbol(sym) def isProductNClass(sym: Symbol) = ProductClass contains sym @@ -652,13 +635,8 @@ trait Definitions extends api.StandardDefinitions { def Product_iterator = getMemberMethod(ProductRootClass, nme.productIterator) def Product_productPrefix = getMemberMethod(ProductRootClass, nme.productPrefix) def Product_canEqual = getMemberMethod(ProductRootClass, nme.canEqual_) - // def Product_productElementName = getMemberMethod(ProductRootClass, nme.productElementName) def productProj(z:Symbol, j: Int): TermSymbol = getMemberValue(z, nme.productAccessorName(j)) - def productProj(n: Int, j: Int): TermSymbol = productProj(ProductClass(n), j) - - /** returns true if this type is exactly ProductN[T1,...,Tn], not some subclass */ - def isExactProductType(tp: Type): Boolean = isProductNClass(tp.typeSymbol) /** if tpe <: ProductN[T1,...,TN], returns List(T1,...,TN) else Nil */ def getProductArgs(tpe: Type): List[Type] = tpe.baseClasses find isProductNClass match { @@ -666,13 +644,16 @@ trait Definitions extends api.StandardDefinitions { case _ => Nil } + def dropNullaryMethod(tp: Type) = tp match { + case NullaryMethodType(restpe) => restpe + case _ => tp + } + def unapplyUnwrap(tpe:Type) = tpe.finalResultType.normalize match { case RefinedType(p :: _, _) => p.normalize case tp => tp } - def functionApply(n: Int) = getMemberMethod(FunctionClass(n), nme.apply) - def abstractFunctionForFunctionType(tp: Type) = if (isFunctionType(tp)) abstractFunctionType(tp.typeArgs.init, tp.typeArgs.last) else NoType @@ -690,8 +671,6 @@ trait Definitions extends api.StandardDefinitions { (sym eq PartialFunctionClass) || (sym eq AbstractPartialFunctionClass) } - def isSeqType(tp: Type) = elementType(SeqClass, tp.normalize) != NoType - def elementType(container: Symbol, tp: Type): Type = tp match { case TypeRef(_, `container`, arg :: Nil) => arg case _ => NoType @@ -704,10 +683,6 @@ trait Definitions extends api.StandardDefinitions { def optionType(tp: Type) = appliedType(OptionClass, tp) def scalaRepeatedType(arg: Type) = appliedType(RepeatedParamClass, arg) def seqType(arg: Type) = appliedType(SeqClass, arg) - def someType(tp: Type) = appliedType(SomeClass, tp) - - def StringArray = arrayType(StringClass.tpe) - lazy val ObjectArray = arrayType(ObjectClass.tpe) def ClassType(arg: Type) = if (phase.erasedTypes || forMSIL) ClassClass.tpe @@ -720,9 +695,6 @@ trait Definitions extends api.StandardDefinitions { // - .linkedClassOfClass: the ClassSymbol of the enumeration (class E) sym.owner.linkedClassOfClass.tpe - def vmClassType(arg: Type): Type = ClassType(arg) - def vmSignature(sym: Symbol, info: Type): String = signature(info) // !!! - /** Given a class symbol C with type parameters T1, T2, ... Tn * which have upper/lower bounds LB1/UB1, LB1/UB2, ..., LBn/UBn, * returns an existential type of the form @@ -730,26 +702,13 @@ trait Definitions extends api.StandardDefinitions { * C[E1, ..., En] forSome { E1 >: LB1 <: UB1 ... en >: LBn <: UBn }. */ def classExistentialType(clazz: Symbol): Type = - newExistentialType(clazz.typeParams, clazz.tpe) - - /** Given type U, creates a Type representing Class[_ <: U]. - */ - def boundedClassType(upperBound: Type) = - appliedTypeAsUpperBounds(ClassClass.typeConstructor, List(upperBound)) - - /** To avoid unchecked warnings on polymorphic classes, translate - * a Foo[T] into a Foo[_] for use in the pattern matcher. - */ - @deprecated("Use classExistentialType", "2.10.0") - def typeCaseType(clazz: Symbol): Type = classExistentialType(clazz) + newExistentialType(clazz.typeParams, clazz.tpe_*) // // .NET backend // lazy val ComparatorClass = getRequiredClass("scala.runtime.Comparator") - // System.ValueType - lazy val ValueTypeClass: ClassSymbol = getClassByName(sn.ValueType) // System.MulticastDelegate lazy val DelegateClass: ClassSymbol = getClassByName(sn.Delegate) var Delegate_scalaCallers: List[Symbol] = List() // Syncnote: No protection necessary yet as only for .NET where reflection is not supported. @@ -841,12 +800,7 @@ trait Definitions extends api.StandardDefinitions { else x :: removeRedundantObjects(xs) } - /** Order a list of types with non-trait classes before others. */ - def classesFirst(tps: List[Type]): List[Type] = { - val (classes, others) = tps partition (t => t.typeSymbol.isClass && !t.typeSymbol.isTrait) - if (classes.isEmpty || others.isEmpty || (tps startsWith classes)) tps - else classes ::: others - } + /** The following transformations applied to a list of parents. * If any parent is a class/trait, all parents which normalize to * Object are discarded. Otherwise, all parents which normalize @@ -859,6 +813,12 @@ trait Definitions extends api.StandardDefinitions { removeRedundantObjects(parents) } + /** Flatten curried parameter lists of a method type. */ + def allParameters(tpe: Type): List[Symbol] = tpe match { + case MethodType(params, res) => params ::: allParameters(res) + case _ => Nil + } + def typeStringNoPackage(tp: Type) = "" + tp stripPrefix tp.typeSymbol.enclosingPackage.fullName + "." @@ -868,10 +828,6 @@ trait Definitions extends api.StandardDefinitions { def parentsString(parents: List[Type]) = normalizedParents(parents) mkString " with " - def typeParamsString(tp: Type) = tp match { - case PolyType(tparams, _) => tparams map (_.defString) mkString ("[", ",", "]") - case _ => "" - } def valueParamsString(tp: Type) = tp match { case MethodType(params, _) => params map (_.defString) mkString ("(", ",", ")") case _ => "" @@ -883,8 +839,8 @@ trait Definitions extends api.StandardDefinitions { lazy val Object_!= = enterNewMethod(ObjectClass, nme.NE, anyrefparam, booltype, FINAL) lazy val Object_eq = enterNewMethod(ObjectClass, nme.eq, anyrefparam, booltype, FINAL) lazy val Object_ne = enterNewMethod(ObjectClass, nme.ne, anyrefparam, booltype, FINAL) - lazy val Object_isInstanceOf = newT1NoParamsMethod(ObjectClass, nme.isInstanceOf_Ob, FINAL | SYNTHETIC)(_ => booltype) - lazy val Object_asInstanceOf = newT1NoParamsMethod(ObjectClass, nme.asInstanceOf_Ob, FINAL | SYNTHETIC)(_.typeConstructor) + lazy val Object_isInstanceOf = newT1NoParamsMethod(ObjectClass, nme.isInstanceOf_Ob, FINAL | SYNTHETIC | ARTIFACT)(_ => booltype) + lazy val Object_asInstanceOf = newT1NoParamsMethod(ObjectClass, nme.asInstanceOf_Ob, FINAL | SYNTHETIC | ARTIFACT)(_.typeConstructor) lazy val Object_synchronized = newPolyMethod(1, ObjectClass, nme.synchronized_, FINAL)(tps => (Some(List(tps.head.typeConstructor)), tps.head.typeConstructor) ) @@ -908,12 +864,6 @@ trait Definitions extends api.StandardDefinitions { lazy val BoxedNumberClass = getClassByName(sn.BoxedNumber) lazy val BoxedCharacterClass = getClassByName(sn.BoxedCharacter) lazy val BoxedBooleanClass = getClassByName(sn.BoxedBoolean) - lazy val BoxedByteClass = requiredClass[java.lang.Byte] - lazy val BoxedShortClass = requiredClass[java.lang.Short] - lazy val BoxedIntClass = requiredClass[java.lang.Integer] - lazy val BoxedLongClass = requiredClass[java.lang.Long] - lazy val BoxedFloatClass = requiredClass[java.lang.Float] - lazy val BoxedDoubleClass = requiredClass[java.lang.Double] lazy val Boxes_isNumberOrBool = getDecl(BoxesRunTimeClass, nme.isBoxedNumberOrBoolean) lazy val Boxes_isNumber = getDecl(BoxesRunTimeClass, nme.isBoxedNumber) @@ -934,7 +884,6 @@ trait Definitions extends api.StandardDefinitions { lazy val ImplicitNotFoundClass = requiredClass[scala.annotation.implicitNotFound] lazy val MigrationAnnotationClass = requiredClass[scala.annotation.migration] lazy val ScalaStrictFPAttr = requiredClass[scala.annotation.strictfp] - lazy val SerializableAttr = requiredClass[scala.annotation.serializable] // @serializable is deprecated lazy val SwitchClass = requiredClass[scala.annotation.switch] lazy val TailrecClass = requiredClass[scala.annotation.tailrec] lazy val VarargsClass = requiredClass[scala.annotation.varargs] @@ -969,7 +918,6 @@ trait Definitions extends api.StandardDefinitions { lazy val ParamTargetClass = requiredClass[meta.param] lazy val SetterTargetClass = requiredClass[meta.setter] lazy val ClassTargetClass = requiredClass[meta.companionClass] - lazy val ObjectTargetClass = requiredClass[meta.companionObject] lazy val MethodTargetClass = requiredClass[meta.companionMethod] // TODO: module, moduleClass? package, packageObject? lazy val LanguageFeatureAnnot = requiredClass[meta.languageFeature] @@ -1014,7 +962,6 @@ trait Definitions extends api.StandardDefinitions { def getLanguageFeature(name: String, owner: Symbol = languageFeatureModule): Symbol = getMember(owner, newTypeName(name)) def termMember(owner: Symbol, name: String): Symbol = owner.info.member(newTermName(name)) - def typeMember(owner: Symbol, name: String): Symbol = owner.info.member(newTypeName(name)) def findNamedMember(fullName: Name, root: Symbol): Symbol = { val segs = nme.segments(fullName.toString, fullName.isTermName) @@ -1054,7 +1001,6 @@ trait Definitions extends api.StandardDefinitions { } } def getMemberClass(owner: Symbol, name: Name): ClassSymbol = { - val y = getMember(owner, name.toTypeName) getMember(owner, name.toTypeName) match { case x: ClassSymbol => x case _ => fatalMissingSymbol(owner, name, "member class") @@ -1082,9 +1028,6 @@ trait Definitions extends api.StandardDefinitions { def getDeclIfDefined(owner: Symbol, name: Name): Symbol = owner.info.nonPrivateDecl(name) - def packageExists(packageName: String): Boolean = - getModuleIfDefined(packageName).isPackage - private def newAlias(owner: Symbol, name: TypeName, alias: Type): AliasTypeSymbol = owner.newAliasType(name) setInfoAndEnter alias @@ -1116,7 +1059,6 @@ trait Definitions extends api.StandardDefinitions { newPolyMethod(1, owner, name, flags)(tparams => (Some(Nil), createFn(tparams.head))) } - lazy val boxedClassValues = boxedClass.values.toSet[Symbol] lazy val isUnbox = unboxMethod.values.toSet[Symbol] lazy val isBox = boxMethod.values.toSet[Symbol] @@ -1176,8 +1118,6 @@ trait Definitions extends api.StandardDefinitions { /** Is symbol a value class? */ def isPrimitiveValueClass(sym: Symbol) = ScalaValueClasses contains sym - def isNonUnitValueClass(sym: Symbol) = isPrimitiveValueClass(sym) && (sym != UnitClass) - def isSpecializableClass(sym: Symbol) = isPrimitiveValueClass(sym) || (sym == AnyRefClass) def isPrimitiveValueType(tp: Type) = isPrimitiveValueClass(tp.typeSymbol) /** Is symbol a boxed value class, e.g. java.lang.Integer? */ @@ -1218,21 +1158,10 @@ trait Definitions extends api.StandardDefinitions { else flatNameString(etp.typeSymbol, '.') } - /** Surgery on the value classes. Without this, AnyVals defined in source - * files end up with an AnyRef parent. It is likely there is a better way - * to evade that AnyRef. - */ - private def setParents(sym: Symbol, parents: List[Type]): Symbol = sym.rawInfo match { - case ClassInfoType(_, scope, clazz) => - sym setInfo ClassInfoType(parents, scope, clazz) - case _ => - sym - } - def init() { if (isInitialized) return // force initialization of every symbol that is synthesized or hijacked by the compiler - val forced = symbolsNotPresentInBytecode + val _ = symbolsNotPresentInBytecode isInitialized = true } //init @@ -1253,11 +1182,6 @@ trait Definitions extends api.StandardDefinitions { newCaller } - // def addScalaCallerInfo(scalaCaller: Symbol, methSym: Symbol, delType: Type) { - // assert(Delegate_scalaCallers contains scalaCaller) - // Delegate_scalaCallerInfos += (scalaCaller -> (methSym, delType)) - // } - def addScalaCallerInfo(scalaCaller: Symbol, methSym: Symbol) { assert(Delegate_scalaCallers contains scalaCaller) Delegate_scalaCallerTargets += (scalaCaller -> methSym) diff --git a/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala b/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala index 59c027868e..2a0fe9d19a 100644 --- a/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala +++ b/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala @@ -7,7 +7,6 @@ package scala.reflect package internal import scala.collection.{ mutable, immutable } -import util._ /** The name of this trait defines the eventual intent better than * it does the initial contents. diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala index 30dd9c3e49..61906740a0 100644 --- a/src/reflect/scala/reflect/internal/Flags.scala +++ b/src/reflect/scala/reflect/internal/Flags.scala @@ -116,6 +116,20 @@ class ModifierFlags { final val LAZY = 1L << 31 // symbol is a lazy val. can't have MUTABLE unless transformed by typer final val PRESUPER = 1L << 37 // value is evaluated before super call final val DEFAULTINIT = 1L << 41 // symbol is initialized to the default value: used by -Xcheckinit + final val ARTIFACT = 1L << 46 // symbol should be ignored when typechecking; will be marked ACC_SYNTHETIC in bytecode + + /** Symbols which are marked ARTIFACT. (Expand this list?) + * + * - $outer fields and accessors + * - super accessors + * - protected accessors + * - lazy local accessors + * - bridge methods + * - default argument getters + * - evaluation-order preserving locals for right-associative and out-of-order named arguments + * - catch-expression storing vals + * - anything else which feels a setFlag(ARTIFACT) + */ // Overridden. def flagToString(flag: Long): String = "" @@ -165,7 +179,6 @@ class Flags extends ModifierFlags { // A Java method's type is ``cooked'' by transforming raw types to existentials final val SYNCHRONIZED = 1L << 45 // symbol is a method which should be marked ACC_SYNCHRONIZED - final val ARTIFACT = 1L << 46 // symbol should be ignored when typechecking; will be marked ACC_SYNTHETIC in bytecode // ------- shift definitions ------------------------------------------------------- @@ -248,7 +261,7 @@ class Flags extends ModifierFlags { /** These modifiers appear in TreePrinter output. */ final val PrintableFlags = ExplicitFlags | BridgeFlags | LOCAL | SYNTHETIC | STABLE | CASEACCESSOR | MACRO | - ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | STATIC | SPECIALIZED | SYNCHRONIZED + ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | STATIC | SPECIALIZED | SYNCHRONIZED | ARTIFACT /** When a symbol for a field is created, only these flags survive * from Modifiers. Others which may be applied at creation time are: @@ -420,7 +433,7 @@ class Flags extends ModifierFlags { case VARARGS => "<varargs>" // (1L << 43) case TRIEDCOOKING => "<triedcooking>" // (1L << 44) case SYNCHRONIZED => "<synchronized>" // (1L << 45) - case 0x400000000000L => "" // (1L << 46) + case ARTIFACT => "<artifact>" // (1L << 46) case 0x800000000000L => "" // (1L << 47) case 0x1000000000000L => "" // (1L << 48) case 0x2000000000000L => "" // (1L << 49) diff --git a/src/reflect/scala/reflect/internal/HasFlags.scala b/src/reflect/scala/reflect/internal/HasFlags.scala index 4a3663b8ea..6f8befd23e 100644 --- a/src/reflect/scala/reflect/internal/HasFlags.scala +++ b/src/reflect/scala/reflect/internal/HasFlags.scala @@ -158,13 +158,14 @@ trait HasFlags { else nonAccess + " " + access } + // Guess this can't be deprecated seeing as it's in the reflect API. + def isParameter = hasFlag(PARAM) + // Backward compat section @deprecated( "Use isTrait", "2.10.0") def hasTraitFlag = hasFlag(TRAIT) @deprecated("Use hasDefault", "2.10.0") def hasDefaultFlag = hasFlag(DEFAULTPARAM) - @deprecated("Use isValueParameter or isTypeParameter", "2.10.0") - def isParameter = hasFlag(PARAM) @deprecated("Use flagString", "2.10.0") def defaultFlagString = flagString @deprecated("Use flagString(mask)", "2.10.0") diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala index 43902c1930..6ad9a63822 100644 --- a/src/reflect/scala/reflect/internal/Importers.scala +++ b/src/reflect/scala/reflect/internal/Importers.scala @@ -316,7 +316,6 @@ trait Importers extends api.Importers { self: SymbolTable => def importName(name: from.Name): Name = if (name.isTypeName) newTypeName(name.toString) else newTermName(name.toString) def importTypeName(name: from.TypeName): TypeName = importName(name).toTypeName - def importTermName(name: from.TermName): TermName = importName(name).toTermName def importModifiers(mods: from.Modifiers): Modifiers = new Modifiers(mods.flags, importName(mods.privateWithin), mods.annotations map importTree) @@ -427,17 +426,17 @@ trait Importers extends api.Importers { self: SymbolTable => } addFixup({ if (mytree != null) { - val mysym = if (tree.hasSymbol) importSymbol(tree.symbol) else NoSymbol + val mysym = if (tree.hasSymbolField) importSymbol(tree.symbol) else NoSymbol val mytpe = importType(tree.tpe) mytree match { case mytt: TypeTree => val tt = tree.asInstanceOf[from.TypeTree] - if (mytree.hasSymbol) mytt.symbol = mysym + if (mytree.hasSymbolField) mytt.symbol = mysym if (tt.wasEmpty) mytt.defineType(mytpe) else mytt.setType(mytpe) if (tt.original != null) mytt.setOriginal(importTree(tt.original)) case _ => - if (mytree.hasSymbol) mytree.symbol = importSymbol(tree.symbol) + if (mytree.hasSymbolField) mytree.symbol = importSymbol(tree.symbol) mytree.tpe = importType(tree.tpe) } } diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala index 0beb8e368f..80aa06d020 100644 --- a/src/reflect/scala/reflect/internal/Mirrors.scala +++ b/src/reflect/scala/reflect/internal/Mirrors.scala @@ -19,6 +19,8 @@ trait Mirrors extends api.Mirrors { trait RootSymbol extends Symbol { def mirror: Mirror } abstract class RootsBase(rootOwner: Symbol) extends scala.reflect.api.Mirror[Mirrors.this.type] { thisMirror => + private[this] var initialized = false + def isMirrorInitialized = initialized protected[scala] def rootLoader: LazyType @@ -40,7 +42,7 @@ trait Mirrors extends api.Mirrors { if (point > 0) getModuleOrClass(path.toTermName, point) else RootClass val name = path subName (point + 1, len) - var sym = owner.info member name + val sym = owner.info member name val result = if (path.isTermName) sym.suchThat(_ hasFlag MODULE) else sym if (result != NoSymbol) result else { @@ -76,7 +78,9 @@ trait Mirrors extends api.Mirrors { protected def universeMissingHook(owner: Symbol, name: Name): Symbol = thisUniverse.missingHook(owner, name) - private[scala] def missingHook(owner: Symbol, name: Name): Symbol = mirrorMissingHook(owner, name) orElse universeMissingHook(owner, name) + private[scala] def missingHook(owner: Symbol, name: Name): Symbol = logResult(s"missingHook($owner, $name)")( + mirrorMissingHook(owner, name) orElse universeMissingHook(owner, name) + ) // todo: get rid of most the methods here and keep just staticClass/Module/Package @@ -228,6 +232,7 @@ trait Mirrors extends api.Mirrors { // } def init() { + if (initialized) return // Still fiddling with whether it's cleaner to do some of this setup here // or from constructors. The latter approach tends to invite init order issues. @@ -239,6 +244,8 @@ trait Mirrors extends api.Mirrors { RootClass.info.decls enter EmptyPackage RootClass.info.decls enter RootPackage + + initialized = true } } diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala index c78ba72dfb..333651162e 100644 --- a/src/reflect/scala/reflect/internal/Names.scala +++ b/src/reflect/scala/reflect/internal/Names.scala @@ -135,9 +135,6 @@ trait Names extends api.Names with LowPriorityNames { def newTypeName(bs: Array[Byte], offset: Int, len: Int): TypeName = newTermName(bs, offset, len).toTypeName - def nameChars: Array[Char] = chrs - @deprecated("", "2.9.0") def view(s: String): TermName = newTermName(s) - // Classes ---------------------------------------------------------------------- /** The name class. @@ -186,28 +183,20 @@ trait Names extends api.Names with LowPriorityNames { scala.compat.Platform.arraycopy(chrs, index, cs, offset, len) /** @return the ascii representation of this name */ - final def toChars: Array[Char] = { + final def toChars: Array[Char] = { // used by ide val cs = new Array[Char](len) copyChars(cs, 0) cs } - /** Write to UTF8 representation of this name to given character array. - * Start copying to index `to`. Return index of next free byte in array. - * Array must have enough remaining space for all bytes - * (i.e. maximally 3*length bytes). - */ - final def copyUTF8(bs: Array[Byte], offset: Int): Int = { - val bytes = Codec.toUTF8(chrs, index, len) - scala.compat.Platform.arraycopy(bytes, 0, bs, offset, bytes.length) - offset + bytes.length - } - /** @return the hash value of this name */ final override def hashCode(): Int = index - // Presently disabled. - // override def equals(other: Any) = paranoidEquals(other) + /**** + * This has been quite useful to find places where people are comparing + * a TermName and a TypeName, or a Name and a String. + + override def equals(other: Any) = paranoidEquals(other) private def paranoidEquals(other: Any): Boolean = { val cmp = this eq other.asInstanceOf[AnyRef] if (cmp || !nameDebug) @@ -215,7 +204,7 @@ trait Names extends api.Names with LowPriorityNames { other match { case x: String => - Console.println("Compared " + debugString + " and String '" + x + "'") + Console.println(s"Compared $debugString and String '$x'") case x: Name => if (this.isTermName != x.isTermName) { val panic = this.toTermName == x.toTermName @@ -228,6 +217,7 @@ trait Names extends api.Names with LowPriorityNames { } false } + ****/ /** @return the i'th Char of this name */ final def charAt(i: Int): Char = chrs(index + i) @@ -279,8 +269,6 @@ trait Names extends api.Names with LowPriorityNames { */ final def lastPos(c: Char): Int = lastPos(c, len - 1) - final def lastPos(s: String): Int = lastPos(s, len - s.length) - /** Returns the index of the last occurrence of char c in this * name from start, -1 if not found. * @@ -294,26 +282,6 @@ trait Names extends api.Names with LowPriorityNames { i } - /** Returns the index of the last occurrence of string s in this - * name from start, -1 if not found. - * - * @param s the string - * @param start ... - * @return the index of the last occurrence of s - */ - final def lastPos(s: String, start: Int): Int = { - var i = lastPos(s.charAt(0), start) - while (i >= 0) { - var j = 1; - while (s.charAt(j) == chrs(index + i + j)) { - j += 1 - if (j == s.length()) return i; - } - i = lastPos(s.charAt(0), i - 1) - } - -s.length() - } - /** Does this name start with prefix? */ final def startsWith(prefix: Name): Boolean = startsWith(prefix, 0) @@ -375,7 +343,6 @@ trait Names extends api.Names with LowPriorityNames { if (idx == length) -1 else idx } def lastIndexOf(ch: Char) = lastPos(ch) - def lastIndexOf(ch: Char, fromIndex: Int) = lastPos(ch, fromIndex) /** Replace all occurrences of `from` by `to` in * name; result is always a term name. @@ -424,12 +391,10 @@ trait Names extends api.Names with LowPriorityNames { def append(ch: Char) = newName("" + this + ch) def append(suffix: String) = newName("" + this + suffix) def append(suffix: Name) = newName("" + this + suffix) - def prepend(ch: Char) = newName("" + ch + this) def prepend(prefix: String) = newName("" + prefix + this) - def prepend(prefix: Name) = newName("" + prefix + this) def decodedName: ThisNameType = newName(decode) - def isOperatorName: Boolean = decode != toString + def isOperatorName: Boolean = decode != toString // used by ide def longString: String = nameKind + " " + decode def debugString = { val s = decode ; if (isTypeName) s + "!" else s } } @@ -441,7 +406,6 @@ trait Names extends api.Names with LowPriorityNames { def stripSuffix(suffix: Name): T = if (name endsWith suffix) dropRight(suffix.length) else name def dropRight(n: Int): T = name.subName(0, name.length - n).asInstanceOf[T] def drop(n: Int): T = name.subName(n, name.length).asInstanceOf[T] - def nonEmpty: Boolean = name.length > 0 } implicit val NameTag = ClassTag[Name](classOf[Name]) @@ -485,7 +449,7 @@ trait Names extends api.Names with LowPriorityNames { type ThisNameType = TermName protected[this] def thisName: TermName = this - var next: TermName = termHashtable(hash) + val next: TermName = termHashtable(hash) termHashtable(hash) = this def isTermName: Boolean = true def isTypeName: Boolean = false @@ -514,7 +478,7 @@ trait Names extends api.Names with LowPriorityNames { type ThisNameType = TypeName protected[this] def thisName: TypeName = this - var next: TypeName = typeHashtable(hash) + val next: TypeName = typeHashtable(hash) typeHashtable(hash) = this def isTermName: Boolean = false def isTypeName: Boolean = true diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index 80d247c0ea..c36724e388 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -168,7 +168,7 @@ trait Printers extends api.Printers { self: SymbolTable => ) def printFlags(flags: Long, privateWithin: String) { - var mask: Long = if (settings.debug.value) -1L else PrintableFlags + val mask: Long = if (settings.debug.value) -1L else PrintableFlags val s = flagsToString(flags & mask, privateWithin) if (s != "") print(s + " ") } @@ -475,8 +475,6 @@ trait Printers extends api.Printers { self: SymbolTable => } def newRawTreePrinter(writer: PrintWriter): RawTreePrinter = new RawTreePrinter(writer) - def newRawTreePrinter(stream: OutputStream): RawTreePrinter = newRawTreePrinter(new PrintWriter(stream)) - def newRawTreePrinter(): RawTreePrinter = newRawTreePrinter(new PrintWriter(ConsoleWriter)) // provides footnotes for types and mirrors import scala.collection.mutable.{Map, WeakHashMap, SortedSet} @@ -525,7 +523,7 @@ trait Printers extends api.Printers { self: SymbolTable => private var depth = 0 private var printTypesInFootnotes = true private var printingFootnotes = false - private var footnotes = footnoteIndex.mkFootnotes() + private val footnotes = footnoteIndex.mkFootnotes() def print(args: Any*): Unit = { // don't print type footnotes if the argument is a mere type @@ -545,8 +543,8 @@ trait Printers extends api.Printers { self: SymbolTable => case emptyValDef: AnyRef if emptyValDef eq self.emptyValDef => print("emptyValDef") case tree: Tree => - val hasSymbol = tree.hasSymbol && tree.symbol != NoSymbol - val isError = hasSymbol && tree.symbol.name.toString == nme.ERROR.toString + val hasSymbolField = tree.hasSymbolField && tree.symbol != NoSymbol + val isError = hasSymbolField && tree.symbol.name.toString == nme.ERROR.toString printProduct( tree, preamble = _ => { @@ -559,7 +557,7 @@ trait Printers extends api.Printers { self: SymbolTable => if (isError) print("<") print(name) if (isError) print(": error>") - } else if (hasSymbol) { + } else if (hasSymbolField) { tree match { case refTree: RefTree => if (tree.symbol.name != refTree.name) print("[", tree.symbol, " aka ", refTree.name, "]") diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala index ab3b9b7ed7..04f1d73360 100644 --- a/src/reflect/scala/reflect/internal/Scopes.scala +++ b/src/reflect/scala/reflect/internal/Scopes.scala @@ -8,6 +8,14 @@ package internal trait Scopes extends api.Scopes { self: SymbolTable => + /** An ADT to represent the results of symbol name lookups. + */ + sealed trait NameLookup { def symbol: Symbol } + case class LookupSucceeded(qualifier: Tree, symbol: Symbol) extends NameLookup + case class LookupAmbiguous(msg: String) extends NameLookup { def symbol = NoSymbol } + case class LookupInaccessible(symbol: Symbol, msg: String) extends NameLookup + case object LookupNotFound extends NameLookup { def symbol = NoSymbol } + class ScopeEntry(val sym: Symbol, val owner: Scope) { /** the next entry in the hash bucket */ @@ -17,15 +25,11 @@ trait Scopes extends api.Scopes { self: SymbolTable => */ var next: ScopeEntry = null + def depth = owner.nestingLevel override def hashCode(): Int = sym.name.start - override def toString(): String = sym.toString() + override def toString() = s"$sym (depth=$depth)" } - /** - * @param sym ... - * @param owner ... - * @return ... - */ private def newScopeEntry(sym: Symbol, owner: Scope): ScopeEntry = { val e = new ScopeEntry(sym, owner) e.next = owner.elems @@ -92,8 +96,6 @@ trait Scopes extends api.Scopes { self: SymbolTable => } /** enter a scope entry - * - * @param e ... */ protected def enterEntry(e: ScopeEntry) { elemsCache = null @@ -110,8 +112,6 @@ trait Scopes extends api.Scopes { self: SymbolTable => } /** enter a symbol - * - * @param sym ... */ def enter[T <: Symbol](sym: T): T = { enterEntry(newScopeEntry(sym, this)) @@ -119,8 +119,6 @@ trait Scopes extends api.Scopes { self: SymbolTable => } /** enter a symbol, asserting that no symbol with same name exists in scope - * - * @param sym ... */ def enterUnique(sym: Symbol) { assert(lookup(sym.name) == NoSymbol, (sym.fullLocationString, lookup(sym.name).fullLocationString)) @@ -175,8 +173,6 @@ trait Scopes extends api.Scopes { self: SymbolTable => } /** remove entry - * - * @param e ... */ def unlink(e: ScopeEntry) { if (elems == e) { @@ -208,14 +204,48 @@ trait Scopes extends api.Scopes { self: SymbolTable => } } - /** lookup a symbol - * - * @param name ... - * @return ... + /** Lookup a module or a class, filtering out matching names in scope + * which do not match that requirement. + */ + def lookupModule(name: Name): Symbol = lookupAll(name.toTermName) find (_.isModule) getOrElse NoSymbol + def lookupClass(name: Name): Symbol = lookupAll(name.toTypeName) find (_.isClass) getOrElse NoSymbol + + /** True if the name exists in this scope, false otherwise. */ + def containsName(name: Name) = lookupEntry(name) != null + + /** Lookup a symbol. */ def lookup(name: Name): Symbol = { val e = lookupEntry(name) - if (e eq null) NoSymbol else e.sym + if (e eq null) NoSymbol + else if (lookupNextEntry(e) eq null) e.sym + else { + // We shouldn't get here: until now this method was picking a random + // symbol when there was more than one with the name, so this should + // only be called knowing that there are 0-1 symbols of interest. So, we + // can safely return an overloaded symbol rather than throwing away the + // rest of them. Most likely we still break, but at least we will break + // in an understandable fashion (unexpectedly overloaded symbol) rather + // than a non-deterministic bizarre one (see any bug involving overloads + // in package objects.) + val alts = lookupAll(name).toList + def alts_s = alts map (s => s.defString) mkString " <and> " + devWarning(s"scope lookup of $name found multiple symbols: $alts_s") + // FIXME - how is one supposed to create an overloaded symbol without + // knowing the correct owner? Using the symbol owner is not correct; + // say for instance this is List's scope and the symbols are its three + // mkString members. Those symbols are owned by TraversableLike, which + // is no more meaningful an owner than NoSymbol given that we're in + // List. Maybe it makes no difference who owns the overloaded symbol, in + // which case let's establish that and have a canonical creation method. + // + // FIXME - a similar question for prefix, although there are more + // clues from the symbols on that one, as implemented here. In general + // the distinct list is one type and lub becomes the identity. + // val prefix = lub(alts map (_.info.prefix) distinct) + // Now using NoSymbol and NoPrefix always to avoid forcing info (SI-6664) + NoSymbol.newOverloaded(NoPrefix, alts) + } } /** Returns an iterator yielding every symbol with given name in this scope. @@ -223,7 +253,20 @@ trait Scopes extends api.Scopes { self: SymbolTable => def lookupAll(name: Name): Iterator[Symbol] = new Iterator[Symbol] { var e = lookupEntry(name) def hasNext: Boolean = e ne null - def next(): Symbol = { val r = e.sym; e = lookupNextEntry(e); r } + def next(): Symbol = try e.sym finally e = lookupNextEntry(e) + } + + def lookupAllEntries(name: Name): Iterator[ScopeEntry] = new Iterator[ScopeEntry] { + var e = lookupEntry(name) + def hasNext: Boolean = e ne null + def next(): ScopeEntry = try e finally e = lookupNextEntry(e) + } + + def lookupUnshadowedEntries(name: Name): Iterator[ScopeEntry] = { + lookupEntry(name) match { + case null => Iterator.empty + case e => lookupAllEntries(name) filter (e1 => (e eq e1) || (e.depth == e1.depth && e.sym != e1.sym)) + } } /** lookup a symbol entry matching given name. @@ -287,36 +330,16 @@ trait Scopes extends api.Scopes { self: SymbolTable => */ def iterator: Iterator[Symbol] = toList.iterator -/* - /** Does this scope contain an entry for `sym`? - */ - def contains(sym: Symbol): Boolean = lookupAll(sym.name) contains sym - - /** A scope that contains all symbols of this scope and that also contains `sym`. - */ - def +(sym: Symbol): Scope = - if (contains(sym)) this - else { - val result = cloneScope - result enter sym - result - } - - /** A scope that contains all symbols of this scope except `sym`. - */ - def -(sym: Symbol): Scope = - if (!contains(sym)) this - else { - val result = cloneScope - result unlink sym - result - } -*/ override def foreach[U](p: Symbol => U): Unit = toList foreach p - override def filter(p: Symbol => Boolean): Scope = - if (!(toList forall p)) newScopeWith(toList filter p: _*) else this - + override def filterNot(p: Symbol => Boolean): Scope = ( + if (toList exists p) newScopeWith(toList filterNot p: _*) + else this + ) + override def filter(p: Symbol => Boolean): Scope = ( + if (toList forall p) this + else newScopeWith(toList filter p: _*) + ) @deprecated("Use `toList.reverse` instead", "2.10.0") def reverse: List[Symbol] = toList.reverse diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 5e7f5777b2..a5810c9c83 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -104,7 +104,6 @@ trait StdNames { val IMPORT: NameType = "<import>" val MODULE_SUFFIX_NAME: NameType = MODULE_SUFFIX_STRING val MODULE_VAR_SUFFIX: NameType = "$module" - val NAME_JOIN_NAME: NameType = NAME_JOIN_STRING val PACKAGE: NameType = "package" val ROOT: NameType = "<root>" val SPECIALIZED_SUFFIX: NameType = "$sp" @@ -121,16 +120,12 @@ trait StdNames { final val Short: NameType = "Short" final val Unit: NameType = "Unit" - final val ScalaValueNames: scala.List[NameType] = - scala.List(Byte, Char, Short, Int, Long, Float, Double, Boolean, Unit) - // some types whose companions we utilize final val AnyRef: NameType = "AnyRef" final val Array: NameType = "Array" final val List: NameType = "List" final val Seq: NameType = "Seq" final val Symbol: NameType = "Symbol" - final val ClassTag: NameType = "ClassTag" final val WeakTypeTag: NameType = "WeakTypeTag" final val TypeTag : NameType = "TypeTag" final val Expr: NameType = "Expr" @@ -220,12 +215,10 @@ trait StdNames { final val Any: NameType = "Any" final val AnyVal: NameType = "AnyVal" - final val ExprApi: NameType = "ExprApi" final val Mirror: NameType = "Mirror" final val Nothing: NameType = "Nothing" final val Null: NameType = "Null" final val Object: NameType = "Object" - final val PartialFunction: NameType = "PartialFunction" final val PrefixType: NameType = "PrefixType" final val Product: NameType = "Product" final val Serializable: NameType = "Serializable" @@ -239,7 +232,6 @@ trait StdNames { final val Group: NameType = "Group" final val Tree: NameType = "Tree" final val Type : NameType = "Type" - final val TypeTree: NameType = "TypeTree" // Annotation simple names, used in Namer final val BeanPropertyAnnot: NameType = "BeanProperty" @@ -249,13 +241,11 @@ trait StdNames { // Classfile Attributes final val AnnotationDefaultATTR: NameType = "AnnotationDefault" final val BridgeATTR: NameType = "Bridge" - final val ClassfileAnnotationATTR: NameType = "RuntimeInvisibleAnnotations" // RetentionPolicy.CLASS. Currently not used (Apr 2009). final val CodeATTR: NameType = "Code" final val ConstantValueATTR: NameType = "ConstantValue" final val DeprecatedATTR: NameType = "Deprecated" final val ExceptionsATTR: NameType = "Exceptions" final val InnerClassesATTR: NameType = "InnerClasses" - final val LineNumberTableATTR: NameType = "LineNumberTable" final val LocalVariableTableATTR: NameType = "LocalVariableTable" final val RuntimeAnnotationATTR: NameType = "RuntimeVisibleAnnotations" // RetentionPolicy.RUNTIME final val RuntimeParamAnnotationATTR: NameType = "RuntimeVisibleParameterAnnotations" // RetentionPolicy.RUNTIME (annotations on parameters) @@ -284,9 +274,6 @@ trait StdNames { val EXCEPTION_RESULT_PREFIX = "exceptionResult" val EXPAND_SEPARATOR_STRING = "$$" val INTERPRETER_IMPORT_WRAPPER = "$iw" - val INTERPRETER_LINE_PREFIX = "line" - val INTERPRETER_VAR_PREFIX = "res" - val INTERPRETER_WRAPPER_SUFFIX = "$object" val LOCALDUMMY_PREFIX = "<local " // owner of local blocks val PROTECTED_PREFIX = "protected$" val PROTECTED_SET_PREFIX = PROTECTED_PREFIX + "set" @@ -304,7 +291,6 @@ trait StdNames { val LAZY_SLOW_SUFFIX: NameType = "$lzycompute" val LOCAL_SUFFIX_STRING = " " val UNIVERSE_BUILD_PREFIX: NameType = "$u.build." - val UNIVERSE_BUILD: NameType = "$u.build" val UNIVERSE_PREFIX: NameType = "$u." val UNIVERSE_SHORT: NameType = "$u" val MIRROR_PREFIX: NameType = "$m." @@ -339,7 +325,6 @@ trait StdNames { def isLocalName(name: Name) = name endsWith LOCAL_SUFFIX_STRING def isLoopHeaderLabel(name: Name) = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX) def isProtectedAccessorName(name: Name) = name startsWith PROTECTED_PREFIX - def isSuperAccessorName(name: Name) = name startsWith SUPER_PREFIX_STRING def isReplWrapperName(name: Name) = name containsName INTERPRETER_IMPORT_WRAPPER def isSetterName(name: Name) = name endsWith SETTER_SUFFIX def isTraitSetterName(name: Name) = isSetterName(name) && (name containsName TRAIT_SETTER_SEPARATOR_STRING) @@ -356,11 +341,6 @@ trait StdNames { ) } - def isDeprecatedIdentifierName(name: Name) = name.toTermName match { - case nme.`then` | nme.`macro` => true - case _ => false - } - def isOpAssignmentName(name: Name) = name match { case raw.NE | raw.LE | raw.GE | EMPTY => false case _ => @@ -395,18 +375,6 @@ trait StdNames { else name ) - /* - def anonNumberSuffix(name: Name): Name = { - ("" + name) lastIndexOf '$' match { - case -1 => nme.EMPTY - case idx => - val s = name drop idx - if (s.toString forall (_.isDigit)) s - else nme.EMPTY - } - } - */ - /** Return the original name and the types on which this name * is specialized. For example, * {{{ @@ -458,18 +426,6 @@ trait StdNames { } else name.toTermName } - // If the name ends with $nn where nn are - // all digits, strip the $ and the digits. - // Otherwise return the argument. - def stripAnonNumberSuffix(name: Name): Name = { - var pos = name.length - while (pos > 0 && name.charAt(pos - 1).isDigit) - pos -= 1 - - if (pos <= 0 || pos == name.length || name.charAt(pos - 1) != '$') name - else name.subName(0, pos - 1) - } - def stripModuleSuffix(name: Name): Name = ( if (isModuleName(name)) name dropRight MODULE_SUFFIX_STRING.length else name ) @@ -484,8 +440,6 @@ trait StdNames { final val Nil: NameType = "Nil" final val Predef: NameType = "Predef" - final val ScalaRunTime: NameType = "ScalaRunTime" - final val Some: NameType = "Some" val _1 : NameType = "_1" val _2 : NameType = "_2" @@ -581,14 +535,10 @@ trait StdNames { val Annotation: NameType = "Annotation" val Any: NameType = "Any" val AnyVal: NameType = "AnyVal" - val AppliedTypeTree: NameType = "AppliedTypeTree" - val Apply: NameType = "Apply" val ArrayAnnotArg: NameType = "ArrayAnnotArg" - val Constant: NameType = "Constant" val ConstantType: NameType = "ConstantType" val EmptyPackage: NameType = "EmptyPackage" val EmptyPackageClass: NameType = "EmptyPackageClass" - val ExistentialTypeTree: NameType = "ExistentialTypeTree" val Flag : NameType = "Flag" val Ident: NameType = "Ident" val Import: NameType = "Import" @@ -597,10 +547,8 @@ trait StdNames { val Modifiers: NameType = "Modifiers" val NestedAnnotArg: NameType = "NestedAnnotArg" val NoFlags: NameType = "NoFlags" - val NoPrefix: NameType = "NoPrefix" val NoSymbol: NameType = "NoSymbol" val Nothing: NameType = "Nothing" - val NoType: NameType = "NoType" val Null: NameType = "Null" val Object: NameType = "Object" val RootPackage: NameType = "RootPackage" @@ -609,17 +557,14 @@ trait StdNames { val StringContext: NameType = "StringContext" val This: NameType = "This" val ThisType: NameType = "ThisType" - val Tree : NameType = "Tree" val Tuple2: NameType = "Tuple2" val TYPE_ : NameType = "TYPE" - val TypeApply: NameType = "TypeApply" val TypeRef: NameType = "TypeRef" val TypeTree: NameType = "TypeTree" val UNIT : NameType = "UNIT" val add_ : NameType = "add" val annotation: NameType = "annotation" val anyValClass: NameType = "anyValClass" - val append: NameType = "append" val apply: NameType = "apply" val applyDynamic: NameType = "applyDynamic" val applyDynamicNamed: NameType = "applyDynamicNamed" @@ -627,34 +572,24 @@ trait StdNames { val args : NameType = "args" val argv : NameType = "argv" val arrayClass: NameType = "arrayClass" - val arrayElementClass: NameType = "arrayElementClass" - val arrayValue: NameType = "arrayValue" val array_apply : NameType = "array_apply" val array_clone : NameType = "array_clone" val array_length : NameType = "array_length" val array_update : NameType = "array_update" - val arraycopy: NameType = "arraycopy" - val asTerm: NameType = "asTerm" val asModule: NameType = "asModule" - val asMethod: NameType = "asMethod" val asType: NameType = "asType" - val asClass: NameType = "asClass" val asInstanceOf_ : NameType = "asInstanceOf" val asInstanceOf_Ob : NameType = "$asInstanceOf" - val assert_ : NameType = "assert" - val assume_ : NameType = "assume" val box: NameType = "box" val build : NameType = "build" val bytes: NameType = "bytes" val canEqual_ : NameType = "canEqual" val checkInitialized: NameType = "checkInitialized" - val ClassManifestFactory: NameType = "ClassManifestFactory" val classOf: NameType = "classOf" val clone_ : NameType = if (forMSIL) "MemberwiseClone" else "clone" // sn.OClone causes checkinit failure val conforms: NameType = "conforms" val copy: NameType = "copy" val currentMirror: NameType = "currentMirror" - val definitions: NameType = "definitions" val delayedInit: NameType = "delayedInit" val delayedInitArg: NameType = "delayedInit$body" val drop: NameType = "drop" @@ -667,7 +602,6 @@ trait StdNames { val equalsNumObject : NameType = "equalsNumObject" val equals_ : NameType = if (forMSIL) "Equals" else "equals" val error: NameType = "error" - val eval: NameType = "eval" val ex: NameType = "ex" val experimental: NameType = "experimental" val f: NameType = "f" @@ -678,17 +612,11 @@ trait StdNames { val flagsFromBits : NameType = "flagsFromBits" val flatMap: NameType = "flatMap" val foreach: NameType = "foreach" - val genericArrayOps: NameType = "genericArrayOps" val get: NameType = "get" - val getOrElse: NameType = "getOrElse" - val hasNext: NameType = "hasNext" val hashCode_ : NameType = if (forMSIL) "GetHashCode" else "hashCode" val hash_ : NameType = "hash" - val head: NameType = "head" - val identity: NameType = "identity" val implicitly: NameType = "implicitly" val in: NameType = "in" - val info: NameType = "info" val inlinedEquals: NameType = "inlinedEquals" val isArray: NameType = "isArray" val isDefinedAt: NameType = "isDefinedAt" @@ -700,57 +628,42 @@ trait StdNames { val lang: NameType = "lang" val length: NameType = "length" val lengthCompare: NameType = "lengthCompare" - val liftedTree: NameType = "liftedTree" - val `macro` : NameType = "macro" - val macroThis : NameType = "_this" val macroContext : NameType = "c" val main: NameType = "main" - val manifest: NameType = "manifest" - val ManifestFactory: NameType = "ManifestFactory" val manifestToTypeTag: NameType = "manifestToTypeTag" val map: NameType = "map" val materializeClassTag: NameType = "materializeClassTag" val materializeWeakTypeTag: NameType = "materializeWeakTypeTag" val materializeTypeTag: NameType = "materializeTypeTag" - val mirror : NameType = "mirror" val moduleClass : NameType = "moduleClass" - val name: NameType = "name" val ne: NameType = "ne" val newArray: NameType = "newArray" val newFreeTerm: NameType = "newFreeTerm" val newFreeType: NameType = "newFreeType" val newNestedSymbol: NameType = "newNestedSymbol" val newScopeWith: NameType = "newScopeWith" - val next: NameType = "next" val nmeNewTermName: NameType = "newTermName" val nmeNewTypeName: NameType = "newTypeName" - val normalize: NameType = "normalize" val notifyAll_ : NameType = "notifyAll" val notify_ : NameType = "notify" val null_ : NameType = "null" - val ofDim: NameType = "ofDim" - val origin: NameType = "origin" val prefix : NameType = "prefix" val productArity: NameType = "productArity" val productElement: NameType = "productElement" val productIterator: NameType = "productIterator" val productPrefix: NameType = "productPrefix" val readResolve: NameType = "readResolve" - val reflect : NameType = "reflect" val reify : NameType = "reify" val rootMirror : NameType = "rootMirror" - val runOrElse: NameType = "runOrElse" val runtime: NameType = "runtime" val runtimeClass: NameType = "runtimeClass" val runtimeMirror: NameType = "runtimeMirror" - val sameElements: NameType = "sameElements" val scala_ : NameType = "scala" val selectDynamic: NameType = "selectDynamic" val selectOverloadedMethod: NameType = "selectOverloadedMethod" val selectTerm: NameType = "selectTerm" val selectType: NameType = "selectType" val self: NameType = "self" - val setAccessible: NameType = "setAccessible" val setAnnotations: NameType = "setAnnotations" val setSymbol: NameType = "setSymbol" val setType: NameType = "setType" @@ -760,15 +673,10 @@ trait StdNames { val staticModule : NameType = "staticModule" val staticPackage : NameType = "staticPackage" val synchronized_ : NameType = "synchronized" - val tail: NameType = "tail" - val `then` : NameType = "then" val this_ : NameType = "this" val thisPrefix : NameType = "thisPrefix" - val throw_ : NameType = "throw" val toArray: NameType = "toArray" - val toList: NameType = "toList" val toObjectArray : NameType = "toObjectArray" - val toSeq: NameType = "toSeq" val toString_ : NameType = if (forMSIL) "ToString" else "toString" val toTypeConstructor: NameType = "toTypeConstructor" val tpe : NameType = "tpe" @@ -788,14 +696,9 @@ trait StdNames { val view_ : NameType = "view" val wait_ : NameType = "wait" val withFilter: NameType = "withFilter" - val wrap: NameType = "wrap" - val zip: NameType = "zip" - - val synthSwitch: NameType = "$synthSwitch" // unencoded operators object raw { - final val AMP : NameType = "&" final val BANG : NameType = "!" final val BAR : NameType = "|" final val DOLLAR: NameType = "$" @@ -804,7 +707,6 @@ trait StdNames { final val MINUS: NameType = "-" final val NE: NameType = "!=" final val PLUS : NameType = "+" - final val SLASH: NameType = "/" final val STAR : NameType = "*" final val TILDE: NameType = "~" @@ -860,14 +762,7 @@ trait StdNames { // Grouped here so Cleanup knows what tests to perform. val CommonOpNames = Set[Name](OR, XOR, AND, EQ, NE) - val ConversionNames = Set[Name](toByte, toChar, toDouble, toFloat, toInt, toLong, toShort) val BooleanOpNames = Set[Name](ZOR, ZAND, UNARY_!) ++ CommonOpNames - val NumberOpNames = ( - Set[Name](ADD, SUB, MUL, DIV, MOD, LSL, LSR, ASR, LT, LE, GE, GT) - ++ Set(UNARY_+, UNARY_-, UNARY_!) - ++ ConversionNames - ++ CommonOpNames - ) val add: NameType = "add" val complement: NameType = "complement" @@ -999,7 +894,6 @@ trait StdNames { object fulltpnme extends TypeNames { val RuntimeNothing: NameType = "scala.runtime.Nothing$" val RuntimeNull: NameType = "scala.runtime.Null$" - val JavaLangEnum: NameType = "java.lang.Enum" } /** Java binary names, like scala/runtime/Nothing$. @@ -1014,16 +908,11 @@ trait StdNames { val javanme = nme.javaKeywords object nme extends TermNames { - - def isModuleVarName(name: Name): Boolean = - stripAnonNumberSuffix(name) endsWith MODULE_VAR_SUFFIX - def moduleVarName(name: TermName): TermName = newTermNameCached("" + name + MODULE_VAR_SUFFIX) def getCause = sn.GetCause def getClass_ = sn.GetClass - def getComponentType = sn.GetComponentType def getMethod_ = sn.GetMethod def invoke_ = sn.Invoke @@ -1036,15 +925,6 @@ trait StdNames { val reflMethodCacheName: NameType = "reflMethod$Cache" val reflMethodName: NameType = "reflMethod$Method" - private val reflectionCacheNames = Set[NameType]( - reflPolyCacheName, - reflClassCacheName, - reflParamsCacheName, - reflMethodCacheName, - reflMethodName - ) - def isReflectionCacheName(name: Name) = reflectionCacheNames exists (name startsWith _) - @deprecated("Use a method in tpnme", "2.10.0") def dropSingletonName(name: Name): TypeName = tpnme.dropSingletonName(name) @deprecated("Use a method in tpnme", "2.10.0") def singletonName(name: Name): TypeName = tpnme.singletonName(name) @deprecated("Use a method in tpnme", "2.10.0") def implClassName(name: Name): TypeName = tpnme.implClassName(name) @@ -1056,28 +936,21 @@ trait StdNames { protected val stringToTypeName = null protected implicit def createNameType(s: String): TypeName = newTypeNameCached(s) - val BeanProperty : TypeName - val BooleanBeanProperty : TypeName val BoxedBoolean : TypeName val BoxedCharacter : TypeName val BoxedNumber : TypeName - val Class : TypeName val Delegate : TypeName val IOOBException : TypeName // IndexOutOfBoundsException val InvTargetException : TypeName // InvocationTargetException - val JavaSerializable : TypeName val MethodAsObject : TypeName val NPException : TypeName // NullPointerException val Object : TypeName - val String : TypeName val Throwable : TypeName val ValueType : TypeName - val ForName : TermName val GetCause : TermName val GetClass : TermName val GetClassLoader : TermName - val GetComponentType : TermName val GetMethod : TermName val Invoke : TermName val JavaLang : TermName @@ -1152,22 +1025,18 @@ trait StdNames { final val BoxedLong: TypeName = "java.lang.Long" final val BoxedNumber: TypeName = "java.lang.Number" final val BoxedShort: TypeName = "java.lang.Short" - final val Class: TypeName = "java.lang.Class" final val Delegate: TypeName = tpnme.NO_NAME final val IOOBException: TypeName = "java.lang.IndexOutOfBoundsException" final val InvTargetException: TypeName = "java.lang.reflect.InvocationTargetException" final val MethodAsObject: TypeName = "java.lang.reflect.Method" final val NPException: TypeName = "java.lang.NullPointerException" final val Object: TypeName = "java.lang.Object" - final val String: TypeName = "java.lang.String" final val Throwable: TypeName = "java.lang.Throwable" final val ValueType: TypeName = tpnme.NO_NAME - final val ForName: TermName = newTermName("forName") final val GetCause: TermName = newTermName("getCause") final val GetClass: TermName = newTermName("getClass") final val GetClassLoader: TermName = newTermName("getClassLoader") - final val GetComponentType: TermName = newTermName("getComponentType") final val GetMethod: TermName = newTermName("getMethod") final val Invoke: TermName = newTermName("invoke") final val JavaLang: TermName = newTermName("java.lang") @@ -1185,28 +1054,21 @@ trait StdNames { } private class MSILNames extends SymbolNames { - final val BeanProperty: TypeName = tpnme.NO_NAME - final val BooleanBeanProperty: TypeName = tpnme.NO_NAME final val BoxedBoolean: TypeName = "System.IConvertible" final val BoxedCharacter: TypeName = "System.IConvertible" final val BoxedNumber: TypeName = "System.IConvertible" - final val Class: TypeName = "System.Type" final val Delegate: TypeName = "System.MulticastDelegate" final val IOOBException: TypeName = "System.IndexOutOfRangeException" final val InvTargetException: TypeName = "System.Reflection.TargetInvocationException" - final val JavaSerializable: TypeName = tpnme.NO_NAME final val MethodAsObject: TypeName = "System.Reflection.MethodInfo" final val NPException: TypeName = "System.NullReferenceException" final val Object: TypeName = "System.Object" - final val String: TypeName = "System.String" final val Throwable: TypeName = "System.Exception" final val ValueType: TypeName = "System.ValueType" - final val ForName: TermName = newTermName("GetType") final val GetCause: TermName = newTermName("InnerException") /* System.Reflection.TargetInvocationException.InnerException */ final val GetClass: TermName = newTermName("GetType") final lazy val GetClassLoader: TermName = throw new UnsupportedOperationException("Scala reflection is not supported on this platform"); - final val GetComponentType: TermName = newTermName("GetElementType") final val GetMethod: TermName = newTermName("GetMethod") final val Invoke: TermName = newTermName("Invoke") final val JavaLang: TermName = newTermName("System") @@ -1223,13 +1085,7 @@ trait StdNames { ) } - private class J2SENames extends JavaNames { - final val BeanProperty: TypeName = "scala.beans.BeanProperty" - final val BooleanBeanProperty: TypeName = "scala.beans.BooleanBeanProperty" - final val JavaSerializable: TypeName = "java.io.Serializable" - } - lazy val sn: SymbolNames = if (forMSIL) new MSILNames - else new J2SENames + else new JavaNames { } } diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index 02ac59a461..1298fc17ed 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -49,24 +49,28 @@ abstract class SymbolTable extends macros.Universe def abort(msg: String): Nothing = throw new FatalError(supplementErrorMessage(msg)) def shouldLogAtThisPhase = false + def isPastTyper = false @deprecated("Give us a reason", "2.10.0") def abort(): Nothing = abort("unknown error") + @deprecated("Use devWarning if this is really a warning; otherwise use log", "2.11.0") + def debugwarn(msg: => String): Unit = devWarning(msg) + /** Override with final implementation for inlining. */ def debuglog(msg: => String): Unit = if (settings.debug.value) log(msg) - def debugwarn(msg: => String): Unit = if (settings.debug.value) Console.err.println(msg) + def devWarning(msg: => String): Unit = if (settings.debug.value) Console.err.println(msg) def throwableAsString(t: Throwable): String = "" + t /** Prints a stack trace if -Ydebug or equivalent was given, otherwise does nothing. */ - def debugStack(t: Throwable): Unit = debugwarn(throwableAsString(t)) + def debugStack(t: Throwable): Unit = devWarning(throwableAsString(t)) /** Overridden when we know more about what was happening during a failure. */ def supplementErrorMessage(msg: String): String = msg private[scala] def printCaller[T](msg: String)(result: T) = { Console.err.println("%s: %s\nCalled from: %s".format(msg, result, - (new Throwable).getStackTrace.drop(2).take(15).mkString("\n"))) + (new Throwable).getStackTrace.drop(2).take(50).mkString("\n"))) result } @@ -139,7 +143,7 @@ abstract class SymbolTable extends macros.Universe type RunId = Int final val NoRunId = 0 - // sigh, this has to be public or atPhase doesn't inline. + // sigh, this has to be public or enteringPhase doesn't inline. var phStack: List[Phase] = Nil private[this] var ph: Phase = NoPhase private[this] var per = NoPeriod @@ -182,9 +186,6 @@ abstract class SymbolTable extends macros.Universe /** The phase identifier of the given period. */ final def phaseId(period: Period): Phase#Id = period & 0xFF - /** The period at the start of run that includes `period`. */ - final def startRun(period: Period): Period = period & 0xFFFFFF00 - /** The current period. */ final def currentPeriod: Period = { //assert(per == (currentRunId << 8) + phase.id) @@ -202,23 +203,17 @@ abstract class SymbolTable extends macros.Universe p != NoPhase && phase.id > p.id /** Perform given operation at given phase. */ - @inline final def atPhase[T](ph: Phase)(op: => T): T = { + @inline final def enteringPhase[T](ph: Phase)(op: => T): T = { val saved = pushPhase(ph) try op finally popPhase(saved) } + @inline final def exitingPhase[T](ph: Phase)(op: => T): T = enteringPhase(ph.next)(op) + @inline final def enteringPrevPhase[T](op: => T): T = enteringPhase(phase.prev)(op) - /** Since when it is to be "at" a phase is inherently ambiguous, - * a couple unambiguously named methods. - */ - @inline final def beforePhase[T](ph: Phase)(op: => T): T = atPhase(ph)(op) - @inline final def afterPhase[T](ph: Phase)(op: => T): T = atPhase(ph.next)(op) - @inline final def afterCurrentPhase[T](op: => T): T = atPhase(phase.next)(op) - @inline final def beforePrevPhase[T](op: => T): T = atPhase(phase.prev)(op) - - @inline final def atPhaseNotLaterThan[T](target: Phase)(op: => T): T = - if (isAtPhaseAfter(target)) atPhase(target)(op) else op + @inline final def enteringPhaseNotLaterThan[T](target: Phase)(op: => T): T = + if (isAtPhaseAfter(target)) enteringPhase(target)(op) else op final def isValid(period: Period): Boolean = period != 0 && runId(period) == currentRunId && { @@ -303,7 +298,6 @@ abstract class SymbolTable extends macros.Universe object perRunCaches { import java.lang.ref.WeakReference - import scala.runtime.ScalaRunTime.stringOf import scala.collection.generic.Clearable // Weak references so the garbage collector will take care of @@ -346,11 +340,15 @@ abstract class SymbolTable extends macros.Universe */ def isCompilerUniverse = false + @deprecated("Use enteringPhase", "2.10.0") + @inline final def atPhase[T](ph: Phase)(op: => T): T = enteringPhase(ph)(op) + @deprecated("Use enteringPhaseNotLaterThan", "2.10.0") + @inline final def atPhaseNotLaterThan[T](target: Phase)(op: => T): T = enteringPhaseNotLaterThan(target)(op) + /** * Adds the `sm` String interpolator to a [[scala.StringContext]]. */ implicit val StringContextStripMarginOps: StringContext => StringContextStripMarginOps = util.StringContextStripMarginOps - } object SymbolTableStats { diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index a27afe9dfd..7de53a7731 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -8,7 +8,7 @@ package internal import scala.collection.{ mutable, immutable } import scala.collection.mutable.ListBuffer -import util.Statistics +import util.{ Statistics, shortClassOfInstance } import Flags._ import scala.annotation.tailrec import scala.reflect.io.AbstractFile @@ -19,8 +19,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => protected var ids = 0 - val emptySymbolArray = new Array[Symbol](0) - protected def nextId() = { ids += 1; ids } /** Used for deciding in the IDE whether we can interrupt the compiler */ @@ -182,7 +180,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => if (isGADTSkolem) " (this is a GADT skolem)" else "" - def shortSymbolClass = getClass.getName.split('.').last.stripPrefix("Symbols$") + def shortSymbolClass = shortClassOfInstance(this) def symbolCreationString: String = ( "%s%25s | %-40s | %s".format( if (settings.uniqid.value) "%06d | ".format(id) else "", @@ -256,9 +254,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => (m, c) } - final def newPackageSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleSymbol = - newTermSymbol(name, pos, newFlags).asInstanceOf[ModuleSymbol] - final def newModuleClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleClassSymbol = newClassSymbol(name, pos, newFlags).asInstanceOf[ModuleClassSymbol] @@ -321,11 +316,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => () => { cnt += 1; nme.syntheticParamName(cnt) } } - /** Synthetic value parameters when parameter symbols are not available - */ - final def newSyntheticValueParamss(argtypess: List[List[Type]]): List[List[TermSymbol]] = - argtypess map (xs => newSyntheticValueParams(xs, freshNamer)) - /** Synthetic value parameters when parameter symbols are not available. * Calling this method multiple times will re-use the same parameter names. */ @@ -341,7 +331,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def newSyntheticValueParam(argtype: Type, name: TermName = nme.syntheticParamName(1)): TermSymbol = newValueParameter(name, owner.pos.focus, SYNTHETIC) setInfo argtype - def newSyntheticTypeParam(): TypeSymbol = newSyntheticTypeParam("T0", 0L) def newSyntheticTypeParam(name: String, newFlags: Long): TypeSymbol = newTypeParameter(newTypeName(name), NoPosition, newFlags) setInfo TypeBounds.empty def newSyntheticTypeParams(num: Int): List[TypeSymbol] = (0 until num).toList map (n => newSyntheticTypeParam("T" + n, 0L)) @@ -405,14 +394,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def newRefinementClass(pos: Position): RefinementClassSymbol = createRefinementClassSymbol(pos, 0L) - /** Create a new getter for current symbol (which must be a field) - */ - final def newGetter: MethodSymbol = ( - owner.newMethod(nme.getterName(name.toTermName), NoPosition, getterFlags(flags)) - setPrivateWithin privateWithin - setInfo MethodType(Nil, tpe) - ) - final def newErrorSymbol(name: Name): Symbol = name match { case x: TypeName => newErrorClass(x) case x: TermName => newErrorValue(x) @@ -528,14 +509,12 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ def isContravariant = false def isCovariant = false - def isExistentialQuantified = false def isExistentialSkolem = false def isExistentiallyBound = false def isGADTSkolem = false def isTypeParameter = false def isTypeParameterOrSkolem = false def isTypeSkolem = false - def isTypeMacro = false def isInvariant = !isCovariant && !isContravariant /** Qualities of Terms, always false for TypeSymbols. @@ -642,7 +621,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isStaticModule = isModule && isStatic && !isMethod final def isThisSym = isTerm && owner.thisSym == this final def isError = hasFlag(IS_ERROR) - final def isErroneous = isError || isInitialized && tpe.isErroneous + final def isErroneous = isError || isInitialized && tpe_*.isErroneous def isHigherOrderTypeParameter = owner.isTypeParameterOrSkolem @@ -709,10 +688,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => } def isStrictFP = hasAnnotation(ScalaStrictFPAttr) || (enclClass hasAnnotation ScalaStrictFPAttr) - def isSerializable = ( - info.baseClasses.exists(p => p == SerializableClass || p == JavaSerializableClass) - || hasAnnotation(SerializableAttr) // last part can be removed, @serializable annotation is deprecated - ) + def isSerializable = info.baseClasses.exists(p => p == SerializableClass || p == JavaSerializableClass) def hasBridgeAnnotation = hasAnnotation(BridgeClass) def isDeprecated = hasAnnotation(DeprecatedAttr) def deprecationMessage = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 0) @@ -722,14 +698,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => = hasAnnotation(DeprecatedInheritanceAttr) def deprecatedInheritanceMessage = getAnnotation(DeprecatedInheritanceAttr) flatMap (_ stringArg 0) - def deprecatedInheritanceVersion - = getAnnotation(DeprecatedInheritanceAttr) flatMap (_ stringArg 1) def hasDeprecatedOverridingAnnotation = hasAnnotation(DeprecatedOverridingAttr) def deprecatedOverridingMessage = getAnnotation(DeprecatedOverridingAttr) flatMap (_ stringArg 0) - def deprecatedOverridingVersion - = getAnnotation(DeprecatedOverridingAttr) flatMap (_ stringArg 1) // !!! when annotation arguments are not literal strings, but any sort of // assembly of strings, there is a fair chance they will turn up here not as @@ -809,7 +781,13 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isStaticOwner: Boolean = isPackageClass || isModuleClass && isStatic - def isTopLevelModule = hasFlag(MODULE) && owner.isPackageClass + /** A helper function for isEffectivelyFinal. */ + private def isNotOverridden = ( + owner.isClass && ( + owner.isEffectivelyFinal + || owner.isSealed && owner.children.forall(c => c.isEffectivelyFinal && (overridingSymbol(c) == NoSymbol)) + ) + ) /** Is this symbol effectively final? I.e, it cannot be overridden */ final def isEffectivelyFinal: Boolean = ( @@ -818,8 +796,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => || isTerm && ( isPrivate || isLocal - || owner.isClass && owner.isEffectivelyFinal - ) + || isNotOverridden + ) ) /** Is this symbol locally defined? I.e. not accessed from outside `this` instance */ @@ -839,12 +817,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ def isLocalClass = false - def isStableClass = false - -/* code for fixing nested objects - override final def isModuleClass: Boolean = - super.isModuleClass && !isExpandedModuleClass -*/ /** Is this class or type defined as a structural refinement type? */ final def isStructuralRefinement: Boolean = @@ -863,17 +835,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isStructuralRefinementMember = owner.isStructuralRefinement && isPossibleInRefinement && isPublic final def isPossibleInRefinement = !isConstructor && !isOverridingSymbol - /** Is this symbol a member of class `clazz`? */ - def isMemberOf(clazz: Symbol) = - clazz.info.member(name).alternatives contains this - /** A a member of class `base` is incomplete if * (1) it is declared deferred or * (2) it is abstract override and its super symbol in `base` is * nonexistent or incomplete. - * - * @param base ... - * @return ... */ final def isIncompleteIn(base: Symbol): Boolean = this.isDeferred || @@ -967,6 +932,14 @@ trait Symbols extends api.Symbols { self: SymbolTable => def ownerChain: List[Symbol] = this :: owner.ownerChain def originalOwnerChain: List[Symbol] = this :: originalOwner.getOrElse(this, rawowner).originalOwnerChain + // All the symbols overridden by this symbol and this symbol at the head, + // or Nil if this is NoSymbol. + def overrideChain = ( + if (this eq NoSymbol) Nil + else if (!owner.isClass) this :: Nil + else this :: allOverriddenSymbols + ) + // Non-classes skip self and return rest of owner chain; overridden in ClassSymbol. def enclClassChain: List[Symbol] = owner.enclClassChain @@ -1076,9 +1049,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => protected def createImplClassSymbol(name: TypeName, pos: Position, newFlags: Long): ClassSymbol = new ClassSymbol(this, pos, name) with ImplClassSymbol initFlags newFlags - protected def createTermSymbol(name: TermName, pos: Position, newFlags: Long): TermSymbol = - new TermSymbol(this, pos, name) initFlags newFlags - protected def createMethodSymbol(name: TermName, pos: Position, newFlags: Long): MethodSymbol = new MethodSymbol(this, pos, name) initFlags newFlags @@ -1181,16 +1151,57 @@ trait Symbols extends api.Symbols { self: SymbolTable => } } - /** Get type. The type of a symbol is: - * for a type symbol, the type corresponding to the symbol itself, - * @M you should use tpeHK for a type symbol with type parameters if - * the kind of the type need not be *, as tpe introduces dummy arguments - * to generate a type of kind * - * for a term symbol, its usual type. - * See the tpe/tpeHK overrides in TypeSymbol for more. + /** The "type" of this symbol. The type of a term symbol is its usual + * type. A TypeSymbol is more complicated; see that class for elaboration. + * Since tpe forwards to tpe_*, if you call it on a type symbol with unapplied + * type parameters, the type returned will contain dummies types. These will + * hide legitimate errors or create spurious ones if used as normal types. */ - def tpe: Type = info - def tpeHK: Type = tpe + final def tpe: Type = tpe_* + + /** typeConstructor throws an exception when called on term + * symbols; this is a more forgiving alternative. Calls + * typeConstructor on TypeSymbols, returns info otherwise. + */ + def tpeHK: Type = info + + /** Only applicable to TypeSymbols, it is the type corresponding + * to the symbol itself. For instance, the type of a List might + * be List[Int] - the same symbol's typeConstructor is simply List. + * One might be tempted to write that as List[_], and in some + * contexts this is possible, but it is discouraged because it is + * syntactically indistinguishable from and easily confused with the + * type List[T] forSome { type T; }, which can also be written List[_]. + */ + def typeConstructor: Type = ( + // Avoiding a third override in NoSymbol to preserve bimorphism + if (this eq NoSymbol) + abort("no-symbol does not have a type constructor (this may indicate scalac cannot find fundamental classes)") + else + abort("typeConstructor inapplicable for " + this) + ) + + /** The type of this symbol, guaranteed to be of kind *. + * If there are unapplied type parameters, they will be + * substituted with dummy type arguments derived from the + * type parameters. Such types are not valid in a general + * sense and will cause difficult-to-find bugs if allowed + * to roam free. + * + * If you call tpe_* explicitly to obtain these types, + * you are responsible for them as if it they were your own + * minor children. + */ + def tpe_* : Type = info + + // Alternate implementation of def tpe for warning about misuse, + // disabled to keep the method maximally hotspot-friendly: + // def tpe: Type = { + // val result = tpe_* + // if (settings.debug.value && result.typeArgs.nonEmpty) + // printCaller(s"""Call to ${this.tpe} created $result: call tpe_* or tpeHK""")("") + // result + // } /** Get type info associated with symbol at current phase, after * ensuring that symbol is initialized (i.e. type is completed). @@ -1226,13 +1237,13 @@ trait Symbols extends api.Symbols { self: SymbolTable => cnt += 1 // allow for two completions: // one: sourceCompleter to LazyType, two: LazyType to completed type - if (cnt == 3) abort("no progress in completing " + this + ":" + tp) + if (cnt == 3) abort(s"no progress in completing $this: $tp") } rawInfo } catch { case ex: CyclicReference => - debugwarn("... hit cycle trying to complete " + this.fullLocationString) + devWarning("... hit cycle trying to complete " + this.fullLocationString) throw ex } @@ -1244,9 +1255,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => } /** Set initial info. */ - def setInfo(info: Type): this.type = { info_=(info); this } + def setInfo(info: Type): this.type = { info_=(info); this } /** Modifies this symbol's info in place. */ - def modifyInfo(f: Type => Type): this.type = setInfo(f(info)) + def modifyInfo(f: Type => Type): this.type = setInfo(f(info)) /** Substitute second list of symbols for first in current info. */ def substInfo(syms0: List[Symbol], syms1: List[Symbol]): this.type = if (syms0.isEmpty) this @@ -1357,6 +1368,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => if (!isInitialized) info this } + def maybeInitialize = { + try { initialize ; true } + catch { case _: CyclicReference => debuglog("Hit cycle in maybeInitialize of $this") ; false } + } /** Called when the programmer requests information that might require initialization of the underlying symbol. * @@ -1399,14 +1414,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => !isInitialized && (flags & LOCKED) == 0 && shouldTriggerCompleter(this, if (infos ne null) infos.info else null, isFlagRelated, mask) /** Was symbol's type updated during given phase? */ - final def isUpdatedAt(pid: Phase#Id): Boolean = { - assert(isCompilerUniverse) - var infos = this.infos - while ((infos ne null) && phaseId(infos.validFrom) != pid + 1) infos = infos.prev - infos ne null - } - - /** Was symbol's type updated during given phase? */ final def hasTypeAt(pid: Phase#Id): Boolean = { assert(isCompilerUniverse) var infos = this.infos @@ -1419,21 +1426,18 @@ trait Symbols extends api.Symbols { self: SymbolTable => * This is done in checkAccessible and overriding checks in refchecks * We can't do this on class loading because it would result in infinite cycles. */ - final def cookJavaRawInfo() { - if (hasFlag(TRIEDCOOKING)) return else setFlag(TRIEDCOOKING) // only try once... - val oldInfo = info - doCookJavaRawInfo() - } + def cookJavaRawInfo(): Unit = { + // only try once... + if (this hasFlag TRIEDCOOKING) + return - protected def doCookJavaRawInfo(): Unit - - /** The type constructor of a symbol is: - * For a type symbol, the type corresponding to the symbol itself, - * excluding parameters. - * Not applicable for term symbols. - */ - def typeConstructor: Type = - abort("typeConstructor inapplicable for " + this) + this setFlag TRIEDCOOKING + info // force the current info + if (isJavaDefined || isType && owner.isJavaDefined) + this modifyInfo rawToExistential + else if (isOverloaded) + alternatives withFilter (_.isJavaDefined) foreach (_ modifyInfo rawToExistential) + } /** The logic approximately boils down to finding the most recent phase * which immediately follows any of parser, namer, typer, or erasure. @@ -1457,7 +1461,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ def unsafeTypeParams: List[Symbol] = if (isMonomorphicType) Nil - else atPhase(unsafeTypeParamPhase)(rawInfo.typeParams) + else enteringPhase(unsafeTypeParamPhase)(rawInfo.typeParams) /** The type parameters of this symbol. * assumption: if a type starts out as monomorphic, it will not acquire @@ -1469,9 +1473,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => // analogously to the "info" getter, here we allow for two completions: // one: sourceCompleter to LazyType, two: LazyType to completed type if (validTo == NoPeriod) - atPhase(phaseOf(infos.validFrom))(rawInfo load this) + enteringPhase(phaseOf(infos.validFrom))(rawInfo load this) if (validTo == NoPeriod) - atPhase(phaseOf(infos.validFrom))(rawInfo load this) + enteringPhase(phaseOf(infos.validFrom))(rawInfo load this) rawInfo.typeParams } @@ -1633,12 +1637,23 @@ trait Symbols extends api.Symbols { self: SymbolTable => def filter(cond: Symbol => Boolean): Symbol = if (isOverloaded) { - val alts = alternatives - val alts1 = alts filter cond - if (alts1 eq alts) this + var changed = false + var alts0: List[Symbol] = alternatives + var alts1: List[Symbol] = Nil + + while (alts0.nonEmpty) { + if (cond(alts0.head)) + alts1 ::= alts0.head + else + changed = true + + alts0 = alts0.tail + } + + if (!changed) this else if (alts1.isEmpty) NoSymbol else if (alts1.tail.isEmpty) alts1.head - else owner.newOverloaded(info.prefix, alts1) + else owner.newOverloaded(info.prefix, alts1.reverse) } else if (cond(this)) this else NoSymbol @@ -1717,10 +1732,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => def thisSym: Symbol = this /** The type of `this` in a class, or else the type of the symbol itself. */ - def typeOfThis = thisSym.tpe + def typeOfThis = thisSym.tpe_* - /** If symbol is a class, the type <code>this.type</code> in this class, - * otherwise <code>NoPrefix</code>. + /** If symbol is a class, the type `this.type` in this class, + * otherwise `NoPrefix`. * We always have: thisType <:< typeOfThis */ def thisType: Type = NoPrefix @@ -1889,11 +1904,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => (this.rawInfo ne NoType) && (this.effectiveOwner == that.effectiveOwner) && ( !this.effectiveOwner.isPackageClass - || (this.sourceFile eq null) - || (that.sourceFile eq null) - || (this.sourceFile.path == that.sourceFile.path) // Cheap possibly wrong check, then expensive normalization - || (this.sourceFile.canonicalPath == that.sourceFile.canonicalPath) - ) + || (this.associatedFile eq null) + || (that.associatedFile eq null) + || (this.associatedFile.path == that.associatedFile.path) // Cheap possibly wrong check, then expensive normalization + || (this.associatedFile.canonicalPath == that.associatedFile.canonicalPath) + ) ) /** The internal representation of classes and objects: @@ -2019,9 +2034,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => if (isClassConstructor) NoSymbol else matchingSymbol(ofclazz, ofclazz.thisType) /** Returns all symbols overriden by this symbol. */ - final def allOverriddenSymbols: List[Symbol] = - if (!owner.isClass) Nil + final def allOverriddenSymbols: List[Symbol] = ( + if ((this eq NoSymbol) || !owner.isClass) Nil else owner.ancestors map overriddenSymbol filter (_ != NoSymbol) + ) /** Equivalent to allOverriddenSymbols.nonEmpty, but more efficient. */ // !!! When if ever will this answer differ from .isOverride? @@ -2032,7 +2048,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => ) /** Equivalent to allOverriddenSymbols.head (or NoSymbol if no overrides) but more efficient. */ def nextOverriddenSymbol: Symbol = { - if (owner.isClass) owner.ancestors foreach { base => + if ((this ne NoSymbol) && owner.isClass) owner.ancestors foreach { base => val sym = overriddenSymbol(base) if (sym != NoSymbol) return sym @@ -2137,13 +2153,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => case p :: _ => p case _ => NoSymbol } -/* code for fixing nested objects - def expandModuleClassName() { - name = newTypeName(name.toString + "$") - } - - def isExpandedModuleClass: Boolean = name(name.length - 1) == '$' -*/ /** Desire to re-use the field in ClassSymbol which stores the source * file to also store the classfile, but without changing the behavior @@ -2153,10 +2162,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => private def sourceFileOnly(file: AbstractFile): AbstractFile = if ((file eq null) || (file.path endsWith ".class")) null else file - private def binaryFileOnly(file: AbstractFile): AbstractFile = - if ((file eq null) || !(file.path endsWith ".class")) null else file - - final def binaryFile: AbstractFile = binaryFileOnly(associatedFile) final def sourceFile: AbstractFile = sourceFileOnly(associatedFile) /** Overridden in ModuleSymbols to delegate to the module class. */ @@ -2180,9 +2185,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => // ------ toString ------------------------------------------------------------------- - /** A tag which (in the ideal case) uniquely identifies class symbols */ - final def tag: Int = fullName.## - /** The simple name of this Symbol */ final def simpleName: Name = name @@ -2413,6 +2415,14 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def isMethod = this hasFlag METHOD override def isModule = this hasFlag MODULE override def isOverloaded = this hasFlag OVERLOADED + /*** !!! TODO: shouldn't we do something like the following: + override def isOverloaded = ( + if (this.isInitialized) + this hasFlag OVERLOADED + else + (infos ne null) && infos.info.isInstanceOf[OverloadedType] + ) + ***/ override def isPackage = this hasFlag PACKAGE override def isValueParameter = this hasFlag PARAM @@ -2509,36 +2519,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => name = nme.expandedName(name.toTermName, base) } } - - protected def doCookJavaRawInfo() { - def cook(sym: Symbol) { - require(sym.isJavaDefined, sym) - // @M: I think this is more desirable, but Martin prefers to leave raw-types as-is as much as possible - // object rawToExistentialInJava extends TypeMap { - // def apply(tp: Type): Type = tp match { - // // any symbol that occurs in a java sig, not just java symbols - // // see http://lampsvn.epfl.ch/trac/scala/ticket/2454#comment:14 - // case TypeRef(pre, sym, List()) if !sym.typeParams.isEmpty => - // val eparams = typeParamsToExistentials(sym, sym.typeParams) - // existentialAbstraction(eparams, TypeRef(pre, sym, eparams map (_.tpe))) - // case _ => - // mapOver(tp) - // } - // } - val tpe1 = rawToExistential(sym.tpe) - // println("cooking: "+ sym +": "+ sym.tpe +" to "+ tpe1) - if (tpe1 ne sym.tpe) { - sym.setInfo(tpe1) - } - } - - if (isJavaDefined) - cook(this) - else if (isOverloaded) - for (sym2 <- alternatives) - if (sym2.isJavaDefined) - cook(sym2) - } } implicit val TermSymbolTag = ClassTag[TermSymbol](classOf[TermSymbol]) @@ -2630,6 +2610,20 @@ trait Symbols extends api.Symbols { self: SymbolTable => owner.newNonClassSymbol(name, pos, newFlags) } + /** Let's say you have a type definition + * + * {{{ + * type T <: Number + * }}} + * + * and tsym is the symbol corresponding to T. Then + * + * {{{ + * tsym is an instance of AbstractTypeSymbol + * tsym.info = TypeBounds(Nothing, Number) + * tsym.tpe = TypeRef(NoPrefix, T, List()) + * }}} + */ class AbstractTypeSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName) extends TypeSymbol(initOwner, initPos, initName) { type TypeOfClonedSymbol = TypeSymbol @@ -2658,7 +2652,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def asNameType(n: Name) = n.toTypeName override def isNonClassType = true - override def isTypeMacro = hasFlag(MACRO) override def resolveOverloadedFlag(flag: Long) = flag match { case TRAIT => "<trait>" // DEFAULTPARAM @@ -2676,7 +2669,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def isAbstractType = this hasFlag DEFERRED override def isContravariant = this hasFlag CONTRAVARIANT override def isCovariant = this hasFlag COVARIANT - override def isExistentialQuantified = isExistentiallyBound && !isSkolem override def isExistentiallyBound = this hasFlag EXISTENTIAL override def isTypeParameter = isTypeParameterOrSkolem && !isSkolem override def isTypeParameterOrSkolem = this hasFlag PARAM @@ -2698,63 +2690,57 @@ trait Symbols extends api.Symbols { self: SymbolTable => private def newPrefix = if (this hasFlag EXISTENTIAL | PARAM) NoPrefix else owner.thisType private def newTypeRef(targs: List[Type]) = typeRef(newPrefix, this, targs) - /** Let's say you have a type definition - * - * {{{ - * type T <: Number - * }}} + /** A polymorphic type symbol has two distinct "types": * - * and tsym is the symbol corresponding to T. Then + * tpe_* a TypeRef with: dummy type args, no unapplied type parameters, and kind * + * tpeHK a TypeRef with: no type args, unapplied type parameters, and + * kind (*,*,...,*) => * depending on the number of tparams. * - * {{{ - * tsym.info = TypeBounds(Nothing, Number) - * tsym.tpe = TypeRef(NoPrefix, T, List()) - * }}} - */ - override def tpe: Type = { - if (tpeCache eq NoType) throw CyclicReference(this, typeConstructor) - if (tpePeriod != currentPeriod) { - if (isValid(tpePeriod)) { - tpePeriod = currentPeriod - } else { - if (isInitialized) tpePeriod = currentPeriod - tpeCache = NoType - val targs = - if (phase.erasedTypes && this != ArrayClass) List() - else unsafeTypeParams map (_.typeConstructor) - //@M! use typeConstructor to generate dummy type arguments, - // sym.tpe should not be called on a symbol that's supposed to be a higher-kinded type - // memberType should be used instead, that's why it uses tpeHK and not tpe - tpeCache = newTypeRef(targs) - } - } - assert(tpeCache ne null/*, "" + this + " " + phase*/)//debug + * The dummy type args in tpe_* are created by wrapping a TypeRef + * around the type parameter symbols. Types containing dummies will + * hide errors or introduce spurious ones if they are passed around + * as if normal types. They should only be used in local operations + * where they will either be discarded immediately after, or will + * undergo substitution in which the dummies are replaced by actual + * type arguments. + */ + override def tpe_* : Type = { + maybeUpdateTypeCache() tpeCache } - - /** @M -- tpe vs tpeHK: - * - * tpe: creates a TypeRef with dummy type arguments and kind * - * tpeHK: creates a TypeRef with no type arguments but with type parameters - * - * If typeParams is nonEmpty, calling tpe may hide errors or - * introduce spurious ones. (For example, when deriving a type from - * the symbol of a type argument that may be higher-kinded.) As far - * as I can tell, it only makes sense to call tpe in conjunction - * with a substitution that replaces the generated dummy type - * arguments by their actual types. - * - * TODO: the above conditions desperately need to be enforced by code. - */ - override def tpeHK = typeConstructor // @M! used in memberType - override def typeConstructor: Type = { + maybeUpdateTyconCache() + tyconCache + } + override def tpeHK: Type = typeConstructor + + private def maybeUpdateTyconCache() { if ((tyconCache eq null) || tyconRunId != currentRunId) { tyconCache = newTypeRef(Nil) tyconRunId = currentRunId } assert(tyconCache ne null) - tyconCache + } + private def maybeUpdateTypeCache() { + if (tpePeriod != currentPeriod) { + if (isValid(tpePeriod)) + tpePeriod = currentPeriod + else + updateTypeCache() // perform the actual update + } + } + private def updateTypeCache() { + if (tpeCache eq NoType) + throw CyclicReference(this, typeConstructor) + + if (isInitialized) + tpePeriod = currentPeriod + + tpeCache = NoType // cycle marker + tpeCache = newTypeRef( + if (phase.erasedTypes && this != ArrayClass || unsafeTypeParams.isEmpty) Nil + else unsafeTypeParams map (_.typeConstructor) + ) } override def info_=(tp: Type) { @@ -2780,15 +2766,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => * public class Test1<T extends Test3> {} * info for T in Test1 should be >: Nothing <: Test3[_] */ - protected def doCookJavaRawInfo() { - if (isJavaDefined || owner.isJavaDefined) { - val tpe1 = rawToExistential(info) - // println("cooking type: "+ this +": "+ info +" to "+ tpe1) - if (tpe1 ne info) { - setInfo(tpe1) - } - } - } if (Statistics.hotEnabled) Statistics.incCounter(typeSymbolCount) } @@ -2822,7 +2799,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def isTypeSkolem = this hasFlag PARAM override def isAbstractType = this hasFlag DEFERRED - override def isExistentialQuantified = false override def existentialBound = if (isAbstractType) this.info else super.existentialBound /** If typeskolem comes from a type parameter, that parameter, otherwise skolem itself */ @@ -2908,21 +2884,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => || isLocal || !owner.isPackageClass && owner.isLocalClass ) - override def isStableClass = (this hasFlag STABLE) || checkStable() - - private def checkStable() = { - def hasNoAbstractTypeMember(clazz: Symbol): Boolean = - (clazz hasFlag STABLE) || { - var e = clazz.info.decls.elems - while ((e ne null) && !(e.sym.isAbstractType && info.member(e.sym.name) == e.sym)) - e = e.next - e == null - } - (info.baseClasses forall hasNoAbstractTypeMember) && { - setFlag(STABLE) - true - } - } override def enclClassChain = this :: owner.enclClassChain @@ -3108,6 +3069,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => ) } trait StubSymbol extends Symbol { + devWarning("creating stub symbol to defer error: " + missingMessage) + protected def missingMessage: String /** Fail the stub by throwing a [[scala.reflect.internal.MissingRequirementError]]. */ @@ -3135,8 +3098,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def info = fail(NoType) override def rawInfo = fail(NoType) override def companionSymbol = fail(NoSymbol) - - debugwarn("creating stub symbol to defer error: " + missingMessage) } class StubClassSymbol(owner0: Symbol, name0: TypeName, protected val missingMessage: String) extends ClassSymbol(owner0, owner0.pos, name0) with StubSymbol class StubTermSymbol(owner0: Symbol, name0: TermName, protected val missingMessage: String) extends TermSymbol(owner0, owner0.pos, name0) with StubSymbol @@ -3194,15 +3155,12 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def info: Type = NoType override def existentialBound: Type = NoType override def rawInfo: Type = NoType - protected def doCookJavaRawInfo() {} override def accessBoundary(base: Symbol): Symbol = enclosingRootClass def cloneSymbolImpl(owner: Symbol, newFlags: Long) = abort("NoSymbol.clone()") override def originalEnclosingMethod = this override def owner: Symbol = abort("no-symbol does not have an owner") - override def typeConstructor: Type = - abort("no-symbol does not have a type constructor (this may indicate scalac cannot find fundamental classes)") } protected def makeNoSymbol: NoSymbol = new NoSymbol diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index ebf0998573..072e94e069 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -11,10 +11,7 @@ abstract class TreeGen extends macros.TreeBuilder { def rootScalaDot(name: Name) = Select(rootId(nme.scala_) setSymbol ScalaPackage, name) def scalaDot(name: Name) = Select(Ident(nme.scala_) setSymbol ScalaPackage, name) def scalaAnnotationDot(name: Name) = Select(scalaDot(nme.annotation), name) - def scalaAnyRefConstr = scalaDot(tpnme.AnyRef) setSymbol AnyRefClass - def scalaUnitConstr = scalaDot(tpnme.Unit) setSymbol UnitClass - def productConstr = scalaDot(tpnme.Product) setSymbol ProductRootClass - def serializableConstr = scalaDot(tpnme.Serializable) setSymbol SerializableClass + def scalaAnyRefConstr = scalaDot(tpnme.AnyRef) setSymbol AnyRefClass // used in ide def scalaFunctionConstr(argtpes: List[Tree], restpe: Tree, abstractFun: Boolean = false): Tree = { val cls = if (abstractFun) @@ -165,17 +162,36 @@ abstract class TreeGen extends macros.TreeBuilder { This(sym.name.toTypeName) setSymbol sym setType sym.thisType def mkAttributedIdent(sym: Symbol): Tree = - Ident(sym.name) setSymbol sym setType sym.tpe + Ident(sym.name) setSymbol sym setType sym.tpeHK def mkAttributedSelect(qual: Tree, sym: Symbol): Tree = { // Tests involving the repl fail without the .isEmptyPackage condition. if (qual.symbol != null && (qual.symbol.isEffectiveRoot || qual.symbol.isEmptyPackage)) mkAttributedIdent(sym) else { + // Have to recognize anytime a selection is made on a package + // so it can be rewritten to foo.bar.`package`.name rather than + // foo.bar.name if name is in the package object. + // TODO - factor out the common logic between this and + // the Typers method "isInPackageObject", used in typedIdent. + val qualsym = ( + if (qual.tpe ne null) qual.tpe.typeSymbol + else if (qual.symbol ne null) qual.symbol + else NoSymbol + ) + val needsPackageQualifier = ( + (sym ne null) + && qualsym.isPackage + && !sym.isDefinedInPackage + ) val pkgQualifier = - if (sym != null && sym.owner.isPackageObjectClass && sym.effectiveOwner == qual.tpe.typeSymbol) { - val obj = sym.owner.sourceModule - Select(qual, nme.PACKAGE) setSymbol obj setType singleType(qual.tpe, obj) + if (needsPackageQualifier) { + // The owner of a symbol which requires package qualification may be the + // package object iself, but it also could be any superclass of the package + // object. In the latter case, we must go through the qualifier's info + // to obtain the right symbol. + val packageObject = if (sym.owner.isModuleClass) sym.owner.sourceModule else qual.tpe member nme.PACKAGE + Select(qual, nme.PACKAGE) setSymbol packageObject setType singleType(qual.tpe, packageObject) } else qual @@ -229,10 +245,6 @@ abstract class TreeGen extends macros.TreeBuilder { Literal(Constant(tp)) setType ConstantType(Constant(tp)) /** Builds a list with given head and tail. */ - def mkNewCons(head: Tree, tail: Tree): Tree = - New(Apply(mkAttributedRef(ConsClass), List(head, tail))) - - /** Builds a list with given head and tail. */ def mkNil: Tree = mkAttributedRef(NilModule) /** Builds a tree representing an undefined local, as in diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 8ad15f37e4..4f60d9cabc 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -104,11 +104,32 @@ abstract class TreeInfo { false } - @deprecated("Use isExprSafeToInline instead", "2.10.0") - def isPureExpr(tree: Tree) = isExprSafeToInline(tree) + /** As if the name of the method didn't give it away, + * this logic is designed around issuing helpful + * warnings and minimizing spurious ones. That means + * don't reuse it for important matters like inlining + * decisions. + */ + def isPureExprForWarningPurposes(tree: Tree) = tree match { + case EmptyTree | Literal(Constant(())) => false + case _ => + def isWarnableRefTree = tree match { + case t: RefTree => isExprSafeToInline(t.qualifier) && t.symbol != null && t.symbol.isAccessor + case _ => false + } + def isWarnableSymbol = { + val sym = tree.symbol + (sym == null) || !(sym.isModule || sym.isLazy) || { + debuglog("'Pure' but side-effecting expression in statement position: " + tree) + false + } + } - def zipMethodParamsAndArgs(params: List[Symbol], args: List[Tree]): List[(Symbol, Tree)] = - mapMethodParamsAndArgs(params, args)((param, arg) => ((param, arg))) + ( !tree.isErrorTyped + && (isExprSafeToInline(tree) || isWarnableRefTree) + && isWarnableSymbol + ) + } def mapMethodParamsAndArgs[R](params: List[Symbol], args: List[Tree])(f: (Symbol, Tree) => R): List[R] = { val b = List.newBuilder[R] @@ -119,11 +140,10 @@ abstract class TreeInfo { val plen = params.length val alen = args.length def fail() = { - global.debugwarn( - "Mismatch trying to zip method parameters and argument list:\n" + - " params = " + params + "\n" + - " args = " + args + "\n" - ) + global.devWarning( + s"""|Mismatch trying to zip method parameters and argument list: + | params = $params + | args = $args""".stripMargin) false } @@ -147,37 +167,6 @@ abstract class TreeInfo { true } - /** - * Selects the correct parameter list when there are nested applications. - * Given Apply(fn, args), args might correspond to any of fn.symbol's parameter - * lists. To choose the correct one before uncurry, we have to unwrap any - * applies: for instance Apply(fn @ Apply(Apply(_, _), _), args) implies args - * correspond to the third parameter list. - * - * The argument fn is the function part of the apply node being considered. - * - * Also accounts for varargs. - */ - private def applyMethodParameters(fn: Tree): List[Symbol] = { - val depth = applyDepth(fn) - // There could be applies which go beyond the parameter list(s), - // being applied to the result of the method call. - // !!! Note that this still doesn't seem correct, although it should - // be closer than what it replaced. - if (depth < fn.symbol.paramss.size) fn.symbol.paramss(depth) - else if (fn.symbol.paramss.isEmpty) Nil - else fn.symbol.paramss.last - } - - def zipMethodParamsAndArgs(t: Tree): List[(Symbol, Tree)] = t match { - case Apply(fn, args) => zipMethodParamsAndArgs(applyMethodParameters(fn), args) - case _ => Nil - } - def foreachMethodParamAndArg(t: Tree)(f: (Symbol, Tree) => Unit): Unit = t match { - case Apply(fn, args) => foreachMethodParamAndArg(applyMethodParameters(fn), args)(f) - case _ => - } - /** Is symbol potentially a getter of a variable? */ def mayBeVarGetter(sym: Symbol): Boolean = sym.info match { @@ -237,6 +226,20 @@ abstract class TreeInfo { tree } + /** Strips layers of `.asInstanceOf[T]` / `_.$asInstanceOf[T]()` from an expression */ + def stripCast(tree: Tree): Tree = tree match { + case TypeApply(sel @ Select(inner, _), _) if isCastSymbol(sel.symbol) => + stripCast(inner) + case Apply(TypeApply(sel @ Select(inner, _), _), Nil) if isCastSymbol(sel.symbol) => + stripCast(inner) + case t => + t + } + + object StripCast { + def unapply(tree: Tree): Some[Tree] = Some(stripCast(tree)) + } + /** Is tree a self or super constructor call? */ def isSelfOrSuperConstrCall(tree: Tree) = { // stripNamedApply for SI-3584: adaptToImplicitMethod in Typers creates a special context @@ -312,10 +315,6 @@ abstract class TreeInfo { case x: Ident => !x.isBackquoted && nme.isVariableName(x.name) case _ => false } - def isDeprecatedIdentifier(tree: Tree): Boolean = tree match { - case x: Ident => !x.isBackquoted && nme.isDeprecatedIdentifierName(x.name) - case _ => false - } /** The first constructor definitions in `stats` */ def firstConstructor(stats: List[Tree]): Tree = stats find { @@ -374,12 +373,6 @@ abstract class TreeInfo { /** Is name a left-associative operator? */ def isLeftAssoc(operator: Name) = operator.nonEmpty && (operator.endChar != ':') - /** Is tree a `this` node which belongs to `enclClass`? */ - def isSelf(tree: Tree, enclClass: Symbol): Boolean = tree match { - case This(_) => tree.symbol == enclClass - case _ => false - } - /** a Match(Typed(_, tpt), _) must be translated into a switch if isSwitchAnnotation(tpt.tpe) */ def isSwitchAnnotation(tpe: Type) = tpe hasAnnotation definitions.SwitchClass @@ -441,15 +434,31 @@ abstract class TreeInfo { case _ => false } - /** Does this CaseDef catch Throwable? */ - def catchesThrowable(cdef: CaseDef) = catchesAllOf(cdef, ThrowableClass.tpe) + private def hasNoSymbol(t: Tree) = t.symbol == null || t.symbol == NoSymbol - /** Does this CaseDef catch everything of a certain Type? */ - def catchesAllOf(cdef: CaseDef, threshold: Type) = - isDefaultCase(cdef) || (cdef.guard.isEmpty && (unbind(cdef.pat) match { - case Typed(Ident(nme.WILDCARD), tpt) => (tpt.tpe != null) && (threshold <:< tpt.tpe) - case _ => false - })) + /** If this CaseDef assigns a name to its top-level pattern, + * in the form 'expr @ pattern' or 'expr: pattern', returns + * the name. Otherwise, nme.NO_NAME. + * + * Note: in the case of Constant patterns such as 'case x @ "" =>', + * the pattern matcher eliminates the binding and inlines the constant, + * so as far as this method is likely to be able to determine, + * the name is NO_NAME. + */ + def assignedNameOfPattern(cdef: CaseDef): Name = cdef.pat match { + case Bind(name, _) => name + case Ident(name) => name + case _ => nme.NO_NAME + } + + /** Does this CaseDef catch Throwable? */ + def catchesThrowable(cdef: CaseDef) = ( + cdef.guard.isEmpty && (unbind(cdef.pat) match { + case Ident(nme.WILDCARD) => true + case i@Ident(name) => hasNoSymbol(i) + case _ => false + }) + ) /** Is this pattern node a catch-all or type-test pattern? */ def isCatchCase(cdef: CaseDef) = cdef match { diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 6df4b75a88..5c1d109662 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -31,7 +31,8 @@ trait Trees extends api.Trees { self: SymbolTable => def symbol: Symbol = null //!!!OPT!!! symbol is about 3% of hot compile times -- megamorphic dispatch? def symbol_=(sym: Symbol) { throw new UnsupportedOperationException("symbol_= inapplicable for " + this) } def setSymbol(sym: Symbol): this.type = { symbol = sym; this } - def hasSymbol = false + def hasSymbolField = false + @deprecated("Use hasSymbolField", "2.11.0") def hasSymbol = hasSymbolField def isDef = false @@ -62,7 +63,7 @@ trait Trees extends api.Trees { self: SymbolTable => private[scala] def copyAttrs(tree: Tree): this.type = { rawatt = tree.rawatt tpe = tree.tpe - if (hasSymbol) symbol = tree.symbol + if (hasSymbolField) symbol = tree.symbol this } @@ -210,7 +211,7 @@ trait Trees extends api.Trees { self: SymbolTable => trait TypTree extends Tree with TypTreeApi abstract class SymTree extends Tree with SymTreeContextApi { - override def hasSymbol = true + override def hasSymbolField = true override var symbol: Symbol = NoSymbol } @@ -416,6 +417,16 @@ trait Trees extends api.Trees { self: SymbolTable => def ApplyConstructor(tpt: Tree, args: List[Tree]) = Apply(Select(New(tpt), nme.CONSTRUCTOR), args) + // Creates a constructor call from the constructor symbol. This is + // to avoid winding up with an OverloadedType for the constructor call. + def NewFromConstructor(constructor: Symbol, args: Tree*) = { + assert(constructor.isConstructor, constructor) + val instance = New(TypeTree(constructor.owner.tpe)) + val init = Select(instance, nme.CONSTRUCTOR) setSymbol constructor + + Apply(init, args.toList) + } + case class ApplyDynamic(qual: Tree, args: List[Tree]) extends SymTree with TermTree case class Super(qual: Tree, mix: TypeName) extends TermTree with SuperApi { @@ -862,7 +873,6 @@ trait Trees extends api.Trees { self: SymbolTable => /** Is the tree Predef, scala.Predef, or _root_.scala.Predef? */ def isReferenceToPredef(t: Tree) = isReferenceToScalaMember(t, nme.Predef) - def isReferenceToAnyVal(t: Tree) = isReferenceToScalaMember(t, tpnme.AnyVal) // --- modifiers implementation --------------------------------------- @@ -1429,7 +1439,7 @@ trait Trees extends api.Trees { self: SymbolTable => } if (tree.tpe ne null) tree.tpe = symSubst(tree.tpe) - if (tree.hasSymbol) { + if (tree.hasSymbolField) { subst(from, to) tree match { case Ident(name0) if tree.symbol != NoSymbol => diff --git a/src/reflect/scala/reflect/internal/TypeDebugging.scala b/src/reflect/scala/reflect/internal/TypeDebugging.scala index 68b4fa69a1..d437b1b058 100644 --- a/src/reflect/scala/reflect/internal/TypeDebugging.scala +++ b/src/reflect/scala/reflect/internal/TypeDebugging.scala @@ -9,8 +9,6 @@ package internal trait TypeDebugging { self: SymbolTable => - import definitions._ - // @M toString that is safe during debugging (does not normalize, ...) object typeDebug { private def to_s(x: Any): String = x match { @@ -20,7 +18,6 @@ trait TypeDebugging { case x: Product => x.productIterator mkString ("(", ", ", ")") case _ => "" + x } - def ptIndent(x: Any) = ("" + x).replaceAll("\\n", " ") def ptBlock(label: String, pairs: (String, Any)*): String = { if (pairs.isEmpty) label + "{ }" else { diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 0c4cda8313..09fc534d8a 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -22,6 +22,8 @@ import util.ThreeValues._ // internal: error case WildcardType => // internal: unknown + case BoundedWildcardType(bounds) => + // internal: unknown case NoType => case NoPrefix => case ThisType(sym) => @@ -66,9 +68,7 @@ import util.ThreeValues._ // a type variable // Replace occurrences of type parameters with type vars, where // inst is the instantiation and constr is a list of bounds. - case DeBruijnIndex(level, index, args) - // for dependent method types: a type referring to a method parameter. - case ErasedValueType(tref) + case ErasedValueType(clazz, underlying) // only used during erasure of derived value classes. */ @@ -91,6 +91,7 @@ trait Types extends api.Types { self: SymbolTable => private final val printLubs = sys.props contains "scalac.debug.lub" private final val traceTypeVars = sys.props contains "scalac.debug.tvar" + private final val breakCycles = settings.breakCycles.value /** In case anyone wants to turn off lub verification without reverting anything. */ private final val verifyLubs = true /** In case anyone wants to turn off type parameter bounds being used @@ -100,10 +101,6 @@ trait Types extends api.Types { self: SymbolTable => protected val enableTypeVarExperimentals = settings.Xexperimental.value - /** Empty immutable maps to avoid allocations. */ - private val emptySymMap = immutable.Map[Symbol, Symbol]() - private val emptySymCount = immutable.Map[Symbol, Int]() - /** The current skolemization level, needed for the algorithms * in isSameType, isSubType that do constraint solving under a prefix. */ @@ -170,10 +167,6 @@ trait Types extends api.Types { self: SymbolTable => log = Nil } finally unlock() } - def size = { - lock() - try log.size finally unlock() - } // `block` should not affect constraints on typevars def undo[T](block: => T): T = { @@ -185,20 +178,6 @@ trait Types extends api.Types { self: SymbolTable => finally undoTo(before) } finally unlock() } - - // if `block` evaluates to false, it should not affect constraints on typevars - def undoUnless(block: => Boolean): Boolean = { - lock() - try { - val before = log - var result = false - - try result = block - finally if (!result) undoTo(before) - - result - } finally unlock() - } } /** A map from lists to compound types that have the given list as parents. @@ -295,7 +274,6 @@ trait Types extends api.Types { self: SymbolTable => abstract class TypeApiImpl extends TypeApi { this: Type => def declaration(name: Name): Symbol = decl(name) - def nonPrivateDeclaration(name: Name): Symbol = nonPrivateDecl(name) def declarations = decls def typeArguments = typeArgs def erasure = this match { @@ -382,9 +360,6 @@ trait Types extends api.Types { self: SymbolTable => /** Is this type produced as a repair for an error? */ def isErroneous: Boolean = ErroneousCollector.collect(this) - /** Does this type denote a reference type which can be null? */ - // def isNullable: Boolean = false - /** Can this type only be subtyped by bottom types? * This is assessed to be the case if the class is final, * and all type parameters (if any) are invariant. @@ -522,11 +497,6 @@ trait Types extends api.Types { self: SymbolTable => /** Only used for dependent method types. */ def resultApprox: Type = ApproximateDependentMap(resultType) - /** If this is a TypeRef `clazz`[`T`], return the argument `T` - * otherwise return this type - */ - def remove(clazz: Symbol): Type = this - /** For a curried/nullary method or poly type its non-method result type, * the type itself for all other types */ def finalResultType: Type = this @@ -664,16 +634,6 @@ trait Types extends api.Types { self: SymbolTable => def nonPrivateMember(name: Name): Symbol = memberBasedOnName(name, BridgeAndPrivateFlags) - /** All members with the given flags, excluding bridges. - */ - def membersWithFlags(requiredFlags: Long): Scope = - membersBasedOnFlags(BridgeFlags, requiredFlags) - - /** All non-private members with the given flags, excluding bridges. - */ - def nonPrivateMembersWithFlags(requiredFlags: Long): Scope = - membersBasedOnFlags(BridgeAndPrivateFlags, requiredFlags) - /** The non-private member with given name, admitting members with given flags `admit`. * "Admitting" refers to the fact that members with a PRIVATE, BRIDGE, or VBRIDGE * flag are usually excluded from findMember results, but supplying any of those flags @@ -694,7 +654,6 @@ trait Types extends api.Types { self: SymbolTable => */ def membersBasedOnFlags(excludedFlags: Long, requiredFlags: Long): Scope = findMembers(excludedFlags, requiredFlags) -// findMember(nme.ANYNAME, excludedFlags, requiredFlags, false).alternatives def memberBasedOnName(name: Name, excludedFlags: Long): Symbol = findMember(name, excludedFlags, 0, false) @@ -748,6 +707,7 @@ trait Types extends api.Types { self: SymbolTable => * }}} */ def memberInfo(sym: Symbol): Type = { + require(sym ne NoSymbol, this) sym.info.asSeenFrom(this, sym.owner) } @@ -808,7 +768,6 @@ trait Types extends api.Types { self: SymbolTable => else substThis(from, to).substSym(symsFrom, symsTo) /** Returns all parts of this type which satisfy predicate `p` */ - def filter(p: Type => Boolean): List[Type] = new FilterTypeCollector(p) collect this def withFilter(p: Type => Boolean) = new FilterMapForeach(p) class FilterMapForeach(p: Type => Boolean) extends FilterTypeCollector(p){ @@ -838,9 +797,6 @@ trait Types extends api.Types { self: SymbolTable => /** Does this type contain a reference to this symbol? */ def contains(sym: Symbol): Boolean = new ContainsCollector(sym).collect(this) - /** Does this type contain a reference to this type */ - def containsTp(tp: Type): Boolean = new ContainsTypeCollector(tp).collect(this) - /** Is this type a subtype of that type? */ def <:<(that: Type): Boolean = { if (Statistics.canEnable) stat_<:<(that) @@ -901,11 +857,6 @@ trait Types extends api.Types { self: SymbolTable => else isSameType(this, that)) ); - /** Does this type implement symbol `sym` with same or stronger type? */ - def specializes(sym: Symbol): Boolean = - if (explainSwitch) explain("specializes", specializesSym, this, sym) - else specializesSym(this, sym) - /** Is this type close enough to that type so that members * with the two type would override each other? * This means: @@ -1050,69 +1001,66 @@ trait Types extends api.Types { self: SymbolTable => } def findMembers(excludedFlags: Long, requiredFlags: Long): Scope = { - // if this type contains type variables, put them to sleep for a while -- don't just wipe them out by - // replacing them by the corresponding type parameter, as that messes up (e.g.) type variables in type refinements - // without this, the matchesType call would lead to type variables on both sides - // of a subtyping/equality judgement, which can lead to recursive types being constructed. - // See (t0851) for a situation where this happens. - val suspension: List[TypeVar] = if (this.isGround) null else suspendTypeVarsInType(this) - - if (Statistics.canEnable) Statistics.incCounter(findMembersCount) - val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, findMembersNanos) else null - - //Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG - var members: Scope = null - var required = requiredFlags - var excluded = excludedFlags | DEFERRED - var continue = true - var self: Type = null - while (continue) { - continue = false - val bcs0 = baseClasses - var bcs = bcs0 - while (!bcs.isEmpty) { - val decls = bcs.head.info.decls - var entry = decls.elems - while (entry ne null) { - val sym = entry.sym - val flags = sym.flags - if ((flags & required) == required) { - val excl = flags & excluded - if (excl == 0L && - (// omit PRIVATE LOCALS unless selector class is contained in class owning the def. - (bcs eq bcs0) || - (flags & PrivateLocal) != PrivateLocal || - (bcs0.head.hasTransOwner(bcs.head)))) { - if (members eq null) members = newFindMemberScope - var others: ScopeEntry = members.lookupEntry(sym.name) - var symtpe: Type = null - while ((others ne null) && { - val other = others.sym - (other ne sym) && - ((other.owner eq sym.owner) || - (flags & PRIVATE) != 0 || { - if (self eq null) self = narrowForFindMember(this) - if (symtpe eq null) symtpe = self.memberType(sym) - !(self.memberType(other) matches symtpe) - })}) { - others = members lookupNextEntry others + def findMembersInternal: Scope = { + var members: Scope = null + if (Statistics.canEnable) Statistics.incCounter(findMembersCount) + val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, findMembersNanos) else null + + //Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG + var required = requiredFlags + var excluded = excludedFlags | DEFERRED + var continue = true + var self: Type = null + while (continue) { + continue = false + val bcs0 = baseClasses + var bcs = bcs0 + while (!bcs.isEmpty) { + val decls = bcs.head.info.decls + var entry = decls.elems + while (entry ne null) { + val sym = entry.sym + val flags = sym.flags + if ((flags & required) == required) { + val excl = flags & excluded + if (excl == 0L && + (// omit PRIVATE LOCALS unless selector class is contained in class owning the def. + (bcs eq bcs0) || + (flags & PrivateLocal) != PrivateLocal || + (bcs0.head.hasTransOwner(bcs.head)))) { + if (members eq null) members = newFindMemberScope + var others: ScopeEntry = members.lookupEntry(sym.name) + var symtpe: Type = null + while ((others ne null) && { + val other = others.sym + (other ne sym) && + ((other.owner eq sym.owner) || + (flags & PRIVATE) != 0 || { + if (self eq null) self = narrowForFindMember(this) + if (symtpe eq null) symtpe = self.memberType(sym) + !(self.memberType(other) matches symtpe) + })}) { + others = members lookupNextEntry others + } + if (others eq null) members enter sym + } else if (excl == DEFERRED) { + continue = true } - if (others eq null) members enter sym - } else if (excl == DEFERRED) { - continue = true } - } - entry = entry.next - } // while (entry ne null) - // excluded = excluded | LOCAL - bcs = bcs.tail - } // while (!bcs.isEmpty) - required |= DEFERRED - excluded &= ~(DEFERRED.toLong) - } // while (continue) - if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start) - if (suspension ne null) suspension foreach (_.suspended = false) - if (members eq null) EmptyScope else members + entry = entry.next + } // while (entry ne null) + // excluded = excluded | LOCAL + bcs = bcs.tail + } // while (!bcs.isEmpty) + required |= DEFERRED + excluded &= ~(DEFERRED.toLong) + } // while (continue) + if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start) + if (members eq null) EmptyScope else members + } + + if (this.isGround) findMembersInternal + else suspendingTypeVars(typeVarsInType(this))(findMembersInternal) } /** @@ -1126,102 +1074,98 @@ trait Types extends api.Types { self: SymbolTable => */ //TODO: use narrow only for modules? (correct? efficiency gain?) def findMember(name: Name, excludedFlags: Long, requiredFlags: Long, stableOnly: Boolean): Symbol = { - // if this type contains type variables, put them to sleep for a while -- don't just wipe them out by - // replacing them by the corresponding type parameter, as that messes up (e.g.) type variables in type refinements - // without this, the matchesType call would lead to type variables on both sides - // of a subtyping/equality judgement, which can lead to recursive types being constructed. - // See (t0851) for a situation where this happens. - val suspension: List[TypeVar] = if (this.isGround) null else suspendTypeVarsInType(this) - - if (Statistics.canEnable) Statistics.incCounter(findMemberCount) - val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, findMemberNanos) else null - - //Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG - var member: Symbol = NoSymbol - var members: List[Symbol] = null - var lastM: ::[Symbol] = null - var membertpe: Type = null - var required = requiredFlags - var excluded = excludedFlags | DEFERRED - var continue = true - var self: Type = null - - while (continue) { - continue = false - val bcs0 = baseClasses - var bcs = bcs0 - while (!bcs.isEmpty) { - val decls = bcs.head.info.decls - var entry = decls.lookupEntry(name) - while (entry ne null) { - val sym = entry.sym - val flags = sym.flags - if ((flags & required) == required) { - val excl = flags & excluded - if (excl == 0L && - (// omit PRIVATE LOCALS unless selector class is contained in class owning the def. - (bcs eq bcs0) || - (flags & PrivateLocal) != PrivateLocal || - (bcs0.head.hasTransOwner(bcs.head)))) { - if (name.isTypeName || stableOnly && sym.isStable) { - if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start) - if (suspension ne null) suspension foreach (_.suspended = false) - return sym - } else if (member eq NoSymbol) { - member = sym - } else if (members eq null) { - if ((member ne sym) && - ((member.owner eq sym.owner) || - (flags & PRIVATE) != 0 || { - if (self eq null) self = narrowForFindMember(this) - if (membertpe eq null) membertpe = self.memberType(member) - !(membertpe matches self.memberType(sym)) - })) { - lastM = new ::(sym, null) - members = member :: lastM - } - } else { - var others: List[Symbol] = members - var symtpe: Type = null - while ((others ne null) && { - val other = others.head - (other ne sym) && - ((other.owner eq sym.owner) || + def findMemberInternal: Symbol = { + var member: Symbol = NoSymbol + var members: List[Symbol] = null + var lastM: ::[Symbol] = null + if (Statistics.canEnable) Statistics.incCounter(findMemberCount) + val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, findMemberNanos) else null + + //Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG + var membertpe: Type = null + var required = requiredFlags + var excluded = excludedFlags | DEFERRED + var continue = true + var self: Type = null + + while (continue) { + continue = false + val bcs0 = baseClasses + var bcs = bcs0 + while (!bcs.isEmpty) { + val decls = bcs.head.info.decls + var entry = decls.lookupEntry(name) + while (entry ne null) { + val sym = entry.sym + val flags = sym.flags + if ((flags & required) == required) { + val excl = flags & excluded + if (excl == 0L && + (// omit PRIVATE LOCALS unless selector class is contained in class owning the def. + (bcs eq bcs0) || + (flags & PrivateLocal) != PrivateLocal || + (bcs0.head.hasTransOwner(bcs.head)))) { + if (name.isTypeName || stableOnly && sym.isStable) { + if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start) + return sym + } else if (member eq NoSymbol) { + member = sym + } else if (members eq null) { + if ((member ne sym) && + ((member.owner eq sym.owner) || (flags & PRIVATE) != 0 || { if (self eq null) self = narrowForFindMember(this) - if (symtpe eq null) symtpe = self.memberType(sym) - !(self.memberType(other) matches symtpe) - })}) { - others = others.tail - } - if (others eq null) { - val lastM1 = new ::(sym, null) - lastM.tl = lastM1 - lastM = lastM1 + if (membertpe eq null) membertpe = self.memberType(member) + !(membertpe matches self.memberType(sym)) + })) { + lastM = new ::(sym, null) + members = member :: lastM + } + } else { + var others: List[Symbol] = members + var symtpe: Type = null + while ((others ne null) && { + val other = others.head + (other ne sym) && + ((other.owner eq sym.owner) || + (flags & PRIVATE) != 0 || { + if (self eq null) self = narrowForFindMember(this) + if (symtpe eq null) symtpe = self.memberType(sym) + !(self.memberType(other) matches symtpe) + })}) { + others = others.tail + } + if (others eq null) { + val lastM1 = new ::(sym, null) + lastM.tl = lastM1 + lastM = lastM1 + } } + } else if (excl == DEFERRED) { + continue = true } - } else if (excl == DEFERRED) { - continue = true } - } - entry = decls lookupNextEntry entry - } // while (entry ne null) - // excluded = excluded | LOCAL - bcs = if (name == nme.CONSTRUCTOR) Nil else bcs.tail - } // while (!bcs.isEmpty) - required |= DEFERRED - excluded &= ~(DEFERRED.toLong) - } // while (continue) - if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start) - if (suspension ne null) suspension foreach (_.suspended = false) - if (members eq null) { - if (member == NoSymbol) if (Statistics.canEnable) Statistics.incCounter(noMemberCount) - member - } else { - if (Statistics.canEnable) Statistics.incCounter(multMemberCount) - lastM.tl = Nil - baseClasses.head.newOverloaded(this, members) + entry = decls lookupNextEntry entry + } // while (entry ne null) + // excluded = excluded | LOCAL + bcs = if (name == nme.CONSTRUCTOR) Nil else bcs.tail + } // while (!bcs.isEmpty) + required |= DEFERRED + excluded &= ~(DEFERRED.toLong) + } // while (continue) + if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start) + if (members eq null) { + if (member == NoSymbol) if (Statistics.canEnable) Statistics.incCounter(noMemberCount) + member + } else { + if (Statistics.canEnable) Statistics.incCounter(multMemberCount) + lastM.tl = Nil + baseClasses.head.newOverloaded(this, members) + } } + + if (this.isGround) findMemberInternal + else suspendingTypeVars(typeVarsInType(this))(findMemberInternal) } /** The (existential or otherwise) skolems and existentially quantified variables which are free in this type */ @@ -1250,10 +1194,6 @@ trait Types extends api.Types { self: SymbolTable => def setAnnotations(annots: List[AnnotationInfo]): Type = annotatedType(annots, this) def withAnnotations(annots: List[AnnotationInfo]): Type = annotatedType(annots, this) - /** Remove any annotations from this type and from any - * types embedded in this type. */ - def stripAnnotations = StripAnnotationsMap(this) - /** Set the self symbol of an annotated type, or do nothing * otherwise. */ def withSelfsym(sym: Symbol) = this @@ -1346,7 +1286,6 @@ trait Types extends api.Types { self: SymbolTable => override def baseType(clazz: Symbol): Type = this override def safeToString: String = "<error>" override def narrow: Type = this - // override def isNullable: Boolean = true override def kind = "ErrorType" } @@ -1356,7 +1295,6 @@ trait Types extends api.Types { self: SymbolTable => case object WildcardType extends Type { override def isWildcard = true override def safeToString: String = "?" - // override def isNullable: Boolean = true override def kind = "WildcardType" } /** BoundedWildcardTypes, used only during type inference, are created in @@ -1381,7 +1319,6 @@ trait Types extends api.Types { self: SymbolTable => case object NoType extends Type { override def isTrivial: Boolean = true override def safeToString: String = "<notype>" - // override def isNullable: Boolean = true override def kind = "NoType" } @@ -1391,7 +1328,6 @@ trait Types extends api.Types { self: SymbolTable => override def isStable: Boolean = true override def prefixString = "" override def safeToString: String = "<noprefix>" - // override def isNullable: Boolean = true override def kind = "NoPrefixType" } @@ -1404,7 +1340,6 @@ trait Types extends api.Types { self: SymbolTable => assert(false, sym) } - //assert(sym.isClass && !sym.isModuleClass || sym.isRoot, sym) override def isTrivial: Boolean = sym.isPackageClass override def isNotNull = true override def typeSymbol = sym @@ -1430,7 +1365,7 @@ trait Types extends api.Types { self: SymbolTable => def apply(sym: Symbol): Type = ( if (!phase.erasedTypes) unique(new UniqueThisType(sym)) else if (sym.isImplClass) sym.typeOfThis - else sym.tpe + else sym.tpe_* ) } @@ -1445,7 +1380,6 @@ trait Types extends api.Types { self: SymbolTable => } override def isGround = sym.isPackageClass || pre.isGround - // override def isNullable = underlying.isNullable override def isNotNull = underlying.isNotNull private[reflect] var underlyingCache: Type = NoType private[reflect] var underlyingPeriod = NoPeriod @@ -1543,11 +1477,10 @@ trait Types extends api.Types { self: SymbolTable => } private def lowerString = if (emptyLowerBound) "" else " >: " + lo private def upperString = if (emptyUpperBound) "" else " <: " + hi - private def emptyLowerBound = typeIsNothing(lo) - private def emptyUpperBound = typeIsAny(hi) + private def emptyLowerBound = typeIsNothing(lo) || lo.isWildcard + private def emptyUpperBound = typeIsAny(hi) || hi.isWildcard def isEmptyBounds = emptyLowerBound && emptyUpperBound - // override def isNullable: Boolean = NullClass.tpe <:< lo; override def safeToString = lowerString + upperString override def kind = "TypeBoundsType" } @@ -1632,15 +1565,44 @@ trait Types extends api.Types { self: SymbolTable => override def isStructuralRefinement: Boolean = typeSymbol.isAnonOrRefinementClass && (decls exists symbolIsPossibleInRefinement) - // override def isNullable: Boolean = - // parents forall (p => p.isNullable && !p.typeSymbol.isAbstractType); - override def safeToString: String = parentsString(parents) + ( (if (settings.debug.value || parents.isEmpty || (decls.elems ne null)) fullyInitializeScope(decls).mkString("{", "; ", "}") else "") ) } + protected def computeBaseClasses(tpe: Type): List[Symbol] = { + val parents = tpe.parents // adriaan says tpe.parents does work sometimes, so call it only once + val baseTail = ( + if (parents.isEmpty || parents.head.isInstanceOf[PackageTypeRef]) Nil + else { + //Console.println("computing base classes of " + typeSymbol + " at phase " + phase);//DEBUG + // optimized, since this seems to be performance critical + val superclazz = parents.head // parents.isEmpty was already excluded + var mixins = parents.tail + val sbcs = superclazz.baseClasses + var bcs = sbcs + def isNew(clazz: Symbol): Boolean = ( + superclazz.baseTypeIndex(clazz) < 0 && + { var p = bcs; + while ((p ne sbcs) && (p.head != clazz)) p = p.tail; + p eq sbcs + } + ) + while (!mixins.isEmpty) { + def addMixinBaseClasses(mbcs: List[Symbol]): List[Symbol] = + if (mbcs.isEmpty) bcs + else if (isNew(mbcs.head)) mbcs.head :: addMixinBaseClasses(mbcs.tail) + else addMixinBaseClasses(mbcs.tail) + bcs = addMixinBaseClasses(mixins.head.baseClasses) + mixins = mixins.tail + } + bcs + } + ) + tpe.typeSymbol :: baseTail + } + protected def defineBaseTypeSeqOfCompoundType(tpe: CompoundType) = { val period = tpe.baseTypeSeqPeriod if (period != currentPeriod) { @@ -1660,7 +1622,7 @@ trait Types extends api.Types { self: SymbolTable => val paramToVarMap = varToParamMap map (_.swap) val varToParam = new TypeMap { def apply(tp: Type) = varToParamMap get tp match { - case Some(sym) => sym.tpe + case Some(sym) => sym.tpe_* case _ => mapOver(tp) } } @@ -1679,7 +1641,7 @@ trait Types extends api.Types { self: SymbolTable => tpe.baseTypeSeqCache = undetBaseTypeSeq tpe.baseTypeSeqCache = if (tpe.typeSymbol.isRefinementClass) - tpe.memo(compoundBaseTypeSeq(tpe))(_.baseTypeSeq updateHead tpe.typeSymbol.tpe) + tpe.memo(compoundBaseTypeSeq(tpe))(_.baseTypeSeq updateHead tpe.typeSymbol.tpe_*) else compoundBaseTypeSeq(tpe) } finally { @@ -1701,41 +1663,61 @@ trait Types extends api.Types { self: SymbolTable => throw new TypeError("illegal cyclic inheritance involving " + tpe.typeSymbol) } - protected def defineBaseClassesOfCompoundType(tpe: CompoundType) = { - def computeBaseClasses: List[Symbol] = - if (tpe.parents.isEmpty) List(tpe.typeSymbol) - else { - //Console.println("computing base classes of " + typeSymbol + " at phase " + phase);//DEBUG - // optimized, since this seems to be performance critical - val superclazz = tpe.firstParent - var mixins = tpe.parents.tail - val sbcs = superclazz.baseClasses - var bcs = sbcs - def isNew(clazz: Symbol): Boolean = - superclazz.baseTypeIndex(clazz) < 0 && - { var p = bcs; - while ((p ne sbcs) && (p.head != clazz)) p = p.tail; - p eq sbcs - } - while (!mixins.isEmpty) { - def addMixinBaseClasses(mbcs: List[Symbol]): List[Symbol] = - if (mbcs.isEmpty) bcs - else if (isNew(mbcs.head)) mbcs.head :: addMixinBaseClasses(mbcs.tail) - else addMixinBaseClasses(mbcs.tail) - bcs = addMixinBaseClasses(mixins.head.baseClasses) - mixins = mixins.tail + object baseClassesCycleMonitor { + private var open: List[Symbol] = Nil + @inline private def cycleLog(msg: => String) { + if (settings.debug.value) + Console.err.println(msg) + } + def size = open.size + def push(clazz: Symbol) { + cycleLog("+ " + (" " * size) + clazz.fullNameString) + open ::= clazz + } + def pop(clazz: Symbol) { + assert(open.head eq clazz, (clazz, open)) + open = open.tail + } + def isOpen(clazz: Symbol) = open contains clazz + } + + protected def defineBaseClassesOfCompoundType(tpe: CompoundType) { + def define() = defineBaseClassesOfCompoundType(tpe, force = false) + if (!breakCycles || isPastTyper) define() + else tpe match { + // non-empty parents helpfully excludes all package classes + case tpe @ ClassInfoType(_ :: _, _, clazz) if !clazz.isAnonOrRefinementClass => + // Cycle: force update + if (baseClassesCycleMonitor isOpen clazz) + defineBaseClassesOfCompoundType(tpe, force = true) + else { + baseClassesCycleMonitor push clazz + try define() + finally baseClassesCycleMonitor pop clazz } - tpe.typeSymbol :: bcs - } + case _ => + define() + } + } + private def defineBaseClassesOfCompoundType(tpe: CompoundType, force: Boolean) { val period = tpe.baseClassesPeriod - if (period != currentPeriod) { + if (period == currentPeriod) { + if (force && breakCycles) { + def what = tpe.typeSymbol + " in " + tpe.typeSymbol.owner.fullNameString + val bcs = computeBaseClasses(tpe) + tpe.baseClassesCache = bcs + warning(s"Breaking cycle in base class computation of $what ($bcs)") + } + } + else { tpe.baseClassesPeriod = currentPeriod if (!isValidForBaseClasses(period)) { val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, baseClassesNanos) else null try { tpe.baseClassesCache = null - tpe.baseClassesCache = tpe.memo(computeBaseClasses)(tpe.typeSymbol :: _.baseClasses.tail) - } finally { + tpe.baseClassesCache = tpe.memo(computeBaseClasses(tpe))(tpe.typeSymbol :: _.baseClasses.tail) + } + finally { if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start) } } @@ -1931,7 +1913,7 @@ trait Types extends api.Types { self: SymbolTable => case tr @ TypeRef(_, sym, args) if args.nonEmpty => val tparams = tr.initializedTypeParams if (settings.debug.value && !sameLength(tparams, args)) - debugwarn("Mismatched zip in computeRefs(): " + sym.info.typeParams + ", " + args) + devWarning(s"Mismatched zip in computeRefs(): ${sym.info.typeParams}, $args") foreach2(tparams, args) { (tparam1, arg) => if (arg contains tparam) { @@ -1974,7 +1956,7 @@ trait Types extends api.Types { self: SymbolTable => var change = false for ((from, targets) <- refs(NonExpansive).iterator) for (target <- targets) { - var thatInfo = classInfo(target) + val thatInfo = classInfo(target) if (thatInfo.state != Initialized) change = change | thatInfo.propagate() addRefs(NonExpansive, from, thatInfo.getRefs(NonExpansive, target)) @@ -1982,7 +1964,7 @@ trait Types extends api.Types { self: SymbolTable => } for ((from, targets) <- refs(Expansive).iterator) for (target <- targets) { - var thatInfo = classInfo(target) + val thatInfo = classInfo(target) if (thatInfo.state != Initialized) change = change | thatInfo.propagate() addRefs(Expansive, from, thatInfo.getRefs(NonExpansive, target)) @@ -1993,11 +1975,6 @@ trait Types extends api.Types { self: SymbolTable => change } - // override def isNullable: Boolean = - // symbol == AnyClass || - // symbol != NothingClass && (symbol isSubClass ObjectClass) && !(symbol isSubClass NonNullClass); - - // override def isNonNull: Boolean = symbol == NonNullClass || super.isNonNull; override def kind = "ClassInfoType" override def safeToString = @@ -2022,8 +1999,6 @@ trait Types extends api.Types { self: SymbolTable => extends ClassInfoType(List(), decls, clazz) /** A class representing a constant type. - * - * @param value ... */ abstract case class ConstantType(value: Constant) extends SingletonType with ConstantTypeApi { override def underlying: Type = value.tpe @@ -2033,8 +2008,6 @@ trait Types extends api.Types { self: SymbolTable => override def deconst: Type = underlying override def safeToString: String = underlying.toString + "(" + value.escapedStringValue + ")" - // override def isNullable: Boolean = value.value eq null - // override def isNonNull: Boolean = value.value ne null override def kind = "ConstantType" } @@ -2064,7 +2037,7 @@ trait Types extends api.Types { self: SymbolTable => // it later turns out not to have kind *. See SI-4070. Only // logging it for now. if (sym.typeParams.size != args.size) - log("!!! %s.transform(%s), but tparams.isEmpty and args=".format(this, tp, args)) + devWarning(s"$this.transform($tp), but tparams.isEmpty and args=$args") asSeenFromOwner(tp).instantiateTypeParams(sym.typeParams, args) } @@ -2296,7 +2269,6 @@ trait Types extends api.Types { self: SymbolTable => } override def isStable = bounds.hi.typeSymbol isSubClass SingletonClass override def bounds = thisInfo.bounds - // def transformInfo(tp: Type): Type = appliedType(tp.asSeenFrom(pre, sym.owner), typeArgsOrDummies) override protected[Types] def baseTypeSeqImpl: BaseTypeSeq = transform(bounds.hi).baseTypeSeq prepend this override def kind = "AbstractTypeRef" } @@ -2833,9 +2805,13 @@ trait Types extends api.Types { self: SymbolTable => override def kind = "OverloadedType" } - def overloadedType(pre: Type, alternatives: List[Symbol]): Type = - if (alternatives.tail.isEmpty) pre memberType alternatives.head - else OverloadedType(pre, alternatives) + /** The canonical creator for OverloadedTypes. + */ + def overloadedType(pre: Type, alternatives: List[Symbol]): Type = alternatives match { + case Nil => NoType + case alt :: Nil => pre memberType alt + case _ => OverloadedType(pre, alternatives) + } /** A class remembering a type instantiation for some a set of overloaded * polymorphic symbols. @@ -2845,21 +2821,9 @@ trait Types extends api.Types { self: SymbolTable => override def safeToString = pre.toString + targs.mkString("(with type arguments ", ", ", ")"); override def memberType(sym: Symbol) = appliedType(pre.memberType(sym), targs) -// override def memberType(sym: Symbol) = pre.memberType(sym) match { -// case PolyType(tparams, restp) => -// restp.subst(tparams, targs) -// /* I don't think this is needed, as existential types close only over value types -// case ExistentialType(tparams, qtpe) => -// existentialAbstraction(tparams, qtpe.memberType(sym)) -// */ -// case ErrorType => -// ErrorType -// } override def kind = "AntiPolyType" } - //private var tidCount = 0 //DEBUG - object HasTypeMember { def apply(name: TypeName, tp: Type): Type = { val bound = refinedType(List(WildcardType), NoSymbol) @@ -2874,16 +2838,6 @@ trait Types extends api.Types { self: SymbolTable => } } - // Not used yet. - object HasTypeParams { - def unapply(tp: Type): Option[(List[Symbol], Type)] = tp match { - case AnnotatedType(_, tp, _) => unapply(tp) - case ExistentialType(tparams, qtpe) => Some((tparams, qtpe)) - case PolyType(tparams, restpe) => Some((tparams, restpe)) - case _ => None - } - } - //@M // a TypeVar used to be a case class with only an origin and a constr // then, constr became mutable (to support UndoLog, I guess), @@ -2977,7 +2931,6 @@ trait Types extends api.Types { self: SymbolTable => require(params.nonEmpty, this) override def isHigherKinded = true - override protected def typeVarString = params.map(_.name).mkString("[", ", ", "]=>" + originName) } /** Precondition: zipped params/args nonEmpty. (Size equivalence enforced structurally.) @@ -2992,10 +2945,6 @@ trait Types extends api.Types { self: SymbolTable => override def params: List[Symbol] = zippedArgs map (_._1) override def typeArgs: List[Type] = zippedArgs map (_._2) - - override protected def typeVarString = ( - zippedArgs map { case (p, a) => p.name + "=" + a } mkString (origin + "[", ", ", "]") - ) } trait UntouchableTypeVar extends TypeVar { @@ -3039,7 +2988,6 @@ trait Types extends api.Types { self: SymbolTable => * in operations that are exposed from types. Hence, no syncing of `constr` * or `encounteredHigherLevel` or `suspended` accesses should be necessary. */ -// var constr = constr0 def instValid = constr.instValid override def isGround = instValid && constr.inst.isGround @@ -3092,7 +3040,10 @@ trait Types extends api.Types { self: SymbolTable => // invariant: before mutating constr, save old state in undoLog // (undoLog is used to reset constraints to avoid piling up unrelated ones) def setInst(tp: Type) { -// assert(!(tp containsTp this), this) + if (tp eq this) { + log(s"TypeVar cycle: called setInst passing $this to itself.") + return + } undoLog record this // if we were compared against later typeskolems, repack the existential, // because skolems are only compatible if they were created at the same level @@ -3237,16 +3188,19 @@ trait Types extends api.Types { self: SymbolTable => def registerTypeEquality(tp: Type, typeVarLHS: Boolean): Boolean = { // println("regTypeEq: "+(safeToString, debugString(tp), tp.getClass, if (typeVarLHS) "in LHS" else "in RHS", if (suspended) "ZZ" else if (constr.instValid) "IV" else "")) //@MDEBUG -// println("constr: "+ constr) - def checkIsSameType(tp: Type) = - if(typeVarLHS) constr.inst =:= tp - else tp =:= constr.inst + def checkIsSameType(tp: Type) = ( + if (typeVarLHS) constr.inst =:= tp + else tp =:= constr.inst + ) if (suspended) tp =:= origin else if (constr.instValid) checkIsSameType(tp) else isRelatable(tp) && { val newInst = wildcardToTypeVarMap(tp) - (constr isWithinBounds newInst) && { setInst(tp); true } + (constr isWithinBounds newInst) && { + setInst(newInst) + true + } } } @@ -3309,7 +3263,6 @@ trait Types extends api.Types { self: SymbolTable => ).flatten map (s => s.decodedName + tparamsOfSym(s)) mkString "#" } private def levelString = if (settings.explaintypes.value) level else "" - protected def typeVarString = originName override def safeToString = ( if ((constr eq null) || (constr.inst eq null)) "TVar<" + originName + "=null>" else if (constr.inst ne NoType) "=?" + constr.inst @@ -3420,22 +3373,12 @@ trait Types extends api.Types { self: SymbolTable => case class NamedType(name: Name, tp: Type) extends Type { override def safeToString: String = name.toString +": "+ tp } - - /** A De Bruijn index referring to a previous type argument. Only used - * as a serialization format. - */ - case class DeBruijnIndex(level: Int, idx: Int, args: List[Type]) extends Type { - override def safeToString: String = "De Bruijn index("+level+","+idx+")" - } - - /** A binder defining data associated with De Bruijn indices. Only used - * as a serialization format. + /** As with NamedType, used only when calling isApplicable. + * Records that the application has a wildcard star (aka _*) + * at the end of it. */ - case class DeBruijnBinder(pnames: List[Name], ptypes: List[Type], restpe: Type) extends Type { - override def safeToString = { - val kind = if (pnames.head.isTypeName) "poly" else "method" - "De Bruijn "+kind+"("+(pnames mkString ",")+";"+(ptypes mkString ",")+";"+restpe+")" - } + case class RepeatedType(tp: Type) extends Type { + override def safeToString: String = tp + ": _*" } /** A temporary type representing the erasure of a user-defined value type. @@ -3480,11 +3423,6 @@ trait Types extends api.Types { self: SymbolTable => (if (typeParams.isEmpty) "" else typeParamsString(this)) + super.safeToString } - // def mkLazyType(tparams: Symbol*)(f: Symbol => Unit): LazyType = ( - // if (tparams.isEmpty) new LazyType { override def complete(sym: Symbol) = f(sym) } - // else new LazyPolyType(tparams.toList) { override def complete(sym: Symbol) = f(sym) } - // ) - // Creators --------------------------------------------------------------- /** Rebind symbol `sym` to an overriding member in type `pre`. */ @@ -3529,10 +3467,6 @@ trait Types extends api.Types { self: SymbolTable => } /** The canonical creator for a refined type with an initially empty scope. - * - * @param parents ... - * @param owner ... - * @return ... */ def refinedType(parents: List[Type], owner: Symbol): Type = refinedType(parents, owner, newScope, owner.pos) @@ -3571,12 +3505,6 @@ trait Types extends api.Types { self: SymbolTable => val pre1 = pre match { case x: SuperType if sym1.isEffectivelyFinal || sym1.isDeferred => x.thistpe - case _: CompoundType if sym1.isClass => - // sharpen prefix so that it is maximal and still contains the class. - pre.parents.reverse dropWhile (_.member(sym1.name) != sym1) match { - case Nil => pre - case parent :: _ => parent - } case _ => pre } if (pre eq pre1) TypeRef(pre, sym1, args) @@ -3658,16 +3586,16 @@ trait Types extends api.Types { self: SymbolTable => tycon match { case TypeRef(pre, sym @ (NothingClass|AnyClass), _) => copyTypeRef(tycon, pre, sym, Nil) //@M drop type args to Any/Nothing - case TypeRef(pre, sym, _) => copyTypeRef(tycon, pre, sym, args) + case TypeRef(pre, sym, Nil) => copyTypeRef(tycon, pre, sym, args) + case TypeRef(pre, sym, bogons) => devWarning(s"Dropping $bogons from $tycon in appliedType.") ; copyTypeRef(tycon, pre, sym, args) case PolyType(tparams, restpe) => restpe.instantiateTypeParams(tparams, args) case ExistentialType(tparams, restpe) => newExistentialType(tparams, appliedType(restpe, args)) case st: SingletonType => appliedType(st.widen, args) // @M TODO: what to do? see bug1 - case RefinedType(parents, decls) => RefinedType(parents map (appliedType(_, args)), decls) // MO to AM: please check - case TypeBounds(lo, hi) => TypeBounds(appliedType(lo, args), appliedType(hi, args)) + case RefinedType(parents, decls) => RefinedType(parents map (appliedType(_, args)), decls) // @PP: Can this be right? + case TypeBounds(lo, hi) => TypeBounds(appliedType(lo, args), appliedType(hi, args)) // @PP: Can this be right? case tv@TypeVar(_, _) => tv.applyArgs(args) case AnnotatedType(annots, underlying, self) => AnnotatedType(annots, appliedType(underlying, args), self) - case ErrorType => tycon - case WildcardType => tycon // needed for neg/t0226 + case ErrorType | WildcardType => tycon case _ => abort(debugString(tycon)) } } @@ -3676,25 +3604,6 @@ trait Types extends api.Types { self: SymbolTable => def appliedType(tyconSym: Symbol, args: Type*): Type = appliedType(tyconSym.typeConstructor, args.toList) - /** A creator for existential types where the type arguments, - * rather than being applied directly, are interpreted as the - * upper bounds of unknown types. For instance if the type argument - * list given is List(AnyRefClass), the resulting type would be - * e.g. Set[_ <: AnyRef] rather than Set[AnyRef] . - */ - def appliedTypeAsUpperBounds(tycon: Type, args: List[Type]): Type = { - tycon match { - case TypeRef(pre, sym, _) if sameLength(sym.typeParams, args) => - val eparams = typeParamsToExistentials(sym) - val bounds = args map (TypeBounds upper _) - foreach2(eparams, bounds)(_ setInfo _) - - newExistentialType(eparams, typeRef(pre, sym, eparams map (_.tpe))) - case _ => - appliedType(tycon, args) - } - } - /** A creator and extractor for type parameterizations that strips empty type parameter lists. * Use this factory method to indicate the type has kind * (it's a polymorphic value) * until we start tracking explicit kinds equivalent to typeFun (except that the latter requires tparams nonEmpty). @@ -3796,18 +3705,6 @@ trait Types extends api.Types { self: SymbolTable => } } - /** Substitutes the empty scope for any non-empty decls in the type. */ - object dropAllRefinements extends TypeMap { - def apply(tp: Type): Type = tp match { - case rt @ RefinedType(parents, decls) if !decls.isEmpty => - mapOver(copyRefinedType(rt, parents, EmptyScope)) - case ClassInfoType(parents, decls, clazz) if !decls.isEmpty => - mapOver(ClassInfoType(parents, EmptyScope, clazz)) - case _ => - mapOver(tp) - } - } - /** Type with all top-level occurrences of abstract types replaced by their bounds */ def abstractTypesToBounds(tp: Type): Type = tp match { // @M don't normalize here (compiler loops on pos/bug1090.scala ) case TypeRef(_, sym, _) if sym.isAbstractType => @@ -3830,12 +3727,16 @@ trait Types extends api.Types { self: SymbolTable => // This is the specified behavior. protected def etaExpandKeepsStar = false - object dropRepeatedParamType extends TypeMap { + /** Turn any T* types into Seq[T] except when + * in method parameter position. + */ + object dropIllegalStarTypes extends TypeMap { def apply(tp: Type): Type = tp match { case MethodType(params, restpe) => - MethodType(params, apply(restpe)) - case PolyType(tparams, restpe) => - PolyType(tparams, apply(restpe)) + // Not mapping over params + val restpe1 = apply(restpe) + if (restpe eq restpe1) tp + else MethodType(params, restpe1) case TypeRef(_, RepeatedParamClass, arg :: Nil) => seqType(arg) case _ => @@ -3843,50 +3744,6 @@ trait Types extends api.Types { self: SymbolTable => } } - object toDeBruijn extends TypeMap { - private var paramStack: List[List[Symbol]] = Nil - def mkDebruijnBinder(params: List[Symbol], restpe: Type) = { - paramStack = params :: paramStack - try { - DeBruijnBinder(params map (_.name), params map (p => this(p.info)), this(restpe)) - } finally paramStack = paramStack.tail - } - def apply(tp: Type): Type = tp match { - case PolyType(tparams, restpe) => - mkDebruijnBinder(tparams, restpe) - case MethodType(params, restpe) => - mkDebruijnBinder(params, restpe) - case TypeRef(NoPrefix, sym, args) => - val level = paramStack indexWhere (_ contains sym) - if (level < 0) mapOver(tp) - else DeBruijnIndex(level, paramStack(level) indexOf sym, args mapConserve this) - case _ => - mapOver(tp) - } - } - - def fromDeBruijn(owner: Symbol) = new TypeMap { - private var paramStack: List[List[Symbol]] = Nil - def apply(tp: Type): Type = tp match { - case DeBruijnBinder(pnames, ptypes, restpe) => - val isType = pnames.head.isTypeName - val newParams = for (name <- pnames) yield - if (isType) owner.newTypeParameter(name.toTypeName) - else owner.newValueParameter(name.toTermName) - paramStack = newParams :: paramStack - try { - foreach2(newParams, ptypes)((p, t) => p setInfo this(t)) - val restpe1 = this(restpe) - if (isType) PolyType(newParams, restpe1) - else MethodType(newParams, restpe1) - } finally paramStack = paramStack.tail - case DeBruijnIndex(level, idx, args) => - TypeRef(NoPrefix, paramStack(level)(idx), args map this) - case _ => - mapOver(tp) - } - } - // Hash consing -------------------------------------------------------------- private val initialUniquesCapacity = 4096 @@ -4092,7 +3949,7 @@ trait Types extends api.Types { self: SymbolTable => variance = -variance val tparams1 = mapOver(tparams) variance = -variance - var result1 = this(result) + val result1 = this(result) if ((tparams1 eq tparams) && (result1 eq result)) tp else PolyType(tparams1, result1.substSym(tparams, tparams1)) case TypeBounds(lo, hi) => @@ -4154,7 +4011,7 @@ trait Types extends api.Types { self: SymbolTable => else copyMethodType(tp, params1, result1.substSym(params, params1)) case PolyType(tparams, result) => val tparams1 = mapOver(tparams) - var result1 = this(result) + val result1 = this(result) if ((tparams1 eq tparams) && (result1 eq result)) tp else PolyType(tparams1, result1.substSym(tparams, tparams1)) case NullaryMethodType(result) => @@ -4179,12 +4036,10 @@ trait Types extends api.Types { self: SymbolTable => case rtp @ RefinedType(parents, decls) => val parents1 = parents mapConserve this val decls1 = mapOver(decls) - //if ((parents1 eq parents) && (decls1 eq decls)) tp - //else refinementOfClass(tp.typeSymbol, parents1, decls1) copyRefinedType(rtp, parents1, decls1) case ExistentialType(tparams, result) => val tparams1 = mapOver(tparams) - var result1 = this(result) + val result1 = this(result) if ((tparams1 eq tparams) && (result1 eq result)) tp else newExistentialType(tparams1, result1.substSym(tparams, tparams1)) case OverloadedType(pre, alts) => @@ -4209,10 +4064,6 @@ trait Types extends api.Types { self: SymbolTable => if ((annots1 eq annots) && (atp1 eq atp)) tp else if (annots1.isEmpty) atp1 else AnnotatedType(annots1, atp1, selfsym) - case DeBruijnIndex(shift, idx, args) => - val args1 = args mapConserve this - if (args1 eq args) tp - else DeBruijnIndex(shift, idx, args1) /* case ErrorType => tp case WildcardType => tp @@ -4319,21 +4170,6 @@ trait Types extends api.Types { self: SymbolTable => } } - /** A collector that tests for existential types appearing at given variance in a type - * @PP: Commenting out due to not being used anywhere. - */ - // class ContainsVariantExistentialCollector(v: Int) extends TypeCollector(false) with VariantTypeMap { - // variance = v - // - // def traverse(tp: Type) = tp match { - // case ExistentialType(_, _) if (variance == v) => result = true - // case _ => mapOver(tp) - // } - // } - // - // val containsCovariantExistentialCollector = new ContainsVariantExistentialCollector(1) - // val containsContravariantExistentialCollector = new ContainsVariantExistentialCollector(-1) - def typeParamsToExistentials(clazz: Symbol, tparams: List[Symbol]): List[Symbol] = { val eparams = mapWithIndex(tparams)((tparam, i) => clazz.newExistential(newTypeName("?"+i), clazz.pos) setInfo tparam.info.bounds) @@ -4381,6 +4217,20 @@ trait Types extends api.Types { self: SymbolTable => mapOver(tp) } } + /*** + *@M: I think this is more desirable, but Martin prefers to leave raw-types as-is as much as possible + object rawToExistentialInJava extends TypeMap { + def apply(tp: Type): Type = tp match { + // any symbol that occurs in a java sig, not just java symbols + // see http://lampsvn.epfl.ch/trac/scala/ticket/2454#comment:14 + case TypeRef(pre, sym, List()) if !sym.typeParams.isEmpty => + val eparams = typeParamsToExistentials(sym, sym.typeParams) + existentialAbstraction(eparams, TypeRef(pre, sym, eparams map (_.tpe))) + case _ => + mapOver(tp) + } + } + */ /** Used by existentialAbstraction. */ @@ -4615,16 +4465,18 @@ trait Types extends api.Types { self: SymbolTable => tp } - def apply(tp0: Type): Type = if (from.isEmpty) tp0 else { - @tailrec def subst(tp: Type, sym: Symbol, from: List[Symbol], to: List[T]): Type = - if (from.isEmpty) tp - // else if (to.isEmpty) error("Unexpected substitution on '%s': from = %s but to == Nil".format(tp, from)) - else if (matches(from.head, sym)) toType(tp, to.head) - else subst(tp, sym, from.tail, to.tail) + @tailrec private def subst(tp: Type, sym: Symbol, from: List[Symbol], to: List[T]): Type = ( + if (from.isEmpty) tp + // else if (to.isEmpty) error("Unexpected substitution on '%s': from = %s but to == Nil".format(tp, from)) + else if (matches(from.head, sym)) toType(tp, to.head) + else subst(tp, sym, from.tail, to.tail) + ) - val boundSyms = tp0.boundSyms - val tp1 = if (boundSyms.nonEmpty && (boundSyms exists from.contains)) renameBoundSyms(tp0) else tp0 - val tp = mapOver(tp1) + def apply(tp0: Type): Type = if (from.isEmpty) tp0 else { + val boundSyms = tp0.boundSyms + val tp1 = if (boundSyms.nonEmpty && (boundSyms exists from.contains)) renameBoundSyms(tp0) else tp0 + val tp = mapOver(tp1) + def substFor(sym: Symbol) = subst(tp, sym, from, to) tp match { // @M @@ -4639,9 +4491,11 @@ trait Types extends api.Types { self: SymbolTable => // (must not recurse --> loops) // 3) replacing m by List in m[Int] should yield List[Int], not just List case TypeRef(NoPrefix, sym, args) => - appliedType(subst(tp, sym, from, to), args) // if args.isEmpty, appliedType is the identity + val tcon = substFor(sym) + if ((tp eq tcon) || args.isEmpty) tcon + else appliedType(tcon.typeConstructor, args) case SingleType(NoPrefix, sym) => - subst(tp, sym, from, to) + substFor(sym) case _ => tp } @@ -4650,29 +4504,35 @@ trait Types extends api.Types { self: SymbolTable => /** A map to implement the `substSym` method. */ class SubstSymMap(from: List[Symbol], to: List[Symbol]) extends SubstMap(from, to) { + def this(pairs: (Symbol, Symbol)*) = this(pairs.toList.map(_._1), pairs.toList.map(_._2)) + protected def toType(fromtp: Type, sym: Symbol) = fromtp match { case TypeRef(pre, _, args) => copyTypeRef(fromtp, pre, sym, args) case SingleType(pre, _) => singleType(pre, sym) } - override def apply(tp: Type): Type = if (from.isEmpty) tp else { - @tailrec def subst(sym: Symbol, from: List[Symbol], to: List[Symbol]): Symbol = - if (from.isEmpty) sym - // else if (to.isEmpty) error("Unexpected substitution on '%s': from = %s but to == Nil".format(sym, from)) - else if (matches(from.head, sym)) to.head - else subst(sym, from.tail, to.tail) - tp match { + @tailrec private def subst(sym: Symbol, from: List[Symbol], to: List[Symbol]): Symbol = ( + if (from.isEmpty) sym + // else if (to.isEmpty) error("Unexpected substitution on '%s': from = %s but to == Nil".format(sym, from)) + else if (matches(from.head, sym)) to.head + else subst(sym, from.tail, to.tail) + ) + private def substFor(sym: Symbol) = subst(sym, from, to) + + override def apply(tp: Type): Type = ( + if (from.isEmpty) tp + else tp match { case TypeRef(pre, sym, args) if pre ne NoPrefix => - val newSym = subst(sym, from, to) + val newSym = substFor(sym) // mapOver takes care of subst'ing in args mapOver ( if (sym eq newSym) tp else copyTypeRef(tp, pre, newSym, args) ) // assert(newSym.typeParams.length == sym.typeParams.length, "typars mismatch in SubstSymMap: "+(sym, sym.typeParams, newSym, newSym.typeParams)) case SingleType(pre, sym) if pre ne NoPrefix => - val newSym = subst(sym, from, to) + val newSym = substFor(sym) mapOver( if (sym eq newSym) tp else singleType(pre, newSym) ) case _ => super.apply(tp) } - } + ) override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = { object trans extends TypeMapTransformer { @@ -4843,15 +4703,6 @@ trait Types extends api.Types { self: SymbolTable => } } - object StripAnnotationsMap extends TypeMap { - def apply(tp: Type): Type = tp match { - case AnnotatedType(_, atp, _) => - mapOver(atp) - case tp => - mapOver(tp) - } - } - /** A map to convert every occurrence of a wildcard type to a fresh * type variable */ object wildcardToTypeVarMap extends TypeMap { @@ -4913,8 +4764,6 @@ trait Types extends api.Types { self: SymbolTable => /** A map to implement the `filter` method. */ class FilterTypeCollector(p: Type => Boolean) extends TypeCollector[List[Type]](Nil) { - def withFilter(q: Type => Boolean) = new FilterTypeCollector(tp => p(tp) && q(tp)) - override def collect(tp: Type) = super.collect(tp).reverse def traverse(tp: Type) { @@ -5024,7 +4873,7 @@ trait Types extends api.Types { self: SymbolTable => else { var rebind0 = pre.findMember(sym.name, BRIDGE, 0, true) orElse { if (sym.isAliasType) throw missingAliasException - debugwarn(pre+"."+sym+" does no longer exist, phase = "+phase) + devWarning(s"$pre.$sym no longer exist at phase $phase") throw new MissingTypeControl // For build manager and presentation compiler purposes } /** The two symbols have the same fully qualified name */ @@ -5082,7 +4931,7 @@ trait Types extends api.Types { self: SymbolTable => if ((pre1 eq pre) && (sym1 eq sym) && (args1 eq args)/* && sym.isExternal*/) { tp } else if (sym1 == NoSymbol) { - debugwarn("adapt fail: "+pre+" "+pre1+" "+sym) + devWarning(s"adapt to new run failed: pre=$pre pre1=$pre1 sym=$sym") tp } else { copyTypeRef(tp, pre1, sym1, args1) @@ -5133,28 +4982,18 @@ trait Types extends api.Types { self: SymbolTable => class SubTypePair(val tp1: Type, val tp2: Type) { override def hashCode = tp1.hashCode * 41 + tp2.hashCode - override def equals(other: Any) = other match { + override def equals(other: Any) = (this eq other.asInstanceOf[AnyRef]) || (other match { + // suspend TypeVars in types compared by =:=, + // since we don't want to mutate them simply to check whether a subtype test is pending + // in addition to making subtyping "more correct" for type vars, + // it should avoid the stackoverflow that's been plaguing us (https://groups.google.com/d/topic/scala-internals/2gHzNjtB4xA/discussion) + // this method is only called when subtyping hits a recursion threshold (subsametypeRecursions >= LogPendingSubTypesThreshold) case stp: SubTypePair => - // suspend TypeVars in types compared by =:=, - // since we don't want to mutate them simply to check whether a subtype test is pending - // in addition to making subtyping "more correct" for type vars, - // it should avoid the stackoverflow that's been plaguing us (https://groups.google.com/d/topic/scala-internals/2gHzNjtB4xA/discussion) - // this method is only called when subtyping hits a recursion threshold (subsametypeRecursions >= LogPendingSubTypesThreshold) - def suspend(tp: Type) = - if (tp.isGround) null else suspendTypeVarsInType(tp) - def revive(suspension: List[TypeVar]) = - if (suspension ne null) suspension foreach (_.suspended = false) - - val suspensions = Array(tp1, stp.tp1, tp2, stp.tp2) map suspend - - val sameTypes = (tp1 =:= stp.tp1) && (tp2 =:= stp.tp2) - - suspensions foreach revive - - sameTypes + val tvars = List(tp1, stp.tp1, tp2, stp.tp2) flatMap (t => if (t.isGround) Nil else typeVarsInType(t)) + suspendingTypeVars(tvars)(tp1 =:= stp.tp1 && tp2 =:= stp.tp2) case _ => false - } + }) override def toString = tp1+" <:<? "+tp2 } @@ -5226,32 +5065,33 @@ trait Types extends api.Types { self: SymbolTable => def isPopulated(tp1: Type, tp2: Type): Boolean = { def isConsistent(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match { case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => - assert(sym1 == sym2) + assert(sym1 == sym2, (sym1, sym2)) pre1 =:= pre2 && - forall3(args1, args2, sym1.typeParams) { (arg1, arg2, tparam) => - //if (tparam.variance == 0 && !(arg1 =:= arg2)) Console.println("inconsistent: "+arg1+"!="+arg2)//DEBUG + forall3(args1, args2, sym1.typeParams)((arg1, arg2, tparam) => if (tparam.variance == 0) arg1 =:= arg2 - else if (arg1.isInstanceOf[TypeVar]) - // if left-hand argument is a typevar, make it compatible with variance - // this is for more precise pattern matching - // todo: work this in the spec of this method - // also: think what happens if there are embedded typevars? - if (tparam.variance < 0) arg1 <:< arg2 else arg2 <:< arg1 - else true - } + // if left-hand argument is a typevar, make it compatible with variance + // this is for more precise pattern matching + // todo: work this in the spec of this method + // also: think what happens if there are embedded typevars? + else arg1 match { + case _: TypeVar => if (tparam.variance < 0) arg1 <:< arg2 else arg2 <:< arg1 + case _ => true + } + ) case (et: ExistentialType, _) => et.withTypeVars(isConsistent(_, tp2)) case (_, et: ExistentialType) => et.withTypeVars(isConsistent(tp1, _)) } - def check(tp1: Type, tp2: Type) = + def check(tp1: Type, tp2: Type) = ( if (tp1.typeSymbol.isClass && tp1.typeSymbol.hasFlag(FINAL)) tp1 <:< tp2 || isNumericValueClass(tp1.typeSymbol) && isNumericValueClass(tp2.typeSymbol) else tp1.baseClasses forall (bc => tp2.baseTypeIndex(bc) < 0 || isConsistent(tp1.baseType(bc), tp2.baseType(bc))) + ) - check(tp1, tp2)/* && check(tp2, tp1)*/ // need to investgate why this can't be made symmetric -- neg/gadts1 fails, and run/existials also. + check(tp1, tp2) && check(tp2, tp1) } /** Does a pattern of type `patType` need an outer test when executed against @@ -5334,13 +5174,15 @@ trait Types extends api.Types { self: SymbolTable => try { val before = undoLog.log var result = false - - try result = { - isSameType1(tp1, tp2) - } finally if (!result) undoLog.undoTo(before) + try { + result = isSameType1(tp1, tp2) + } + finally if (!result) undoLog.undoTo(before) result - } finally undoLog.unlock() - } finally { + } + finally undoLog.unlock() + } + finally { subsametypeRecursions -= 1 // XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866) // it doesn't help to keep separate recursion counts for the three methods that now share it @@ -5382,108 +5224,7 @@ trait Types extends api.Types { self: SymbolTable => case _ => tp.normalize } */ -/* - private def isSameType0(tp1: Type, tp2: Type): Boolean = { - if (tp1 eq tp2) return true - ((tp1, tp2) match { - case (ErrorType, _) => true - case (WildcardType, _) => true - case (_, ErrorType) => true - case (_, WildcardType) => true - - case (NoType, _) => false - case (NoPrefix, _) => tp2.typeSymbol.isPackageClass - case (_, NoType) => false - case (_, NoPrefix) => tp1.typeSymbol.isPackageClass - - case (ThisType(sym1), ThisType(sym2)) - if (sym1 == sym2) => - true - case (SingleType(pre1, sym1), SingleType(pre2, sym2)) - if (equalSymsAndPrefixes(sym1, pre1, sym2, pre2)) => - true -/* - case (SingleType(pre1, sym1), ThisType(sym2)) - if (sym1.isModule && - sym1.moduleClass == sym2 && - pre1 =:= sym2.owner.thisType) => - true - case (ThisType(sym1), SingleType(pre2, sym2)) - if (sym2.isModule && - sym2.moduleClass == sym1 && - pre2 =:= sym1.owner.thisType) => - true -*/ - case (ConstantType(value1), ConstantType(value2)) => - value1 == value2 - case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => - equalSymsAndPrefixes(sym1, pre1, sym2, pre2) && - ((tp1.isHigherKinded && tp2.isHigherKinded && tp1.normalize =:= tp2.normalize) || - isSameTypes(args1, args2)) - // @M! normalize reduces higher-kinded case to PolyType's - case (RefinedType(parents1, ref1), RefinedType(parents2, ref2)) => - def isSubScope(s1: Scope, s2: Scope): Boolean = s2.toList.forall { - sym2 => - var e1 = s1.lookupEntry(sym2.name) - (e1 ne null) && { - val substSym = sym2.info.substThis(sym2.owner, e1.sym.owner.thisType) - var isEqual = false - while (!isEqual && (e1 ne null)) { - isEqual = e1.sym.info =:= substSym - e1 = s1.lookupNextEntry(e1) - } - isEqual - } - } - //Console.println("is same? " + tp1 + " " + tp2 + " " + tp1.typeSymbol.owner + " " + tp2.typeSymbol.owner)//DEBUG - isSameTypes(parents1, parents2) && isSubScope(ref1, ref2) && isSubScope(ref2, ref1) - case (MethodType(params1, res1), MethodType(params2, res2)) => - // new dependent types: probably fix this, use substSym as done for PolyType - (isSameTypes(tp1.paramTypes, tp2.paramTypes) && - res1 =:= res2 && - tp1.isImplicit == tp2.isImplicit) - case (PolyType(tparams1, res1), PolyType(tparams2, res2)) => - // assert((tparams1 map (_.typeParams.length)) == (tparams2 map (_.typeParams.length))) - (tparams1.length == tparams2.length) && (tparams1 corresponds tparams2)(_.info =:= _.info.substSym(tparams2, tparams1)) && // @M looks like it might suffer from same problem as #2210 - res1 =:= res2.substSym(tparams2, tparams1) - case (ExistentialType(tparams1, res1), ExistentialType(tparams2, res2)) => - (tparams1.length == tparams2.length) && (tparams1 corresponds tparams2)(_.info =:= _.info.substSym(tparams2, tparams1)) && // @M looks like it might suffer from same problem as #2210 - res1 =:= res2.substSym(tparams2, tparams1) - case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) => - lo1 =:= lo2 && hi1 =:= hi2 - case (BoundedWildcardType(bounds), _) => - bounds containsType tp2 - case (_, BoundedWildcardType(bounds)) => - bounds containsType tp1 - case (tv @ TypeVar(_,_), tp) => - tv.registerTypeEquality(tp, true) - case (tp, tv @ TypeVar(_,_)) => - tv.registerTypeEquality(tp, false) - case (AnnotatedType(_,_,_), _) => - annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations - case (_, AnnotatedType(_,_,_)) => - annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations - case (_: SingletonType, _: SingletonType) => - var origin1 = tp1 - while (origin1.underlying.isInstanceOf[SingletonType]) { - assert(origin1 ne origin1.underlying, origin1) - origin1 = origin1.underlying - } - var origin2 = tp2 - while (origin2.underlying.isInstanceOf[SingletonType]) { - assert(origin2 ne origin2.underlying, origin2) - origin2 = origin2.underlying - } - ((origin1 ne tp1) || (origin2 ne tp2)) && (origin1 =:= origin2) - case _ => - false - }) || { - val tp1n = normalizePlus(tp1) - val tp2n = normalizePlus(tp2) - ((tp1n ne tp1) || (tp2n ne tp2)) && isSameType(tp1n, tp2n) - } - } -*/ + private def isSameType1(tp1: Type, tp2: Type): Boolean = { if ((tp1 eq tp2) || (tp1 eq ErrorType) || (tp1 eq WildcardType) || @@ -5622,12 +5363,12 @@ trait Types extends api.Types { self: SymbolTable => } tp1 match { case tv @ TypeVar(_,_) => - return tv.registerTypeEquality(tp2, true) + return tv.registerTypeEquality(tp2, typeVarLHS = true) case _ => } tp2 match { case tv @ TypeVar(_,_) => - return tv.registerTypeEquality(tp1, false) + return tv.registerTypeEquality(tp1, typeVarLHS = false) case _ => } tp1 match { @@ -5756,18 +5497,6 @@ trait Types extends api.Types { self: SymbolTable => false } - @deprecated("The compiler doesn't use this so you shouldn't either - it will be removed", "2.10.0") - def instTypeVar(tp: Type): Type = tp match { - case TypeRef(pre, sym, args) => - copyTypeRef(tp, instTypeVar(pre), sym, args) - case SingleType(pre, sym) => - singleType(instTypeVar(pre), sym) - case TypeVar(_, constr) => - instTypeVar(constr.inst) - case _ => - tp - } - def isErrorOrWildcard(tp: Type) = (tp eq ErrorType) || (tp eq WildcardType) def isSingleType(tp: Type) = tp match { @@ -5805,10 +5534,11 @@ trait Types extends api.Types { self: SymbolTable => * types which are used internally in type applications and * types which are not. */ + /**** Not used right now, but kept around to document which Types + * land in which bucket. private def isInternalTypeNotUsedAsTypeArg(tp: Type): Boolean = tp match { case AntiPolyType(pre, targs) => true case ClassInfoType(parents, defs, clazz) => true - case DeBruijnIndex(level, index, args) => true case ErasedValueType(tref) => true case NoPrefix => true case NoType => true @@ -5816,6 +5546,7 @@ trait Types extends api.Types { self: SymbolTable => case TypeBounds(lo, hi) => true case _ => false } + ****/ private def isInternalTypeUsedAsTypeArg(tp: Type): Boolean = tp match { case WildcardType => true case BoundedWildcardType(_) => true @@ -5861,7 +5592,7 @@ trait Types extends api.Types { self: SymbolTable => * useful as documentation; it is likely that !isNonValueType(tp) * will serve better than isValueType(tp). */ - def isValueType(tp: Type) = isValueElseNonValue(tp) + /** def isValueType(tp: Type) = isValueElseNonValue(tp) */ /** SLS 3.3, Non-Value Types * Is the given type definitely a non-value type, as defined in SLS 3.3? @@ -5872,7 +5603,7 @@ trait Types extends api.Types { self: SymbolTable => * not designated non-value types because there is code which depends on using * them as type arguments, but their precise status is unclear. */ - def isNonValueType(tp: Type) = !isValueElseNonValue(tp) + /** def isNonValueType(tp: Type) = !isValueElseNonValue(tp) */ def isNonRefinementClassType(tpe: Type) = tpe match { case SingleType(_, sym) => sym.isModuleClass @@ -5921,8 +5652,6 @@ trait Types extends api.Types { self: SymbolTable => corresponds3(tps1, tps2, tparams map (_.variance))(isSubArg) } - def differentOrNone(tp1: Type, tp2: Type) = if (tp1 eq tp2) NoType else tp1 - /** Does type `tp1` conform to `tp2`? */ private def isSubType2(tp1: Type, tp2: Type, depth: Int): Boolean = { if ((tp1 eq tp2) || isErrorOrWildcard(tp1) || isErrorOrWildcard(tp2)) return true @@ -6126,18 +5855,6 @@ trait Types extends api.Types { self: SymbolTable => !(sym isNonBottomSubClass AnyValClass) && !(sym isNonBottomSubClass NotNullClass) - /** Are `tps1` and `tps2` lists of equal length such that all elements - * of `tps1` conform to corresponding elements of `tps2`? - */ - def isSubTypes(tps1: List[Type], tps2: List[Type]): Boolean = (tps1 corresponds tps2)(_ <:< _) - - /** Does type `tp` implement symbol `sym` with same or - * stronger type? Exact only if `sym` is a member of some - * refinement type, otherwise we might return false negatives. - */ - def specializesSym(tp: Type, sym: Symbol): Boolean = - specializesSym(tp, sym, AnyDepth) - def specializesSym(tp: Type, sym: Symbol, depth: Int): Boolean = tp.typeSymbol == NothingClass || tp.typeSymbol == NullClass && containsNull(sym.owner) || { @@ -6156,6 +5873,7 @@ trait Types extends api.Types { self: SymbolTable => * than member `sym2` of `tp2`? */ private def specializesSym(tp1: Type, sym1: Symbol, tp2: Type, sym2: Symbol, depth: Int): Boolean = { + require((sym1 ne NoSymbol) && (sym2 ne NoSymbol), ((tp1, sym1, tp2, sym2, depth))) val info1 = tp1.memberInfo(sym1) val info2 = tp2.memberInfo(sym2).substThis(tp2.typeSymbol, tp1) //System.out.println("specializes "+tp1+"."+sym1+":"+info1+sym1.locationString+" AND "+tp2+"."+sym2+":"+info2)//DEBUG @@ -6470,25 +6188,27 @@ trait Types extends api.Types { self: SymbolTable => * @See baseTypeSeq for a definition of sorted and upwards closed. */ private def lubList(ts: List[Type], depth: Int): List[Type] = { - // Matching the type params of one of the initial types means dummies. - val initialTypeParams = ts map (_.typeParams) - def isHotForTs(xs: List[Type]) = initialTypeParams contains (xs map (_.typeSymbol)) + var lubListDepth = 0 + // This catches some recursive situations which would otherwise + // befuddle us, e.g. pos/hklub0.scala + def isHotForTs(xs: List[Type]) = ts exists (_.typeParams == xs.map(_.typeSymbol)) def elimHigherOrderTypeParam(tp: Type) = tp match { - case TypeRef(pre, sym, args) if args.nonEmpty && isHotForTs(args) => tp.typeConstructor - case _ => tp + case TypeRef(_, _, args) if args.nonEmpty && isHotForTs(args) => + logResult("Retracting dummies from " + tp + " in lublist")(tp.typeConstructor) + case _ => tp } - var lubListDepth = 0 - def loop(tsBts: List[List[Type]]): List[Type] = { + // pretypes is a tail-recursion-preserving accumulator. + @annotation.tailrec def loop(pretypes: List[Type], tsBts: List[List[Type]]): List[Type] = { lubListDepth += 1 - if (tsBts.isEmpty || (tsBts exists typeListIsEmpty)) Nil - else if (tsBts.tail.isEmpty) tsBts.head + if (tsBts.isEmpty || (tsBts exists typeListIsEmpty)) pretypes.reverse + else if (tsBts.tail.isEmpty) pretypes.reverse ++ tsBts.head else { // ts0 is the 1-dimensional frontier of symbols cutting through 2-dimensional tsBts. // Invariant: all symbols "under" (closer to the first row) the frontier // are smaller (according to _.isLess) than the ones "on and beyond" the frontier - val ts0 = tsBts map (_.head) + val ts0 = tsBts map (_.head) // Is the frontier made up of types with the same symbol? val isUniformFrontier = (ts0: @unchecked) match { @@ -6501,23 +6221,23 @@ trait Types extends api.Types { self: SymbolTable => // merging, strip targs that refer to bound tparams (when we're computing the lub of type // constructors.) Also filter out all types that are a subtype of some other type. if (isUniformFrontier) { - if (settings.debug.value || printLubs) { - val fbounds = findRecursiveBounds(ts0) - if (fbounds.nonEmpty) { - println("Encountered " + fbounds.size + " recursive bounds while lubbing " + ts0.size + " types.") - for ((p0, p1) <- fbounds) { - val desc = if (p0 == p1) "its own bounds" else "the bounds of " + p1 - - println(" " + p0.fullLocationString + " appears in " + desc) - println(" " + p1 + " " + p1.info.bounds) + val fbounds = findRecursiveBounds(ts0) map (_._2) + val tcLubList = typeConstructorLubList(ts0) + def isRecursive(tp: Type) = tp.typeSymbol.typeParams exists fbounds.contains + + val ts1 = ts0 map { t => + if (isRecursive(t)) { + tcLubList map (t baseType _.typeSymbol) find (t => !isRecursive(t)) match { + case Some(tp) => logResult(s"Breaking recursion in lublist, substituting weaker type.\n Was: $t\n Now")(tp) + case _ => t } - println("") } + else t } val tails = tsBts map (_.tail) - mergePrefixAndArgs(elimSub(ts0 map elimHigherOrderTypeParam, depth), 1, depth) match { - case Some(tp) => tp :: loop(tails) - case _ => loop(tails) + mergePrefixAndArgs(elimSub(ts1, depth) map elimHigherOrderTypeParam, 1, depth) match { + case Some(tp) => loop(tp :: pretypes, tails) + case _ => loop(pretypes, tails) } } else { @@ -6534,7 +6254,7 @@ trait Types extends api.Types { self: SymbolTable => printLubMatrix((ts zip tsBts).toMap, lubListDepth) } - loop(newtps) + loop(pretypes, newtps) } } } @@ -6543,7 +6263,7 @@ trait Types extends api.Types { self: SymbolTable => if (printLubs) printLubMatrix((ts zip initialBTSes).toMap, depth) - loop(initialBTSes) + loop(Nil, initialBTSes) } /** The minimal symbol of a list of types (as determined by `Symbol.isLess`). */ @@ -6576,10 +6296,6 @@ trait Types extends api.Types { self: SymbolTable => case _ => t } - def elimRefinement(t: Type) = t match { - case RefinedType(parents, decls) if !decls.isEmpty => intersectionType(parents) - case _ => t - } /** Eliminate from list of types all elements which are a subtype * of some other element of the list. */ @@ -6624,28 +6340,12 @@ trait Types extends api.Types { self: SymbolTable => (annotationsLub(lub(ts map (_.withoutAnnotations)), ts), true) else (lub(ts), false) - def weakGlb(ts: List[Type]) = { - if (ts.nonEmpty && (ts forall isNumericValueType)) { - val nglb = numericGlb(ts) - if (nglb != NoType) (nglb, true) - else (glb(ts), false) - } else if (ts exists typeHasAnnotations) { - (annotationsGlb(glb(ts map (_.withoutAnnotations)), ts), true) - } else (glb(ts), false) - } - def numericLub(ts: List[Type]) = ts reduceLeft ((t1, t2) => if (isNumericSubType(t1, t2)) t2 else if (isNumericSubType(t2, t1)) t1 else IntClass.tpe) - def numericGlb(ts: List[Type]) = - ts reduceLeft ((t1, t2) => - if (isNumericSubType(t1, t2)) t1 - else if (isNumericSubType(t2, t1)) t2 - else NoType) - def isWeakSubType(tp1: Type, tp2: Type) = tp1.deconst.normalize match { case TypeRef(_, sym1, _) if isNumericValueClass(sym1) => @@ -6681,6 +6381,23 @@ trait Types extends api.Types { self: SymbolTable => private val lubResults = new mutable.HashMap[(Int, List[Type]), Type] private val glbResults = new mutable.HashMap[(Int, List[Type]), Type] + /** Given a list of types, finds all the base classes they have in + * common, then returns a list of type constructors derived directly + * from the symbols (so any more specific type information is ignored.) + * The list is filtered such that every type constructor in the list + * expects the same number of type arguments, which is chosen based + * on the deepest class among the common baseclasses. + */ + def typeConstructorLubList(ts: List[Type]): List[Type] = { + val bcs = ts.flatMap(_.baseClasses).distinct sortWith (_ isLess _) + val tcons = bcs filter (clazz => ts forall (_.typeSymbol isSubClass clazz)) + + tcons map (_.typeConstructor) match { + case Nil => Nil + case t :: ts => t :: ts.filter(_.typeParams.size == t.typeParams.size) + } + } + def lub(ts: List[Type]): Type = ts match { case List() => NothingClass.tpe case List(t) => t @@ -6688,8 +6405,20 @@ trait Types extends api.Types { self: SymbolTable => if (Statistics.canEnable) Statistics.incCounter(lubCount) val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, lubNanos) else null try { - lub(ts, lubDepth(ts)) - } finally { + val res = lub(ts, lubDepth(ts)) + // If the number of unapplied type parameters in all incoming + // types is consistent, and the lub does not match that, return + // the type constructor of the calculated lub instead. This + // is because lubbing type constructors tends to result in types + // which have been applied to dummies or Nothing. + ts.map(_.typeParams.size).distinct match { + case x :: Nil if res.typeParams.size != x => + logResult(s"Stripping type args from lub because $res is not consistent with $ts")(res.typeConstructor) + case _ => + res + } + } + finally { lubResults.clear() glbResults.clear() if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start) @@ -6723,13 +6452,13 @@ trait Types extends api.Types { self: SymbolTable => } } def lub1(ts0: List[Type]): Type = { - val (ts, tparams) = stripExistentialsAndTypeVars(ts0) + val (ts, tparams) = stripExistentialsAndTypeVars(ts0) val lubBaseTypes: List[Type] = lubList(ts, depth) - val lubParents = spanningTypes(lubBaseTypes) - val lubOwner = commonOwner(ts) - val lubBase = intersectionType(lubParents, lubOwner) + val lubParents = spanningTypes(lubBaseTypes) + val lubOwner = commonOwner(ts) + val lubBase = intersectionType(lubParents, lubOwner) val lubType = - if (phase.erasedTypes || depth == 0) lubBase + if (phase.erasedTypes || depth == 0 ) lubBase else { val lubRefined = refinedType(lubParents, lubOwner) val lubThisType = lubRefined.typeSymbol.thisType @@ -6746,6 +6475,7 @@ trait Types extends api.Types { self: SymbolTable => val syms = narrowts map (t => t.nonPrivateMember(proto.name).suchThat(sym => sym.tpe matches prototp.substThis(lubThisType.typeSymbol, t))) + if (syms contains NoSymbol) NoSymbol else { val symtypes = @@ -6772,10 +6502,8 @@ trait Types extends api.Types { self: SymbolTable => // add a refinement symbol for all non-class members of lubBase // which are refined by every type in ts. for (sym <- lubBase.nonPrivateMembers ; if !excludeFromLub(sym)) { - try { - val lsym = lubsym(sym) - if (lsym != NoSymbol) addMember(lubThisType, lubRefined, lsym, depth) - } catch { + try lubsym(sym) andAlso (addMember(lubThisType, lubRefined, _, depth)) + catch { case ex: NoCommonType => } } @@ -6972,15 +6700,19 @@ trait Types extends api.Types { self: SymbolTable => } tvs.reverse } - /** Make each type var in this type use its original type for comparisons instead - * of collecting constraints. - */ - def suspendTypeVarsInType(tp: Type): List[TypeVar] = { - val tvs = typeVarsInType(tp) - // !!! Is it somehow guaranteed that this will not break under nesting? - // In general one has to save and restore the contents of the field... + + // If this type contains type variables, put them to sleep for a while. + // Don't just wipe them out by replacing them by the corresponding type + // parameter, as that messes up (e.g.) type variables in type refinements. + // Without this, the matchesType call would lead to type variables on both + // sides of a subtyping/equality judgement, which can lead to recursive types + // being constructed. See pos/t0851 for a situation where this happens. + @inline final def suspendingTypeVars[T](tvs: List[TypeVar])(op: => T): T = { + val saved = tvs map (_.suspended) tvs foreach (_.suspended = true) - tvs + + try op + finally foreach2(tvs, saved)(_.suspended = _) } /** Compute lub (if `variance == 1`) or glb (if `variance == -1`) of given list @@ -7019,18 +6751,16 @@ trait Types extends api.Types { self: SymbolTable => debuglog("transposed irregular matrix!?" +(tps, argss)) None case Some(argsst) => - val args = map2(sym.typeParams, argsst) { (tparam, as) => - if (depth == 0) { - if (tparam.variance == variance) { - // Take the intersection of the upper bounds of the type parameters - // rather than falling all the way back to "Any", otherwise we end up not - // conforming to bounds. - val bounds0 = sym.typeParams map (_.info.bounds.hi) filterNot (_.typeSymbol == AnyClass) - if (bounds0.isEmpty) AnyClass.tpe - else intersectionType(bounds0 map (b => b.asSeenFrom(tps.head, sym))) - } - else if (tparam.variance == -variance) NothingClass.tpe - else NoType + val args = map2(sym.typeParams, argsst) { (tparam, as0) => + val as = as0.distinct + if (as.size == 1) as.head + else if (depth == 0) { + log("Giving up merging args: can't unify %s under %s".format(as.mkString(", "), tparam.fullLocationString)) + // Don't return "Any" (or "Nothing") when we have to give up due to + // recursion depth. Return NoType, which prevents us from poisoning + // lublist's results. It can recognize the recursion and deal with it, but + // only if we aren't returning invalid types. + NoType } else { if (tparam.variance == variance) lub(as, decr(depth)) @@ -7039,7 +6769,7 @@ trait Types extends api.Types { self: SymbolTable => val l = lub(as, decr(depth)) val g = glb(as, decr(depth)) if (l <:< g) l - else { // Martin: I removed this, because incomplete. Not sure there is a good way to fix it. For the moment we + else { // Martin: I removed this, because incomplete. Not sure there is a good way to fix it. For the moment we // just err on the conservative side, i.e. with a bound that is too high. // if(!(tparam.info.bounds contains tparam)) //@M can't deal with f-bounds, see #2251 @@ -7087,6 +6817,14 @@ trait Types extends api.Types { self: SymbolTable => } } + def isJavaVarargsAncestor(clazz: Symbol) = ( + clazz.isClass + && clazz.isJavaDefined + && (clazz.info.nonPrivateDecls exists isJavaVarArgsMethod) + ) + def inheritsJavaVarArgsMethod(clazz: Symbol) = + clazz.thisType.baseClasses exists isJavaVarargsAncestor + /** All types in list must be polytypes with type parameter lists of * same length as tparams. * Returns list of list of bounds infos, where corresponding type @@ -7199,6 +6937,15 @@ trait Types extends api.Types { self: SymbolTable => else (ps :+ SerializableClass.tpe).toList ) + /** Members of the given class, other than those inherited + * from Any or AnyRef. + */ + def nonTrivialMembers(clazz: Symbol): Scope = clazz.info.members filterNot isUniversalMember + + /** Members which can be imported into other scopes. + */ + def importableMembers(pre: Type): Scope = pre.members filter isImportable + def objToAny(tp: Type): Type = if (!phase.erasedTypes && tp.typeSymbol == ObjectClass) AnyClass.tpe else tp @@ -7222,7 +6969,7 @@ trait Types extends api.Types { self: SymbolTable => protected def typeToString(tpe: Type): String = if (tostringRecursions >= maxTostringRecursions) { - debugwarn("Exceeded recursion depth attempting to print type.") + devWarning("Exceeded recursion depth attempting to print " + util.shortClassOfInstance(tpe)) if (settings.debug.value) (new Throwable).printStackTrace @@ -7292,7 +7039,6 @@ trait Types extends api.Types { self: SymbolTable => object TypesStats { import BaseTypeSeqsStats._ val rawTypeCount = Statistics.newCounter ("#raw type creations") - val asSeenFromCount = Statistics.newCounter ("#asSeenFrom ops") val subtypeCount = Statistics.newCounter ("#subtype ops") val sametypeCount = Statistics.newCounter ("#sametype ops") val lubCount = Statistics.newCounter ("#toplevel lubs/glbs") diff --git a/src/reflect/scala/reflect/internal/pickling/PickleBuffer.scala b/src/reflect/scala/reflect/internal/pickling/PickleBuffer.scala index 6170fcbb90..34c6fe234c 100644 --- a/src/reflect/scala/reflect/internal/pickling/PickleBuffer.scala +++ b/src/reflect/scala/reflect/internal/pickling/PickleBuffer.scala @@ -62,11 +62,8 @@ class PickleBuffer(data: Array[Byte], from: Int, to: Int) { writeByte((x & 0x7f).toInt) } - /** Write a natural number <code>x</code> at position <code>pos</code>. + /** Write a natural number `x` at position `pos`. * If number is more than one byte, shift rest of array to make space. - * - * @param pos ... - * @param x ... */ def patchNat(pos: Int, x: Int) { def patchNatPrefix(x: Int) { @@ -81,7 +78,7 @@ class PickleBuffer(data: Array[Byte], from: Int, to: Int) { if (y != 0) patchNatPrefix(y) } - /** Write a long number <code>x</code> in signed big endian format, base 256. + /** Write a long number `x` in signed big endian format, base 256. * * @param x The long number to be written. */ @@ -94,9 +91,6 @@ class PickleBuffer(data: Array[Byte], from: Int, to: Int) { // -- Basic input routines -------------------------------------------- - /** Peek at the current byte without moving the read index */ - def peekByte(): Int = bytes(readIndex) - /** Read a byte */ def readByte(): Int = { val x = bytes(readIndex); readIndex += 1; x @@ -151,18 +145,14 @@ class PickleBuffer(data: Array[Byte], from: Int, to: Int) { result.toIndexedSeq } - /** Perform operation <code>op</code> until the condition - * <code>readIndex == end</code> is satisfied. + /** Perform operation `op` until the condition + * `readIndex == end` is satisfied. * Concatenate results into a list. - * - * @param end ... - * @param op ... - * @return ... */ def until[T](end: Int, op: () => T): List[T] = if (readIndex == end) List() else op() :: until(end, op); - /** Perform operation <code>op</code> the number of + /** Perform operation `op` the number of * times specified. Concatenate the results into a list. */ def times[T](n: Int, op: ()=>T): List[T] = diff --git a/src/reflect/scala/reflect/internal/pickling/PickleFormat.scala b/src/reflect/scala/reflect/internal/pickling/PickleFormat.scala index 16747af08a..3722c77aa2 100644 --- a/src/reflect/scala/reflect/internal/pickling/PickleFormat.scala +++ b/src/reflect/scala/reflect/internal/pickling/PickleFormat.scala @@ -56,7 +56,7 @@ object PickleFormat { * | 42 ANNOTATEDtpe len_Nat [sym_Ref /* no longer needed */] tpe_Ref {annotinfo_Ref} * | 43 ANNOTINFO len_Nat AnnotInfoBody * | 44 ANNOTARGARRAY len_Nat {constAnnotArg_Ref} - * | 47 DEBRUIJNINDEXtpe len_Nat level_Nat index_Nat + * | 47 DEBRUIJNINDEXtpe len_Nat level_Nat index_Nat /* no longer needed */ * | 48 EXISTENTIALtpe len_Nat type_Ref {symbol_Ref} * | 49 TREE len_Nat 1 EMPTYtree * | 49 TREE len_Nat 2 PACKAGEtree type_Ref sym_Ref mods_Ref name_Ref {tree_Ref} @@ -115,7 +115,6 @@ object PickleFormat { */ val MajorVersion = 5 val MinorVersion = 0 - def VersionString = "V" + MajorVersion + "." + MinorVersion final val TERMname = 1 final val TYPEname = 2 @@ -161,7 +160,7 @@ object PickleFormat { final val ANNOTARGARRAY = 44 final val SUPERtpe = 46 - final val DEBRUIJNINDEXtpe = 47 + final val DEBRUIJNINDEXtpe = 47 // no longer generated final val EXISTENTIALtpe = 48 final val TREE = 49 // prefix code that means a tree is coming diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala index f3a5053a91..5a0454a569 100644 --- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala @@ -159,9 +159,9 @@ abstract class UnPickler { result } - /** If entry at <code>i</code> is undefined, define it by performing - * operation <code>op</code> with <code>readIndex at start of i'th - * entry. Restore <code>readIndex</code> afterwards. + /** If entry at `i` is undefined, define it by performing + * operation `op` with `readIndex at start of i'th + * entry. Restore `readIndex` afterwards. */ protected def at[T <: AnyRef](i: Int, op: () => T): T = { var r = entries(i) @@ -186,13 +186,12 @@ abstract class UnPickler { case _ => errorBadSignature("bad name tag: " + tag) } } - protected def readTermName(): TermName = readName().toTermName - protected def readTypeName(): TypeName = readName().toTypeName + private def readEnd() = readNat() + readIndex /** Read a symbol */ protected def readSymbol(): Symbol = { val tag = readByte() - val end = readNat() + readIndex + val end = readEnd() def atEnd = readIndex == end def readExtSymbol(): Symbol = { @@ -325,7 +324,7 @@ abstract class UnPickler { */ protected def readType(forceProperType: Boolean = false): Type = { val tag = readByte() - val end = readNat() + readIndex + val end = readEnd() (tag: @switch) match { case NOtpe => NoType @@ -344,7 +343,7 @@ abstract class UnPickler { case TYPEREFtpe => val pre = readTypeRef() val sym = readSymbolRef() - var args = until(end, readTypeRef) + val args = until(end, readTypeRef) TypeRef(pre, sym, args) case TYPEBOUNDStpe => TypeBounds(readTypeRef(), readTypeRef()) @@ -431,7 +430,7 @@ abstract class UnPickler { protected def readChildren() { val tag = readByte() assert(tag == CHILDREN) - val end = readNat() + readIndex + val end = readEnd() val target = readSymbolRef() while (readIndex != end) target addChild readSymbolRef() } @@ -450,7 +449,7 @@ abstract class UnPickler { */ private def readArrayAnnot() = { readByte() // skip the `annotargarray` tag - val end = readNat() + readIndex + val end = readEnd() until(end, () => readClassfileAnnotArg(readNat())).toArray(JavaArgumentTag) } protected def readClassfileAnnotArg(i: Int): ClassfileAnnotArg = bytes(index(i)) match { @@ -486,7 +485,7 @@ abstract class UnPickler { val tag = readByte() if (tag != SYMANNOT) errorBadSignature("symbol annotation expected ("+ tag +")") - val end = readNat() + readIndex + val end = readEnd() val target = readSymbolRef() target.addAnnotation(readAnnotationInfo(end)) } @@ -497,7 +496,7 @@ abstract class UnPickler { val tag = readByte() if (tag != ANNOTINFO) errorBadSignature("annotation expected (" + tag + ")") - val end = readNat() + readIndex + val end = readEnd() readAnnotationInfo(end) } @@ -506,7 +505,7 @@ abstract class UnPickler { val outerTag = readByte() if (outerTag != TREE) errorBadSignature("tree expected (" + outerTag + ")") - val end = readNat() + readIndex + val end = readEnd() val tag = readByte() val tpe = if (tag == EMPTYtree) NoType else readTypeRef() @@ -764,7 +763,8 @@ abstract class UnPickler { val tag = readNat() if (tag != MODIFIERS) errorBadSignature("expected a modifiers tag (" + tag + ")") - val end = readNat() + readIndex + + readEnd() val pflagsHi = readNat() val pflagsLo = readNat() val pflags = (pflagsHi.toLong << 32) + pflagsLo @@ -796,7 +796,6 @@ abstract class UnPickler { protected def readTreeRef(): Tree = at(readNat(), readTree) protected def readTypeNameRef(): TypeName = readNameRef().toTypeName - protected def readTermNameRef(): TermName = readNameRef().toTermName protected def readTemplateRef(): Template = readTreeRef() match { @@ -843,7 +842,6 @@ abstract class UnPickler { * error reporting, so we rely on the typechecker to report the error). */ def toTypeError(e: MissingRequirementError) = { - // e.printStackTrace() new TypeError(e.msg) } @@ -853,7 +851,7 @@ abstract class UnPickler { private val p = phase override def complete(sym: Symbol) : Unit = try { val tp = at(i, () => readType(sym.isTerm)) // after NMT_TRANSITION, revert `() => readType(sym.isTerm)` to `readType` - atPhase(p) (sym setInfo tp) + enteringPhase(p) (sym setInfo tp) if (currentRunId != definedAtRunId) sym.setInfo(adaptToNewRunMap(tp)) } @@ -871,7 +869,7 @@ abstract class UnPickler { super.complete(sym) var alias = at(j, readSymbol) if (alias.isOverloaded) - alias = atPhase(picklerPhase)((alias suchThat (alt => sym.tpe =:= sym.owner.thisType.memberType(alt)))) + alias = enteringPhase(picklerPhase)((alias suchThat (alt => sym.tpe =:= sym.owner.thisType.memberType(alt)))) sym.asInstanceOf[TermSymbol].setAlias(alias) } diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala index 81368df7a6..81ed63bfc6 100644 --- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala +++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala @@ -47,4 +47,5 @@ abstract class MutableSettings extends AbsSettings { def XoldPatmat: BooleanSetting def XnoPatmatAnalysis: BooleanSetting def XfullLubs: BooleanSetting + def breakCycles: BooleanSetting } diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala index 52d1657dc3..59bf51d638 100644 --- a/src/reflect/scala/reflect/internal/transform/Erasure.scala +++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala @@ -69,7 +69,7 @@ trait Erasure { // // This requires that cls.isClass. protected def rebindInnerClass(pre: Type, cls: Symbol): Type = { - if (cls.owner.isClass) cls.owner.tpe else pre // why not cls.isNestedClass? + if (cls.owner.isClass) cls.owner.tpe_* else pre // why not cls.isNestedClass? } def unboxDerivedValueClassMethod(clazz: Symbol): Symbol = @@ -233,7 +233,7 @@ trait Erasure { // It seems there is a deeper problem here, which needs // following up to. But we will not risk regressions // in 2.10 because of it. - log(s"!!! unexpected constructor erasure $tp for $clazz") + devWarning(s"unexpected constructor erasure $tp for $clazz") specialScalaErasure(tp) } } diff --git a/src/reflect/scala/reflect/internal/util/Collections.scala b/src/reflect/scala/reflect/internal/util/Collections.scala index 2ba15e0776..0d644aa73e 100644 --- a/src/reflect/scala/reflect/internal/util/Collections.scala +++ b/src/reflect/scala/reflect/internal/util/Collections.scala @@ -40,8 +40,6 @@ trait Collections { mforeach(xss)(x => if ((res eq null) && p(x)) res = Some(x)) if (res eq null) None else res } - final def mfilter[A](xss: List[List[A]])(p: A => Boolean) = - for (xs <- xss; x <- xs; if p(x)) yield x final def map2[A, B, C](xs1: List[A], xs2: List[B])(f: (A, B) => C): List[C] = { val lb = new ListBuffer[C] @@ -78,19 +76,6 @@ trait Collections { lb.toList } - final def distinctBy[A, B](xs: List[A])(f: A => B): List[A] = { - val buf = new ListBuffer[A] - val seen = mutable.Set[B]() - xs foreach { x => - val y = f(x) - if (!seen(y)) { - buf += x - seen += y - } - } - buf.toList - } - @tailrec final def flattensToEmpty(xss: Seq[Seq[_]]): Boolean = { xss.isEmpty || xss.head.isEmpty && flattensToEmpty(xss.tail) } @@ -189,18 +174,6 @@ trait Collections { } false } - final def forall2[A, B](xs1: List[A], xs2: List[B])(f: (A, B) => Boolean): Boolean = { - var ys1 = xs1 - var ys2 = xs2 - while (!ys1.isEmpty && !ys2.isEmpty) { - if (!f(ys1.head, ys2.head)) - return false - - ys1 = ys1.tail - ys2 = ys2.tail - } - true - } final def forall3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C])(f: (A, B, C) => Boolean): Boolean = { var ys1 = xs1 var ys2 = xs2 @@ -222,6 +195,3 @@ trait Collections { case _: IllegalArgumentException => None } } - -object Collections extends Collections { } - diff --git a/src/reflect/scala/reflect/internal/util/HashSet.scala b/src/reflect/scala/reflect/internal/util/HashSet.scala index 4135f3c469..74b6a54c6e 100644 --- a/src/reflect/scala/reflect/internal/util/HashSet.scala +++ b/src/reflect/scala/reflect/internal/util/HashSet.scala @@ -6,8 +6,6 @@ package scala.reflect.internal.util object HashSet { - def apply[T >: Null <: AnyRef](): HashSet[T] = this(16) - def apply[T >: Null <: AnyRef](label: String): HashSet[T] = this(label, 16) def apply[T >: Null <: AnyRef](initialCapacity: Int): HashSet[T] = this("No Label", initialCapacity) def apply[T >: Null <: AnyRef](label: String, initialCapacity: Int): HashSet[T] = new HashSet[T](label, initialCapacity) diff --git a/src/reflect/scala/reflect/internal/util/Origins.scala b/src/reflect/scala/reflect/internal/util/Origins.scala index 3259a12163..a2b9e24ebc 100644 --- a/src/reflect/scala/reflect/internal/util/Origins.scala +++ b/src/reflect/scala/reflect/internal/util/Origins.scala @@ -6,9 +6,7 @@ package scala.reflect package internal.util -import NameTransformer._ import scala.collection.{ mutable, immutable } -import Origins._ /** A debugging class for logging from whence a method is being called. * Say you wanted to discover who was calling phase_= in SymbolTable. diff --git a/src/reflect/scala/reflect/internal/util/Position.scala b/src/reflect/scala/reflect/internal/util/Position.scala index 0725e9775b..bbc95feaab 100644 --- a/src/reflect/scala/reflect/internal/util/Position.scala +++ b/src/reflect/scala/reflect/internal/util/Position.scala @@ -128,7 +128,7 @@ abstract class Position extends scala.reflect.api.Position { self => def endOrPoint: Int = point @deprecated("use point instead", "2.9.0") - def offset: Option[Int] = if (isDefined) Some(point) else None + def offset: Option[Int] = if (isDefined) Some(point) else None // used by sbt /** The same position with a different start value (if a range) */ def withStart(off: Int): Position = this diff --git a/src/reflect/scala/reflect/internal/util/Set.scala b/src/reflect/scala/reflect/internal/util/Set.scala index 36bdb8174a..57e5e0c0b9 100644 --- a/src/reflect/scala/reflect/internal/util/Set.scala +++ b/src/reflect/scala/reflect/internal/util/Set.scala @@ -18,8 +18,6 @@ abstract class Set[T <: AnyRef] { def apply(x: T): Boolean = contains(x) - @deprecated("use `iterator` instead", "2.9.0") def elements = iterator - def contains(x: T): Boolean = findEntry(x) ne null diff --git a/src/reflect/scala/reflect/internal/util/SourceFile.scala b/src/reflect/scala/reflect/internal/util/SourceFile.scala index bc2d0ee4db..dd2a6e21f1 100644 --- a/src/reflect/scala/reflect/internal/util/SourceFile.scala +++ b/src/reflect/scala/reflect/internal/util/SourceFile.scala @@ -24,7 +24,6 @@ abstract class SourceFile { assert(offset < length, file + ": " + offset + " >= " + length) new OffsetPosition(this, offset) } - def position(line: Int, column: Int) : Position = new OffsetPosition(this, lineToOffset(line) + column) def offsetToLine(offset: Int): Int def lineToOffset(index : Int): Int @@ -37,9 +36,6 @@ abstract class SourceFile { def dbg(offset: Int) = (new OffsetPosition(this, offset)).dbgString def path = file.path - def beginsWith(offset: Int, text: String): Boolean = - (content drop offset) startsWith text - def lineToString(index: Int): String = content drop lineToOffset(index) takeWhile (c => !isLineBreakChar(c.toChar)) mkString "" @@ -81,7 +77,6 @@ object ScriptSourceFile { } else 0 } - def stripHeader(cs: Array[Char]): Array[Char] = cs drop headerLength(cs) def apply(file: AbstractFile, content: Array[Char]) = { val underlying = new BatchSourceFile(file, content) @@ -91,7 +86,6 @@ object ScriptSourceFile { stripped } } -import ScriptSourceFile._ class ScriptSourceFile(underlying: BatchSourceFile, content: Array[Char], override val start: Int) extends BatchSourceFile(underlying.file, content) { override def isSelfContained = false diff --git a/src/reflect/scala/reflect/internal/util/Statistics.scala b/src/reflect/scala/reflect/internal/util/Statistics.scala index 2c90d2d525..b078b7d4f9 100644 --- a/src/reflect/scala/reflect/internal/util/Statistics.scala +++ b/src/reflect/scala/reflect/internal/util/Statistics.scala @@ -257,7 +257,6 @@ quant) def enabled = _enabled def enabled_=(cond: Boolean) = { if (cond && !_enabled) { - val test = new Timer("", Nil) val start = System.nanoTime() var total = 0L for (i <- 1 to 10000) { diff --git a/src/reflect/scala/reflect/internal/util/StringOps.scala b/src/reflect/scala/reflect/internal/util/StringOps.scala index 8f6c409e0b..93bbfdd273 100644 --- a/src/reflect/scala/reflect/internal/util/StringOps.scala +++ b/src/reflect/scala/reflect/internal/util/StringOps.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ - package scala.reflect.internal.util /** This object provides utility methods to extract elements @@ -16,22 +15,14 @@ package scala.reflect.internal.util * @version 1.0 */ trait StringOps { - def onull(s: String) = if (s == null) "" else s - def oempty(xs: String*) = xs filterNot (x => x == null || x == "") - def ojoin(xs: String*): String = oempty(xs: _*) mkString " " - def ojoin(xs: Seq[String], sep: String): String = oempty(xs: _*) mkString sep - def ojoinOr(xs: Seq[String], sep: String, orElse: String) = { - val ys = oempty(xs: _*) - if (ys.isEmpty) orElse else ys mkString sep - } - def trimTrailingSpace(s: String) = { - if (s.length == 0 || !s.charAt(s.length - 1).isWhitespace) s - else { - var idx = s.length - 1 - while (idx >= 0 && s.charAt(idx).isWhitespace) - idx -= 1 - - s.substring(0, idx + 1) + def oempty(xs: String*) = xs filterNot (x => x == null || x == "") + def ojoin(xs: String*): String = oempty(xs: _*) mkString " " + def longestCommonPrefix(xs: List[String]): String = { + if (xs.isEmpty || xs.contains("")) "" + else xs.head.head match { + case ch => + if (xs.tail forall (_.head == ch)) "" + ch + longestCommonPrefix(xs map (_.tail)) + else "" } } @@ -49,14 +40,6 @@ trait StringOps { def words(str: String): List[String] = decompose(str, ' ') - def stripPrefixOpt(str: String, prefix: String): Option[String] = - if (str startsWith prefix) Some(str drop prefix.length) - else None - - def stripSuffixOpt(str: String, suffix: String): Option[String] = - if (str endsWith suffix) Some(str dropRight suffix.length) - else None - def splitWhere(str: String, f: Char => Boolean, doDropIndex: Boolean = false): Option[(String, String)] = splitAt(str, str indexWhere f, doDropIndex) @@ -65,10 +48,6 @@ trait StringOps { else Some((str take idx, str drop (if (doDropIndex) idx + 1 else idx))) /** Returns a string meaning "n elements". - * - * @param n ... - * @param elements ... - * @return ... */ def countElementsAsString(n: Int, elements: String): String = n match { @@ -81,9 +60,6 @@ trait StringOps { } /** Turns a count into a friendly English description if n<=4. - * - * @param n ... - * @return ... */ def countAsString(n: Int): String = n match { diff --git a/src/reflect/scala/reflect/internal/util/TableDef.scala b/src/reflect/scala/reflect/internal/util/TableDef.scala index 8e2bcc2ff7..04ecfe8d76 100644 --- a/src/reflect/scala/reflect/internal/util/TableDef.scala +++ b/src/reflect/scala/reflect/internal/util/TableDef.scala @@ -67,12 +67,6 @@ class TableDef[T](_cols: Column[T]*) { override def toString = allToSeq mkString "\n" } - def formatterFor(rows: Seq[T]): T => String = { - val formatStr = new Table(rows).rowFormat - - x => formatStr.format(colApply(x) : _*) - } - def table(rows: Seq[T]) = new Table(rows) override def toString = cols.mkString("TableDef(", ", ", ")") diff --git a/src/reflect/scala/reflect/internal/util/TraceSymbolActivity.scala b/src/reflect/scala/reflect/internal/util/TraceSymbolActivity.scala index fa83f70f3a..632890d600 100644 --- a/src/reflect/scala/reflect/internal/util/TraceSymbolActivity.scala +++ b/src/reflect/scala/reflect/internal/util/TraceSymbolActivity.scala @@ -12,13 +12,9 @@ trait TraceSymbolActivity { if (enabled && global.isCompilerUniverse) scala.sys addShutdownHook showAllSymbols() - private type Set[T] = scala.collection.immutable.Set[T] - private val Set = scala.collection.immutable.Set - val allSymbols = mutable.Map[Int, Symbol]() val allChildren = mutable.Map[Int, List[Int]]() withDefaultValue Nil val prevOwners = mutable.Map[Int, List[(Int, Phase)]]() withDefaultValue Nil - val symsCaused = mutable.Map[Int, Int]() withDefaultValue 0 val allTrees = mutable.Set[Tree]() def recordSymbolsInTree(tree: Tree) { @@ -44,38 +40,6 @@ trait TraceSymbolActivity { } } - /** TODO. - */ - private def reachableDirectlyFromSymbol(sym: Symbol): List[Symbol] = ( - List(sym.owner, sym.alias, sym.thisSym) - ++ sym.children - ++ sym.info.parents.map(_.typeSymbol) - ++ sym.typeParams - ++ sym.paramss.flatten - ) - private def reachable[T](inputs: Traversable[T], mkSymbol: T => Symbol): Set[Symbol] = { - def loop(seen: Set[Symbol], remaining: List[Symbol]): Set[Symbol] = { - remaining match { - case Nil => seen - case head :: rest => - if ((head eq null) || (head eq NoSymbol) || seen(head)) loop(seen, rest) - else loop(seen + head, rest ++ reachableDirectlyFromSymbol(head).filterNot(seen)) - } - } - loop(immutable.Set(), inputs.toList map mkSymbol filterNot (_ eq null) distinct) - } - private def treeList(t: Tree) = { - val buf = mutable.ListBuffer[Tree]() - t foreach (buf += _) - buf.toList - } - - private def reachableFromSymbol(root: Symbol): Set[Symbol] = - reachable[Symbol](List(root, root.info.typeSymbol), x => x) - - private def reachableFromTree(tree: Tree): Set[Symbol] = - reachable[Tree](treeList(tree), _.symbol) - private def signature(id: Int) = runBeforeErasure(allSymbols(id).defString) private def dashes(s: Any): String = ("" + s) map (_ => '-') @@ -119,7 +83,7 @@ trait TraceSymbolActivity { } println("\n") } - private def showFreq[T, U](xs: Traversable[T])(groupFn: T => U, showFn: U => String = (x: U) => "" + x) = { + private def showFreq[T, U](xs: Traversable[T])(groupFn: T => U, showFn: U => String) = { showMapFreq(xs.toList groupBy groupFn)(showFn) } private lazy val findErasurePhase: Phase = { @@ -129,7 +93,7 @@ trait TraceSymbolActivity { } ph } - private def runBeforeErasure[T](body: => T): T = atPhase(findErasurePhase)(body) + private def runBeforeErasure[T](body: => T): T = enteringPhase(findErasurePhase)(body) def showAllSymbols() { if (!enabled) return diff --git a/src/reflect/scala/reflect/internal/util/WeakHashSet.scala b/src/reflect/scala/reflect/internal/util/WeakHashSet.scala index 9882aad5e5..41e74f80e9 100644 --- a/src/reflect/scala/reflect/internal/util/WeakHashSet.scala +++ b/src/reflect/scala/reflect/internal/util/WeakHashSet.scala @@ -1,9 +1,6 @@ package scala.reflect.internal.util import scala.collection.mutable -import scala.collection.mutable.ArrayBuffer -import scala.collection.mutable.Builder -import scala.collection.mutable.SetBuilder import scala.collection.generic.Clearable import scala.runtime.AbstractFunction1 diff --git a/src/reflect/scala/reflect/internal/util/package.scala b/src/reflect/scala/reflect/internal/util/package.scala index 6d77235db6..1ca57b81ed 100644 --- a/src/reflect/scala/reflect/internal/util/package.scala +++ b/src/reflect/scala/reflect/internal/util/package.scala @@ -1,7 +1,36 @@ -package scala.reflect +package scala +package reflect package internal package object util { + import StringOps.longestCommonPrefix + + // Shorten a name like Symbols$FooSymbol to FooSymbol. + private def shortenName(name: String): String = { + if (name == "") return "" + val segments = (name split '$').toList + val last = segments.last + + if (last.length == 0) + segments takeRight 2 mkString "$" + else + last + } + + def shortClassOfInstance(x: AnyRef): String = shortClass(x.getClass) + def shortClass(clazz: Class[_]): String = { + val name: String = (clazz.getName split '.').last + def isModule = name endsWith "$" // object + def isAnon = (name split '$').last forall (_.isDigit) // anonymous class + + if (isModule) + (name split '$' filterNot (_ == "")).last + "$" + else if (isAnon) { + val parents = clazz.getSuperclass :: clazz.getInterfaces.toList + parents map (c => shortClass(c)) mkString " with " + } + else shortenName(name) + } /** * Adds the `sm` String interpolator to a [[scala.StringContext]]. */ diff --git a/src/reflect/scala/reflect/io/AbstractFile.scala b/src/reflect/scala/reflect/io/AbstractFile.scala index 15befb67f1..1a8d1c4f5e 100644 --- a/src/reflect/scala/reflect/io/AbstractFile.scala +++ b/src/reflect/scala/reflect/io/AbstractFile.scala @@ -14,9 +14,9 @@ import scala.collection.mutable.ArrayBuffer /** * An abstraction over files for use in the reflection/compiler libraries. - * + * * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' - * + * * @author Philippe Altherr * @version 1.0, 23/03/2004 */ @@ -27,7 +27,7 @@ object AbstractFile { /** * If the specified File exists and is a regular file, returns an - * abstract regular file backed by it. Otherwise, returns <code>null</code>. + * abstract regular file backed by it. Otherwise, returns `null`. */ def getFile(file: File): AbstractFile = if (file.isFile) new PlainFile(file) else null @@ -38,10 +38,7 @@ object AbstractFile { /** * If the specified File exists and is either a directory or a * readable zip or jar archive, returns an abstract directory - * backed by it. Otherwise, returns <code>null</code>. - * - * @param file ... - * @return ... + * backed by it. Otherwise, returns `null`. */ def getDirectory(file: File): AbstractFile = if (file.isDirectory) new PlainFile(file) @@ -51,10 +48,7 @@ object AbstractFile { /** * If the specified URL exists and is a readable zip or jar archive, * returns an abstract directory backed by it. Otherwise, returns - * <code>null</code>. - * - * @param file ... - * @return ... + * `null`. */ def getURL(url: URL): AbstractFile = { if (url == null || !Path.isExtensionJarOrZip(url.getPath)) null @@ -80,12 +74,12 @@ object AbstractFile { * </p> * <p> * The interface does <b>not</b> allow to access the content. - * The class <code>symtab.classfile.AbstractFileReader</code> accesses + * The class `symtab.classfile.AbstractFileReader` accesses * bytes, knowing that the character set of classfiles is UTF-8. For - * all other cases, the class <code>SourceFile</code> is used, which honors - * <code>global.settings.encoding.value</code>. + * all other cases, the class `SourceFile` is used, which honors + * `global.settings.encoding.value`. * </p> - * + * * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ abstract class AbstractFile extends Iterable[AbstractFile] { @@ -148,7 +142,7 @@ abstract class AbstractFile extends Iterable[AbstractFile] { def toURL: URL = if (file == null) null else file.toURI.toURL /** Returns contents of file (if applicable) in a Char array. - * warning: use <code>Global.getSourceFile()</code> to use the proper + * warning: use `Global.getSourceFile()` to use the proper * encoding when converting to the char array. */ @throws(classOf[IOException]) @@ -175,8 +169,8 @@ abstract class AbstractFile extends Iterable[AbstractFile] { def iterator: Iterator[AbstractFile] /** Returns the abstract file in this abstract directory with the specified - * name. If there is no such file, returns <code>null</code>. The argument - * <code>directory</code> tells whether to look for a directory or + * name. If there is no such file, returns `null`. The argument + * `directory` tells whether to look for a directory or * a regular file. */ def lookupName(name: String, directory: Boolean): AbstractFile @@ -186,19 +180,6 @@ abstract class AbstractFile extends Iterable[AbstractFile] { */ def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile - /** Returns the abstract file in this abstract directory with the specified - * path relative to it, If there is no such file, returns null. The argument - * <code>directory</code> tells whether to look for a directory or a regular - * file. - * - * @param path ... - * @param directory ... - * @return ... - */ - def lookupPath(path: String, directory: Boolean): AbstractFile = { - lookup((f, p, dir) => f.lookupName(p, dir), path, directory) - } - /** Return an abstract file that does not check that `path` denotes * an existing file. */ diff --git a/src/reflect/scala/reflect/io/Directory.scala b/src/reflect/scala/reflect/io/Directory.scala index c040d1eac5..4bf9ed8a36 100644 --- a/src/reflect/scala/reflect/io/Directory.scala +++ b/src/reflect/scala/reflect/io/Directory.scala @@ -14,12 +14,10 @@ import java.io.{ File => JFile } * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ object Directory { - import scala.util.Properties.{ tmpDir, userHome, userDir } + import scala.util.Properties.{ userHome, userDir } private def normalizePath(s: String) = Some(apply(Path(s).normalize)) def Current: Option[Directory] = if (userDir == "") None else normalizePath(userDir) - def Home: Option[Directory] = if (userHome == "") None else normalizePath(userHome) - def TmpDir: Option[Directory] = if (tmpDir == "") None else normalizePath(tmpDir) def apply(path: Path): Directory = path.toDirectory @@ -30,20 +28,18 @@ object Directory { path.createDirectory() } } -import Path._ /** An abstraction for directories. * * @author Paul Phillips * @since 2.8 - * + * * ''Note: This is library is considered experimental and should not be used unless you know what you are doing.'' */ class Directory(jfile: JFile) extends Path(jfile) { override def toAbsolute: Directory = if (isAbsolute) this else super.toAbsolute.toDirectory override def toDirectory: Directory = this override def toFile: File = new File(jfile) - override def isValid = jfile.isDirectory() || !jfile.exists() override def normalize: Directory = super.normalize.toDirectory /** An iterator over the contents of this directory. @@ -60,7 +56,6 @@ class Directory(jfile: JFile) extends Path(jfile) { override def walkFilter(cond: Path => Boolean): Iterator[Path] = list filter cond flatMap (_ walkFilter cond) - def deepDirs: Iterator[Directory] = Path.onlyDirs(deepList()) def deepFiles: Iterator[File] = Path.onlyFiles(deepList()) /** If optional depth argument is not given, will recurse @@ -70,10 +65,4 @@ class Directory(jfile: JFile) extends Path(jfile) { if (depth < 0) list ++ (dirs flatMap (_ deepList (depth))) else if (depth == 0) Iterator.empty else list ++ (dirs flatMap (_ deepList (depth - 1))) - - /** An iterator over the directories underneath this directory, - * to the (optionally) given depth. - */ - def subdirs(depth: Int = 1): Iterator[Directory] = - deepList(depth) collect { case x: Directory => x } } diff --git a/src/reflect/scala/reflect/io/File.scala b/src/reflect/scala/reflect/io/File.scala index 736ba5d51e..c74dc06501 100644 --- a/src/reflect/scala/reflect/io/File.scala +++ b/src/reflect/scala/reflect/io/File.scala @@ -22,8 +22,7 @@ import scala.language.{reflectiveCalls, implicitConversions} */ object File { def pathSeparator = java.io.File.pathSeparator - def separator = java.io.File.separator - + def separator = java.io.File.separator def apply(path: Path)(implicit codec: Codec) = new File(path.jfile)(codec) // Create a temporary file, which will be deleted upon jvm exit. @@ -32,41 +31,7 @@ object File { jfile.deleteOnExit() apply(jfile) } - - type HasClose = { def close(): Unit } - - def closeQuietly(target: HasClose) { - try target.close() catch { case e: IOException => } - } - def closeQuietly(target: JCloseable) { - try target.close() catch { case e: IOException => } - } - - // this is a workaround for http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6503430 - // we are using a static initializer to statically initialize a java class so we don't - // trigger java.lang.InternalErrors later when using it concurrently. We ignore all - // the exceptions so as not to cause spurious failures when no write access is available, - // e.g. google app engine. - // - // XXX need to put this behind a setting. - // - // try { - // import Streamable.closing - // val tmp = java.io.File.createTempFile("bug6503430", null, null) - // try closing(new FileInputStream(tmp)) { in => - // val inc = in.getChannel() - // closing(new FileOutputStream(tmp, true)) { out => - // out.getChannel().transferFrom(inc, 0, 0) - // } - // } - // finally tmp.delete() - // } - // catch { - // case _: IllegalArgumentException | _: IllegalStateException | _: IOException | _: SecurityException => () - // } } -import File._ -import Path._ /** An abstraction for files. For character data, a Codec * can be supplied at either creation time or when a method @@ -76,19 +41,17 @@ import Path._ * * @author Paul Phillips * @since 2.8 - * + * * ''Note: This is library is considered experimental and should not be used unless you know what you are doing.'' */ class File(jfile: JFile)(implicit constructorCodec: Codec) extends Path(jfile) with Streamable.Chars { override val creationCodec = constructorCodec - def withCodec(codec: Codec): File = new File(jfile)(codec) override def addExtension(ext: String): File = super.addExtension(ext).toFile override def toAbsolute: File = if (isAbsolute) this else super.toAbsolute.toFile override def toDirectory: Directory = new Directory(jfile) override def toFile: File = this override def normalize: File = super.normalize.toFile - override def isValid = jfile.isFile() || !jfile.exists() override def length = super[Path].length override def walkFilter(cond: Path => Boolean): Iterator[Path] = if (cond(this)) Iterator.single(this) else Iterator.empty @@ -99,14 +62,11 @@ class File(jfile: JFile)(implicit constructorCodec: Codec) extends Path(jfile) w /** Obtains a OutputStream. */ def outputStream(append: Boolean = false) = new FileOutputStream(jfile, append) def bufferedOutput(append: Boolean = false) = new BufferedOutputStream(outputStream(append)) - def printStream(append: Boolean = false) = new PrintStream(outputStream(append), true) /** Obtains an OutputStreamWriter wrapped around a FileOutputStream. * This should behave like a less broken version of java.io.FileWriter, * in that unlike the java version you can specify the encoding. */ - def writer(): OutputStreamWriter = writer(false) - def writer(append: Boolean): OutputStreamWriter = writer(append, creationCodec) def writer(append: Boolean, codec: Codec): OutputStreamWriter = new OutputStreamWriter(outputStream(append), codec.charSet) @@ -118,7 +78,6 @@ class File(jfile: JFile)(implicit constructorCodec: Codec) extends Path(jfile) w new BufferedWriter(writer(append, codec)) def printWriter(): PrintWriter = new PrintWriter(bufferedWriter(), true) - def printWriter(append: Boolean): PrintWriter = new PrintWriter(bufferedWriter(append), true) /** Creates a new file and writes all the Strings to it. */ def writeAll(strings: String*): Unit = { @@ -127,12 +86,6 @@ class File(jfile: JFile)(implicit constructorCodec: Codec) extends Path(jfile) w finally out.close() } - def writeBytes(bytes: Array[Byte]): Unit = { - val out = bufferedOutput() - try out write bytes - finally out.close() - } - def appendAll(strings: String*): Unit = { val out = bufferedWriter(append = true) try strings foreach (out write _) @@ -150,39 +103,6 @@ class File(jfile: JFile)(implicit constructorCodec: Codec) extends Path(jfile) w try Some(slurp()) catch { case _: IOException => None } - def copyTo(destPath: Path, preserveFileDate: Boolean = false): Boolean = { - val CHUNK = 1024 * 1024 * 16 // 16 MB - val dest = destPath.toFile - if (!isValid) fail("Source %s is not a valid file." format name) - if (this.normalize == dest.normalize) fail("Source and destination are the same.") - if (!dest.parent.exists) fail("Destination cannot be created.") - if (dest.exists && !dest.canWrite) fail("Destination exists but is not writable.") - if (dest.isDirectory) fail("Destination exists but is a directory.") - - lazy val in_s = inputStream() - lazy val out_s = dest.outputStream() - lazy val in = in_s.getChannel() - lazy val out = out_s.getChannel() - - try { - val size = in.size() - var pos, count = 0L - while (pos < size) { - count = (size - pos) min CHUNK - pos += out.transferFrom(in, pos, count) - } - } - finally List[HasClose](out, out_s, in, in_s) foreach closeQuietly - - if (this.length != dest.length) - fail("Failed to completely copy %s to %s".format(name, dest.name)) - - if (preserveFileDate) - dest.lastModified = this.lastModified - - true - } - /** Reflection since we're into the java 6+ API. */ def setExecutable(executable: Boolean, ownerOnly: Boolean = true): Boolean = { diff --git a/src/reflect/scala/reflect/io/Path.scala b/src/reflect/scala/reflect/io/Path.scala index 36fdc04db4..3b5d3079cd 100644 --- a/src/reflect/scala/reflect/io/Path.scala +++ b/src/reflect/scala/reflect/io/Path.scala @@ -27,7 +27,7 @@ import scala.language.implicitConversions * * @author Paul Phillips * @since 2.8 - * + * * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ object Path { @@ -49,27 +49,12 @@ object Path { implicit def string2path(s: String): Path = apply(s) implicit def jfile2path(jfile: JFile): Path = apply(jfile) - // java 7 style, we don't use it yet - // object AccessMode extends Enumeration { - // val EXECUTE, READ, WRITE = Value - // } - // def checkAccess(modes: AccessMode*): Boolean = { - // modes foreach { - // case EXECUTE => throw new Exception("Unsupported") // can't check in java 5 - // case READ => if (!jfile.canRead()) return false - // case WRITE => if (!jfile.canWrite()) return false - // } - // true - // } - def onlyDirs(xs: Iterator[Path]): Iterator[Directory] = xs filter (_.isDirectory) map (_.toDirectory) def onlyDirs(xs: List[Path]): List[Directory] = xs filter (_.isDirectory) map (_.toDirectory) def onlyFiles(xs: Iterator[Path]): Iterator[File] = xs filter (_.isFile) map (_.toFile) - def onlyFiles(xs: List[Path]): List[File] = xs filter (_.isFile) map (_.toFile) def roots: List[Path] = java.io.File.listRoots().toList map Path.apply - def apply(segments: Seq[String]): Path = apply(segments mkString java.io.File.separator) def apply(path: String): Path = apply(new JFile(path)) def apply(jfile: JFile): Path = if (jfile.isFile) new File(jfile) @@ -84,19 +69,13 @@ import Path._ /** The Path constructor is private so we can enforce some * semantics regarding how a Path might relate to the world. - * + * * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ class Path private[io] (val jfile: JFile) { val separator = java.io.File.separatorChar val separatorStr = java.io.File.separator - // Validation: this verifies that the type of this object and the - // contents of the filesystem are in agreement. All objects are - // valid except File objects whose path points to a directory and - // Directory objects whose path points to a file. - def isValid: Boolean = true - // conversions def toFile: File = new File(jfile) def toDirectory: Directory = new Directory(jfile) @@ -104,6 +83,7 @@ class Path private[io] (val jfile: JFile) { def toCanonical: Path = Path(jfile.getCanonicalPath()) def toURI: URI = jfile.toURI() def toURL: URL = toURI.toURL() + /** If this path is absolute, returns it: otherwise, returns an absolute * path made up of root / this. */ @@ -136,7 +116,6 @@ class Path private[io] (val jfile: JFile) { def name: String = jfile.getName() def path: String = jfile.getPath() def normalize: Path = Path(jfile.getAbsolutePath()) - def isRootPath: Boolean = roots exists (_ isSame this) def resolve(other: Path) = if (other.isAbsolute || isEmpty) other else /(other) def relativize(other: Path) = { @@ -152,9 +131,8 @@ class Path private[io] (val jfile: JFile) { Path(createRelativePath(segments, other.segments)) } - // derived from identity - def root: Option[Path] = roots find (this startsWith _) def segments: List[String] = (path split separator).toList filterNot (_.length == 0) + /** * @return The path of the parent directory, or root if path is already root */ @@ -185,10 +163,6 @@ class Path private[io] (val jfile: JFile) { if (i < 0) "" else name.substring(i + 1) } - // def extension: String = (name lastIndexOf '.') match { - // case -1 => "" - // case idx => name drop (idx + 1) - // } // compares against extensions in a CASE INSENSITIVE way. def hasExtension(ext: String, exts: String*) = { val lower = extension.toLowerCase @@ -213,22 +187,18 @@ class Path private[io] (val jfile: JFile) { def canRead = jfile.canRead() def canWrite = jfile.canWrite() def exists = jfile.exists() - def notExists = try !jfile.exists() catch { case ex: SecurityException => false } def isFile = jfile.isFile() def isDirectory = jfile.isDirectory() def isAbsolute = jfile.isAbsolute() - def isHidden = jfile.isHidden() def isEmpty = path.length == 0 // Information def lastModified = jfile.lastModified() - def lastModified_=(time: Long) = jfile setLastModified time // should use setXXX function? def length = jfile.length() // Boolean path comparisons def endsWith(other: Path) = segments endsWith other.segments - def startsWith(other: Path) = segments startsWith other.segments def isSame(other: Path) = toCanonical == other.toCanonical def isFresher(other: Path) = lastModified > other.lastModified @@ -248,7 +218,6 @@ class Path private[io] (val jfile: JFile) { // deletions def delete() = jfile.delete() - def deleteIfExists() = if (jfile.exists()) delete() else false /** Deletes the path recursively. Returns false on failure. * Use with caution! @@ -270,16 +239,6 @@ class Path private[io] (val jfile: JFile) { length == 0 } - def touch(modTime: Long = System.currentTimeMillis) = { - createFile() - if (isFile) - lastModified = modTime - } - - // todo - // def copyTo(target: Path, options ...): Boolean - // def moveTo(target: Path, options ...): Boolean - override def toString() = path override def equals(other: Any) = other match { case x: Path => path == x.path diff --git a/src/reflect/scala/reflect/io/PlainFile.scala b/src/reflect/scala/reflect/io/PlainFile.scala index 82b0568657..0d4d55bdec 100644 --- a/src/reflect/scala/reflect/io/PlainFile.scala +++ b/src/reflect/scala/reflect/io/PlainFile.scala @@ -3,23 +3,11 @@ * @author Martin Odersky */ - package scala.reflect package io import java.io.{ FileInputStream, FileOutputStream, IOException } -import PartialFunction._ -/** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ -object PlainFile { - /** - * If the specified File exists, returns an abstract file backed - * by it. Otherwise, returns null. - */ - def fromPath(file: Path): PlainFile = - if (file.isDirectory) new PlainDirectory(file.toDirectory) - else if (file.isFile) new PlainFile(file) - else null -} + /** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ class PlainDirectory(givenPath: Directory) extends PlainFile(givenPath) { override def isDirectory = true @@ -28,7 +16,7 @@ class PlainDirectory(givenPath: Directory) extends PlainFile(givenPath) { } /** This class implements an abstract file backed by a File. - * + * * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ class PlainFile(val givenPath: Path) extends AbstractFile { @@ -77,10 +65,6 @@ class PlainFile(val givenPath: Path) extends AbstractFile { * specified name. If there is no such file, returns null. The * argument "directory" tells whether to look for a directory or * or a regular file. - * - * @param name ... - * @param directory ... - * @return ... */ def lookupName(name: String, directory: Boolean): AbstractFile = { val child = givenPath / name diff --git a/src/reflect/scala/reflect/io/Streamable.scala b/src/reflect/scala/reflect/io/Streamable.scala index 61ec8a4c23..b45cffb150 100644 --- a/src/reflect/scala/reflect/io/Streamable.scala +++ b/src/reflect/scala/reflect/io/Streamable.scala @@ -17,14 +17,14 @@ import Path.fail * * @author Paul Phillips * @since 2.8 - * + * * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ object Streamable { /** Traits which can be viewed as a sequence of bytes. Source types * which know their length should override def length: Long for more * efficient method implementations. - * + * * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ trait Bytes { @@ -69,7 +69,7 @@ object Streamable { } /** For objects which can be viewed as Chars. - * + * * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ trait Chars extends Bytes { @@ -81,7 +81,6 @@ object Streamable { */ def creationCodec: Codec = implicitly[Codec] - def chars(): BufferedSource = chars(creationCodec) def chars(codec: Codec): BufferedSource = Source.fromInputStream(inputStream())(codec) def lines(): Iterator[String] = lines(creationCodec) @@ -89,7 +88,6 @@ object Streamable { /** Obtains an InputStreamReader wrapped around a FileInputStream. */ - def reader(): InputStreamReader = reader(creationCodec) def reader(codec: Codec): InputStreamReader = new InputStreamReader(inputStream, codec.charSet) /** Wraps a BufferedReader around the result of reader(). diff --git a/src/reflect/scala/reflect/io/VirtualDirectory.scala b/src/reflect/scala/reflect/io/VirtualDirectory.scala index 78713c2ae0..94cb52e9b5 100644 --- a/src/reflect/scala/reflect/io/VirtualDirectory.scala +++ b/src/reflect/scala/reflect/io/VirtualDirectory.scala @@ -11,7 +11,7 @@ import scala.collection.mutable * An in-memory directory. * * @author Lex Spoon - * + * * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ class VirtualDirectory(val name: String, maybeContainer: Option[VirtualDirectory]) @@ -26,7 +26,7 @@ extends AbstractFile { def container = maybeContainer.get def isDirectory = true - var lastModified: Long = System.currentTimeMillis + val lastModified: Long = System.currentTimeMillis override def file = null override def input = sys.error("directories cannot be read") diff --git a/src/reflect/scala/reflect/io/VirtualFile.scala b/src/reflect/scala/reflect/io/VirtualFile.scala index 95f4429fad..09b977bd45 100644 --- a/src/reflect/scala/reflect/io/VirtualFile.scala +++ b/src/reflect/scala/reflect/io/VirtualFile.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ - package scala.reflect package io @@ -14,7 +13,7 @@ import java.io.{ File => JFile } * * @author Philippe Altherr * @version 1.0, 23/03/2004 - * + * * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ class VirtualFile(val name: String, override val path: String) extends AbstractFile { @@ -33,12 +32,8 @@ class VirtualFile(val name: String, override val path: String) extends AbstractF case _ => false } - //######################################################################## - // Private data private var content = Array.emptyByteArray - //######################################################################## - // Public Methods def absolute = this /** Returns null. */ @@ -65,7 +60,6 @@ class VirtualFile(val name: String, override val path: String) extends AbstractF /** Returns the time that this abstract file was last modified. */ private var _lastModified: Long = 0 def lastModified: Long = _lastModified - def lastModified_=(x: Long) = _lastModified = x /** Returns all abstract subfiles of this abstract directory. */ def iterator: Iterator[AbstractFile] = { @@ -84,10 +78,6 @@ class VirtualFile(val name: String, override val path: String) extends AbstractF * specified name. If there is no such file, returns null. The * argument "directory" tells whether to look for a directory or * or a regular file. - * - * @param name ... - * @param directory ... - * @return ... */ def lookupName(name: String, directory: Boolean): AbstractFile = { assert(isDirectory, "not a directory '" + this + "'") @@ -98,6 +88,4 @@ class VirtualFile(val name: String, override val path: String) extends AbstractF * check that it exists. */ def lookupNameUnchecked(name: String, directory: Boolean) = unsupported - - //######################################################################## } diff --git a/src/reflect/scala/reflect/io/ZipArchive.scala b/src/reflect/scala/reflect/io/ZipArchive.scala index 3b57721e89..097d3cb71c 100644 --- a/src/reflect/scala/reflect/io/ZipArchive.scala +++ b/src/reflect/scala/reflect/io/ZipArchive.scala @@ -20,13 +20,10 @@ import scala.annotation.tailrec * @author Philippe Altherr (original version) * @author Paul Phillips (this one) * @version 2.0, - * + * * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ object ZipArchive { - def fromPath(path: String): FileZipArchive = fromFile(new JFile(path)) - def fromPath(path: Path): FileZipArchive = fromFile(path.toFile) - /** * @param file a File * @return A ZipArchive if `file` is a readable zip file, otherwise null. @@ -41,7 +38,6 @@ object ZipArchive { * @return A ZipArchive backed by the given url. */ def fromURL(url: URL): URLZipArchive = new URLZipArchive(url) - def fromURL(url: String): URLZipArchive = fromURL(new URL(url)) private def dirName(path: String) = splitPath(path, true) private def baseName(path: String) = splitPath(path, false) @@ -79,7 +75,6 @@ abstract class ZipArchive(override val file: JFile) extends AbstractFile with Eq else Iterator(f) } } - def deepIterator = walkIterator(iterator) /** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ sealed abstract class Entry(path: String) extends VirtualFile(baseName(path), path) { // have to keep this name for compat with sbt's compiler-interface diff --git a/src/reflect/scala/reflect/macros/TreeBuilder.scala b/src/reflect/scala/reflect/macros/TreeBuilder.scala index 204dc40858..fbbbe13201 100644 --- a/src/reflect/scala/reflect/macros/TreeBuilder.scala +++ b/src/reflect/scala/reflect/macros/TreeBuilder.scala @@ -11,7 +11,6 @@ abstract class TreeBuilder { val global: Universe import global._ - import definitions._ /** Builds a reference to value whose type is given stable prefix. * The type must be suitable for this. For example, it diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index ab93d7033a..54d02f3371 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -17,12 +17,9 @@ import internal.ClassfileConstants._ import internal.pickling.UnPickler import scala.collection.mutable.{ HashMap, ListBuffer } import internal.Flags._ -//import scala.tools.nsc.util.ScalaClassLoader -//import scala.tools.nsc.util.ScalaClassLoader._ import ReflectionUtils.{staticSingletonInstance, innerSingletonInstance} import scala.language.existentials import scala.runtime.{ScalaRunTime, BoxesRunTime} -import scala.reflect.internal.util.Collections._ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { thisUniverse: SymbolTable => @@ -378,7 +375,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni val varargMatch = args.length >= params.length - 1 && isVarArgsList(params) if (!perfectMatch && !varargMatch) { val n_arguments = if (isVarArgsList(params)) s"${params.length - 1} or more" else s"${params.length}" - var s_arguments = if (params.length == 1 && !isVarArgsList(params)) "argument" else "arguments" + val s_arguments = if (params.length == 1 && !isVarArgsList(params)) "argument" else "arguments" throw new ScalaReflectionException(s"${showMethodSig(symbol)} takes $n_arguments $s_arguments") } @@ -495,13 +492,10 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni Class.forName(path, true, classLoader) /** Does `path` correspond to a Java class with that fully qualified name in the current class loader? */ - def tryJavaClass(path: String): Option[jClass[_]] = - try { - Some(javaClass(path)) - } catch { - case (_: ClassNotFoundException) | (_: NoClassDefFoundError) | (_: IncompatibleClassChangeError) => - None - } + def tryJavaClass(path: String): Option[jClass[_]] = ( + try Some(javaClass(path)) + catch { case ex @ (_: LinkageError | _: ClassNotFoundException) => None } // TODO - log + ) /** The mirror that corresponds to the classloader that original defined the given Java class */ def mirrorDefining(jclazz: jClass[_]): JavaMirror = { @@ -838,20 +832,6 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni } /** - * The Scala field corresponding to given Java field. - * @param jfield The Java field - * @return A Scala field object that corresponds to `jfield`. - * // ??? should we return the getter instead? - */ - def fieldToScala(jfield: jField): TermSymbol = - toScala(fieldCache, jfield)(_ fieldToScala1 _) - - private def fieldToScala1(jfield: jField): TermSymbol = { - val owner = followStatic(classToScala(jfield.getDeclaringClass), jfield.getModifiers) - (lookup(owner, jfield.getName) suchThat (!_.isMethod) orElse jfieldAsScala(jfield)).asTerm - } - - /** * The Scala package corresponding to given Java package */ def packageToScala(jpkg: jPackage): ModuleSymbol = packageCache.toScala(jpkg) { @@ -1041,7 +1021,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni private def jclassAsScala(jclazz: jClass[_], owner: Symbol): ClassSymbol = { val name = scalaSimpleName(jclazz) val completer = (clazz: Symbol, module: Symbol) => new FromJavaClassCompleter(clazz, module, jclazz) - val (clazz, module) = createClassModule(owner, name, completer) + val (clazz, _) = createClassModule(owner, name, completer) classCache enter (jclazz, clazz) clazz } @@ -1106,7 +1086,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni constructorCache enter (jconstr, constr) val tparams = jconstr.getTypeParameters.toList map createTypeParameter val paramtpes = jconstr.getGenericParameterTypes.toList map typeToScala - setMethType(constr, tparams, paramtpes, clazz.tpe) + setMethType(constr, tparams, paramtpes, clazz.tpe_*) constr setInfo GenPolyType(tparams, MethodType(clazz.newSyntheticValueParams(paramtpes), clazz.tpe)) copyAnnotations(constr, jconstr) constr @@ -1114,13 +1094,6 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni // -------------------- Scala to Java ----------------------------------- - /** Optionally, the Java package corresponding to a given Scala package, or None if no such Java package exists. - * @param pkg The Scala package - */ - def packageToJavaOption(pkg: ModuleSymbol): Option[jPackage] = packageCache.toJavaOption(pkg) { - Option(jPackage.getPackage(pkg.fullName.toString)) - } - /** The Java class corresponding to given Scala class. * Note: This only works for * - top-level classes diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index e18435d5b0..a12e7d43d4 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -1,8 +1,6 @@ package scala.reflect package runtime -import internal.{SomePhase, NoPhase, Phase, TreeGen} - /** An implementation of [[scala.reflect.api.Universe]] for runtime reflection using JVM classloaders. * * Should not be instantiated directly, use [[scala.reflect.runtime.universe]] instead. @@ -11,13 +9,14 @@ import internal.{SomePhase, NoPhase, Phase, TreeGen} */ class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.SymbolTable { self => - def picklerPhase = SomePhase + def picklerPhase = internal.SomePhase - lazy val settings = new Settings def forInteractive = false def forScaladoc = false + lazy val settings = new Settings + private val isLogging = sys.props contains "scala.debug.reflect" - def log(msg: => AnyRef): Unit = println(" [] "+msg) + def log(msg: => AnyRef): Unit = if (isLogging) Console.err.println("[reflect] " + msg) type TreeCopier = InternalTreeCopierOps def newStrictTreeCopier: TreeCopier = new StrictTreeCopier @@ -25,4 +24,3 @@ class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.S init() } - diff --git a/src/reflect/scala/reflect/runtime/Settings.scala b/src/reflect/scala/reflect/runtime/Settings.scala index 0e0cf3fc40..7d04202455 100644 --- a/src/reflect/scala/reflect/runtime/Settings.scala +++ b/src/reflect/scala/reflect/runtime/Settings.scala @@ -43,6 +43,7 @@ private[reflect] class Settings extends MutableSettings { val printtypes = new BooleanSetting(false) val uniqid = new BooleanSetting(false) val verbose = new BooleanSetting(false) + val breakCycles = new BooleanSetting(false) val Yrecursion = new IntSetting(0) val maxClassfileName = new IntSetting(255) diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala index 61663f6181..60b22afd18 100644 --- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala +++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala @@ -28,7 +28,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => debugInfo("completing "+sym+"/"+clazz.fullName) assert(sym == clazz || sym == module || sym == module.moduleClass) // try { - atPhaseNotLaterThan(picklerPhase) { + enteringPhaseNotLaterThan(picklerPhase) { val loadingMirror = mirrorThatLoaded(sym) val javaClass = loadingMirror.javaClass(clazz.javaClassName) loadingMirror.unpickleClass(clazz, module, javaClass) @@ -116,7 +116,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => currentMirror.tryJavaClass(path) match { case Some(cls) => val loadingMirror = currentMirror.mirrorDefining(cls) - val (clazz, module) = + val (_, module) = if (loadingMirror eq currentMirror) { createClassModule(pkgClass, name.toTypeName, new TopClassCompleter(_, _)) } else { diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala index 00f6952dc1..1154927279 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala @@ -83,9 +83,6 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb override protected def createPackageObjectClassSymbol(pos: Position, newFlags: Long): PackageObjectClassSymbol = new PackageObjectClassSymbol(this, pos) with SynchronizedClassSymbol initFlags newFlags - override protected def createTermSymbol(name: TermName, pos: Position, newFlags: Long): TermSymbol = - new TermSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags - override protected def createMethodSymbol(name: TermName, pos: Position, newFlags: Long): MethodSymbol = new MethodSymbol(this, pos, name) with SynchronizedMethodSymbol initFlags newFlags @@ -118,7 +115,8 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb override def name_=(x: Name) = synchronized { super.name_=(x) } override def rawname = synchronized { super.rawname } override def typeConstructor: Type = synchronized { super.typeConstructor } - override def tpe: Type = synchronized { super.tpe } + override def tpe_* : Type = synchronized { super.tpe_* } + override def tpeHK : Type = synchronized { super.tpeHK } } trait SynchronizedClassSymbol extends ClassSymbol with SynchronizedTypeSymbol { diff --git a/src/reflect/scala/reflect/runtime/package.scala b/src/reflect/scala/reflect/runtime/package.scala index b97913daf0..eadbc0c52e 100644 --- a/src/reflect/scala/reflect/runtime/package.scala +++ b/src/reflect/scala/reflect/runtime/package.scala @@ -6,7 +6,7 @@ package scala.reflect package object runtime { /** The entry point into Scala runtime reflection. - * + * * To use Scala runtime reflection, simply use or import `scala.reflect.runtime.universe._` * * See [[scala.reflect.api.Universe]] or the diff --git a/src/scalacheck/org/scalacheck/Commands.scala b/src/scalacheck/org/scalacheck/Commands.scala index 88ef8ae2a1..2acc460b5e 100644 --- a/src/scalacheck/org/scalacheck/Commands.scala +++ b/src/scalacheck/org/scalacheck/Commands.scala @@ -87,11 +87,6 @@ trait Commands extends Prop { private val bindings = new scala.collection.mutable.ListBuffer[(State,Any)] - private def initState() = { - bindings.clear() - initialState() - } - private def genCmds: Gen[Cmds] = { def sizedCmds(s: State)(sz: Int): Gen[Cmds] = if(sz <= 0) value(Cmds(Nil, Nil)) else for { diff --git a/src/scalap/scala/tools/scalap/Arguments.scala b/src/scalap/scala/tools/scalap/Arguments.scala index a151e3067e..9f139cb5ea 100644 --- a/src/scalap/scala/tools/scalap/Arguments.scala +++ b/src/scalap/scala/tools/scalap/Arguments.scala @@ -87,7 +87,7 @@ object Arguments { i += 2 } } else { - var iter = prefixes.iterator + val iter = prefixes.iterator val j = i while ((i == j) && iter.hasNext) { val prefix = iter.next diff --git a/src/scalap/scala/tools/scalap/scalax/rules/Rule.scala b/src/scalap/scala/tools/scalap/scalax/rules/Rule.scala index 1500b81050..489a05ecd0 100644 --- a/src/scalap/scala/tools/scalap/scalax/rules/Rule.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/Rule.scala @@ -50,7 +50,7 @@ trait Rule[-In, +Out, +A, +X] extends (In => Result[Out, A, X]) { lazy val choices = Rule.this :: other :: Nil } - def orError[In2 <: In] = this orElse(error[In2]) + def orError[In2 <: In] = this orElse error[Any] def |[In2 <: In, Out2 >: Out, A2 >: A, X2 >: X](other : => Rule[In2, Out2, A2, X2]) = orElse(other) diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSig.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSig.scala index aa5acbb06d..fd70e0de35 100644 --- a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSig.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSig.scala @@ -167,57 +167,10 @@ object ScalaSigEntryParsers extends RulesWithState with MemoisableRules { val symbolInfo = nameRef ~ symbolRef ~ nat ~ (symbolRef?) ~ ref ~ get ^~~~~~^ SymbolInfo - def symHeader(key: Int) = (key -~ none | (key + 64) -~ nat) + def symHeader(key: Int): EntryParser[Any] = (key -~ none | (key + 64) -~ nat) def symbolEntry(key : Int) = symHeader(key) -~ symbolInfo - /*************************************************** - * Symbol table attribute format: - * Symtab = nentries_Nat {Entry} - * Entry = 1 TERMNAME len_Nat NameInfo - * | 2 TYPENAME len_Nat NameInfo - * | 3 NONEsym len_Nat - * | 4 TYPEsym len_Nat SymbolInfo - * | 5 ALIASsym len_Nat SymbolInfo - * | 6 CLASSsym len_Nat SymbolInfo [thistype_Ref] - * | 7 MODULEsym len_Nat SymbolInfo - * | 8 VALsym len_Nat [defaultGetter_Ref /* no longer needed*/] SymbolInfo [alias_Ref] - * | 9 EXTref len_Nat name_Ref [owner_Ref] - * | 10 EXTMODCLASSref len_Nat name_Ref [owner_Ref] - * | 11 NOtpe len_Nat - * | 12 NOPREFIXtpe len_Nat - * | 13 THIStpe len_Nat sym_Ref - * | 14 SINGLEtpe len_Nat type_Ref sym_Ref - * | 15 CONSTANTtpe len_Nat constant_Ref - * | 16 TYPEREFtpe len_Nat type_Ref sym_Ref {targ_Ref} - * | 17 TYPEBOUNDStpe len_Nat tpe_Ref tpe_Ref - * | 18 REFINEDtpe len_Nat classsym_Ref {tpe_Ref} - * | 19 CLASSINFOtpe len_Nat classsym_Ref {tpe_Ref} - * | 20 METHODtpe len_Nat tpe_Ref {sym_Ref} - * | 21 POLYTtpe len_Nat tpe_Ref {sym_Ref} - * | 22 IMPLICITMETHODtpe len_Nat tpe_Ref {sym_Ref} /* no longer needed */ - * | 52 SUPERtpe len_Nat tpe_Ref tpe_Ref - * | 24 LITERALunit len_Nat - * | 25 LITERALboolean len_Nat value_Long - * | 26 LITERALbyte len_Nat value_Long - * | 27 LITERALshort len_Nat value_Long - * | 28 LITERALchar len_Nat value_Long - * | 29 LITERALint len_Nat value_Long - * | 30 LITERALlong len_Nat value_Long - * | 31 LITERALfloat len_Nat value_Long - * | 32 LITERALdouble len_Nat value_Long - * | 33 LITERALstring len_Nat name_Ref - * | 34 LITERALnull len_Nat - * | 35 LITERALclass len_Nat tpe_Ref - * | 36 LITERALenum len_Nat sym_Ref - * | 40 SYMANNOT len_Nat sym_Ref AnnotInfoBody - * | 41 CHILDREN len_Nat sym_Ref {sym_Ref} - * | 42 ANNOTATEDtpe len_Nat [sym_Ref /* no longer needed */] tpe_Ref {annotinfo_Ref} - * | 43 ANNOTINFO len_Nat AnnotInfoBody - * | 44 ANNOTARGARRAY len_Nat {constAnnotArg_Ref} - * | 47 DEBRUIJNINDEXtpe len_Nat level_Nat index_Nat - * | 48 EXISTENTIALtpe len_Nat type_Ref {symbol_Ref} - */ val noSymbol = 3 -^ NoSymbol val typeSymbol = symbolEntry(4) ^^ TypeSymbol as "typeSymbol" val aliasSymbol = symbolEntry(5) ^^ AliasSymbol as "alias" @@ -260,10 +213,9 @@ object ScalaSigEntryParsers extends RulesWithState with MemoisableRules { 22 -~ typeRef ~ (symbolRef*) ^~^ MethodType, 42 -~ typeRef ~ (attribTreeRef*) ^~^ AnnotatedType, 51 -~ typeRef ~ symbolRef ~ (attribTreeRef*) ^~~^ AnnotatedWithSelfType, - 47 -~ typeLevel ~ typeIndex ^~^ DeBruijnIndexType, 48 -~ typeRef ~ (symbolRef*) ^~^ ExistentialType) as "type" - lazy val literal = oneOf( + lazy val literal: EntryParser[Any] = oneOf( 24 -^ (()), 25 -~ longValue ^^ (_ != 0L), 26 -~ longValue ^^ (_.toByte), diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala index cfe615a6d5..e5a4ff649e 100644 --- a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala @@ -70,7 +70,7 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) { } def isCaseClassObject(o: ObjectSymbol): Boolean = { - val TypeRefType(prefix, classSymbol: ClassSymbol, typeArgs) = o.infoType + val TypeRefType(_, classSymbol: ClassSymbol, _) = o.infoType o.isFinal && (classSymbol.children.find(x => x.isCase && x.isInstanceOf[MethodSymbol]) match { case Some(_) => true case None => false @@ -167,7 +167,7 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) { print("object ") val poName = o.symbolInfo.owner.name print(processName(poName)) - val TypeRefType(prefix, classSymbol: ClassSymbol, typeArgs) = o.infoType + val TypeRefType(_, classSymbol: ClassSymbol, _) = o.infoType printType(classSymbol) print(" {\n") printChildren(level, classSymbol) @@ -179,7 +179,7 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) { printModifiers(o) print("object ") print(processName(o.name)) - val TypeRefType(prefix, classSymbol: ClassSymbol, typeArgs) = o.infoType + val TypeRefType(_, classSymbol: ClassSymbol, _) = o.infoType printType(classSymbol) print(" {\n") printChildren(level, classSymbol) @@ -191,7 +191,7 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) { val j = str.indexOf("[") if (j > 0) str = str.substring(0, j) str = StringUtil.trimStart(str, "=> ") - var i = str.lastIndexOf(".") + val i = str.lastIndexOf(".") val res = if (i > 0) str.substring(i + 1) else str if (res.length > 1) StringUtil.decapitalize(res.substring(0, 1)) else res.toLowerCase }) @@ -381,7 +381,6 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) { toString(typeRef, sep) } case AnnotatedWithSelfType(typeRef, symbol, attribTreeRefs) => toString(typeRef, sep) - //case DeBruijnIndexType(typeLevel, typeIndex) => case ExistentialType(typeRef, symbols) => { val refs = symbols.map(toString _).filter(!_.startsWith("_")).map("type " + _) toString(typeRef, sep) + (if (refs.size > 0) refs.mkString(" forSome {", "; ", "}") else "") diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Type.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Type.scala index 543ddbe186..0444e701f2 100644 --- a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Type.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Type.scala @@ -22,5 +22,4 @@ case class PolyType(typeRef : Type, symbols : Seq[TypeSymbol]) extends Type case class PolyTypeWithCons(typeRef : Type, symbols : Seq[TypeSymbol], cons: String) extends Type case class AnnotatedType(typeRef : Type, attribTreeRefs : List[Int]) extends Type case class AnnotatedWithSelfType(typeRef : Type, symbol : Symbol, attribTreeRefs : List[Int]) extends Type -case class DeBruijnIndexType(typeLevel : Int, typeIndex : Int) extends Type case class ExistentialType(typeRef : Type, symbols : Seq[Symbol]) extends Type diff --git a/src/swing/scala/swing/Button.scala b/src/swing/scala/swing/Button.scala index f10d49d804..0170727e3b 100644 --- a/src/swing/scala/swing/Button.scala +++ b/src/swing/scala/swing/Button.scala @@ -6,11 +6,8 @@ ** |/ ** \* */ - - package scala.swing -import event._ import javax.swing._ object Button { diff --git a/src/swing/scala/swing/ButtonGroup.scala b/src/swing/scala/swing/ButtonGroup.scala index 2075df7c92..0b04d20837 100644 --- a/src/swing/scala/swing/ButtonGroup.scala +++ b/src/swing/scala/swing/ButtonGroup.scala @@ -8,9 +8,7 @@ package scala.swing -import event._ -import javax.swing.{AbstractButton => JAbstractButton,Icon} -import scala.collection.{ mutable, immutable } +import scala.collection.mutable /** * A button mutex. At most one of its associated buttons is selected diff --git a/src/swing/scala/swing/ComboBox.scala b/src/swing/scala/swing/ComboBox.scala index 5b70f6fda9..ce2b3ba6fb 100644 --- a/src/swing/scala/swing/ComboBox.scala +++ b/src/swing/scala/swing/ComboBox.scala @@ -182,7 +182,7 @@ class ComboBox[A](items: Seq[A]) extends Component with Publisher { * of the component to its own defaults _after_ the renderer has been * configured. That's Swing's principle of most suprise. */ - def renderer: ListView.Renderer[A] = ListView.Renderer.wrap(peer.getRenderer) + def renderer: ListView.Renderer[A] = ListView.Renderer.wrap[A](peer.getRenderer) def renderer_=(r: ListView.Renderer[A]) { peer.setRenderer(r.peer) } /* XXX: currently not safe to expose: diff --git a/src/swing/scala/swing/EditorPane.scala b/src/swing/scala/swing/EditorPane.scala index b8c506daf0..9b1aab7874 100644 --- a/src/swing/scala/swing/EditorPane.scala +++ b/src/swing/scala/swing/EditorPane.scala @@ -6,13 +6,10 @@ ** |/ ** \* */ - package scala.swing -import event._ import javax.swing._ import javax.swing.text._ -import java.awt.event._ /** * A text component that allows multiline text input and display. diff --git a/src/swing/scala/swing/Font.scala.disabled b/src/swing/scala/swing/Font.scala.disabled deleted file mode 100644 index 9e21eb859c..0000000000 --- a/src/swing/scala/swing/Font.scala.disabled +++ /dev/null @@ -1,70 +0,0 @@ -package scala.swing - -/*object Font { - def apply(fontFormat: Int, fontFile: java.io.File) = java.awt.Font.createFont(fontFormat, fontFile) - def apply(fontFormat: Int, fontStream: java.io.InputStream) = java.awt.Font.createFont(fontFormat, fontStream) - def decode(str: String) = java.awt.Font.decode(str) - - /* TODO: finish implementation - /** - * See [java.awt.Font.getFont]. - */ - def get(attributes: Map[_ <: java.text.AttributedCharacterIterator.Attribute, _]) = - java.awt.Font.getFont(ImmutableMapWrapper(attributes)) - - import java.{util => ju} - private case class ImmutableMapWrapper[A, B](underlying : Map[A, B])(t : ClassTag[A]) extends ju.AbstractMap[A, B] { - self => - override def size = underlying.size - - override def put(k : A, v : B) = - throw new UnsupportedOperationException("This is a wrapper that does not support mutation") - override def remove(k : AnyRef) = - throw new UnsupportedOperationException("This is a wrapper that does not support mutation") - - override def entrySet : ju.Set[ju.Map.Entry[A, B]] = new ju.AbstractSet[ju.Map.Entry[A, B]] { - def size = self.size - - def iterator = new ju.Iterator[ju.Map.Entry[A, B]] { - val ui = underlying.iterator - var prev : Option[A] = None - - def hasNext = ui.hasNext - - def next = { - val (k, v) = ui.next - prev = Some(k) - new ju.Map.Entry[A, B] { - def getKey = k - def getValue = v - def setValue(v1 : B) = self.put(k, v1) - override def equals(other : Any) = other match { - case e : ju.Map.Entry[_, _] => k == e.getKey && v == e.getValue - case _ => false - } - } - } - - def remove = prev match { - case Some(k) => val v = self.remove(k.asInstanceOf[AnyRef]) ; prev = None ; v - case _ => throw new IllegalStateException("next must be called at least once before remove") - } - } - } - } - */ - - /** - * See [java.awt.Font.getFont]. - */ - def get(nm: String) = java.awt.Font.getFont(nm) - /** - * See [java.awt.Font.getFont]. - */ - def get(nm: String, font: Font) = java.awt.Font.getFont(nm, font) - - def Insets(x: Int, y: Int, width: Int, height: Int) = new Insets(x, y, width, height) - def Rectangle(x: Int, y: Int, width: Int, height: Int) = new Insets(x, y, width, height) - def Point(x: Int, y: Int) = new Point(x, y) - def Dimension(x: Int, y: Int) = new Dimension(x, y) -}*/
\ No newline at end of file diff --git a/src/swing/scala/swing/FormattedTextField.scala b/src/swing/scala/swing/FormattedTextField.scala index 311ff42d0a..b08075850c 100644 --- a/src/swing/scala/swing/FormattedTextField.scala +++ b/src/swing/scala/swing/FormattedTextField.scala @@ -6,13 +6,9 @@ ** |/ ** \* */ - - package scala.swing -import event._ import javax.swing._ -import java.awt.event._ object FormattedTextField { /** diff --git a/src/swing/scala/swing/ListView.scala b/src/swing/scala/swing/ListView.scala index 40639aa9e2..d0c4e45190 100644 --- a/src/swing/scala/swing/ListView.scala +++ b/src/swing/scala/swing/ListView.scala @@ -216,7 +216,7 @@ class ListView[A] extends Component { def adjusting = peer.getSelectionModel.getValueIsAdjusting } - def renderer: ListView.Renderer[A] = ListView.Renderer.wrap(peer.getCellRenderer) + def renderer: ListView.Renderer[A] = ListView.Renderer.wrap[A](peer.getCellRenderer) def renderer_=(r: ListView.Renderer[A]) { peer.setCellRenderer(r.peer) } def fixedCellWidth = peer.getFixedCellWidth diff --git a/src/swing/scala/swing/MainFrame.scala b/src/swing/scala/swing/MainFrame.scala index 85ce0755ac..1dfc155f9c 100644 --- a/src/swing/scala/swing/MainFrame.scala +++ b/src/swing/scala/swing/MainFrame.scala @@ -6,12 +6,8 @@ ** |/ ** \* */ - - package scala.swing -import event._ - /** * A frame that can be used for main application windows. Shuts down the * framework and quits the application when closed. diff --git a/src/swing/scala/swing/PasswordField.scala b/src/swing/scala/swing/PasswordField.scala index d2fdd0d38a..fd0b586a0f 100644 --- a/src/swing/scala/swing/PasswordField.scala +++ b/src/swing/scala/swing/PasswordField.scala @@ -6,13 +6,9 @@ ** |/ ** \* */ - - package scala.swing -import event._ import javax.swing._ -import java.awt.event._ /** * A password field, that displays a replacement character for each character in the password. diff --git a/src/swing/scala/swing/ProgressBar.scala b/src/swing/scala/swing/ProgressBar.scala index 33dd716524..81e2989c3e 100644 --- a/src/swing/scala/swing/ProgressBar.scala +++ b/src/swing/scala/swing/ProgressBar.scala @@ -6,12 +6,8 @@ ** |/ ** \* */ - - package scala.swing -import event._ - /** * A bar indicating progress of some action. Can be in indeterminate mode, * in which it indicates that the action is in progress (usually by some diff --git a/src/swing/scala/swing/Reactions.scala b/src/swing/scala/swing/Reactions.scala index d8a62aa99d..c32212cf3a 100644 --- a/src/swing/scala/swing/Reactions.scala +++ b/src/swing/scala/swing/Reactions.scala @@ -14,8 +14,6 @@ import event.Event import scala.collection.mutable.{Buffer, ListBuffer} object Reactions { - import scala.ref._ - class Impl extends Reactions { private val parts: Buffer[Reaction] = new ListBuffer[Reaction] def isDefinedAt(e: Event) = parts.exists(_ isDefinedAt e) diff --git a/src/swing/scala/swing/SplitPane.scala b/src/swing/scala/swing/SplitPane.scala index dd4f2908d5..f61dfedbf4 100644 --- a/src/swing/scala/swing/SplitPane.scala +++ b/src/swing/scala/swing/SplitPane.scala @@ -6,11 +6,8 @@ ** |/ ** \* */ - - package scala.swing -import event._ import Swing._ /** diff --git a/src/swing/scala/swing/SwingActor.scala b/src/swing/scala/swing/SwingActor.scala index 6692180aac..c665fa4c00 100644 --- a/src/swing/scala/swing/SwingActor.scala +++ b/src/swing/scala/swing/SwingActor.scala @@ -6,12 +6,8 @@ ** |/ ** \* */ - - package scala.swing -import scala.actors._ - // Dummy to keep ant from recompiling on every run. trait SwingActor { } diff --git a/src/swing/scala/swing/TabbedPane.scala b/src/swing/scala/swing/TabbedPane.scala index 338050515a..6e46256f86 100644 --- a/src/swing/scala/swing/TabbedPane.scala +++ b/src/swing/scala/swing/TabbedPane.scala @@ -112,9 +112,6 @@ class TabbedPane extends Component with Publisher { */ def tabPlacement_=(b: Alignment.Value) { peer.setTabPlacement(b.id) } - @deprecated("Use tabPlacement_=() instead.", "2.9.1") - def tabPlacement(b: Alignment.Value) { peer.setTabPlacement(b.id) } - /** * The current page selection */ diff --git a/src/swing/scala/swing/TextArea.scala b/src/swing/scala/swing/TextArea.scala index 01bf115d28..2f6bdca119 100644 --- a/src/swing/scala/swing/TextArea.scala +++ b/src/swing/scala/swing/TextArea.scala @@ -6,13 +6,9 @@ ** |/ ** \* */ - - package scala.swing -import event._ import javax.swing._ -import java.awt.event._ /** * A text component that allows multiline text input and display. diff --git a/src/swing/scala/swing/TextComponent.scala b/src/swing/scala/swing/TextComponent.scala index 48c03a5f54..4d23399737 100644 --- a/src/swing/scala/swing/TextComponent.scala +++ b/src/swing/scala/swing/TextComponent.scala @@ -6,12 +6,9 @@ ** |/ ** \* */ - - package scala.swing import event._ -import javax.swing._ import javax.swing.text._ import javax.swing.event._ diff --git a/src/swing/scala/swing/ToggleButton.scala b/src/swing/scala/swing/ToggleButton.scala index 3d3d0b957f..8f210d00d8 100644 --- a/src/swing/scala/swing/ToggleButton.scala +++ b/src/swing/scala/swing/ToggleButton.scala @@ -6,11 +6,8 @@ ** |/ ** \* */ - - package scala.swing -import event._ import javax.swing._ /** diff --git a/src/swing/scala/swing/Window.scala b/src/swing/scala/swing/Window.scala index 5bdb50e959..a9f4ae7538 100644 --- a/src/swing/scala/swing/Window.scala +++ b/src/swing/scala/swing/Window.scala @@ -6,13 +6,10 @@ ** |/ ** \* */ - - package scala.swing import java.awt.{Window => AWTWindow} import event._ -import javax.swing._ /** * A window with decoration such as a title, border, and action buttons. |