From d492b489b176a3d2a4da0d199756af86514be352 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 28 Jul 2008 10:00:31 +0000 Subject: fixed #842, #945, #83, #996, #1016, + some perf... fixed #842, #945, #83, #996, #1016, + some performace tuning. --- .../scala/tools/nsc/backend/jvm/GenJVM.scala | 2 +- .../scala/tools/nsc/javac/JavaParsers.scala | 3 +- .../scala/tools/nsc/symtab/BaseTypeSeqs.scala | 12 +++- src/compiler/scala/tools/nsc/symtab/StdNames.scala | 7 +++ src/compiler/scala/tools/nsc/symtab/Types.scala | 14 +---- .../nsc/symtab/classfile/ClassfileParser.scala | 44 ++++++++------- .../scala/tools/nsc/transform/Erasure.scala | 9 ++- .../scala/tools/nsc/typechecker/Typers.scala | 11 ++-- src/library/scala/util/matching/Regex.scala | 64 ++++++++++++++-------- test/files/neg/t0764.check | 2 +- test/files/neg/t0842.check | 4 ++ test/files/neg/t0842.scala | 1 + test/files/pos/t0872.scala | 8 +++ test/pending/pos/t0756.scala | 8 +++ test/pending/pos/t0774/unrelated.scala | 9 +++ test/pending/pos/t0805.scala | 9 +++ test/pending/run/t0508x.scala | 21 +++++++ test/pending/run/t0818.scala | 4 ++ 18 files changed, 165 insertions(+), 67 deletions(-) create mode 100644 test/files/neg/t0842.check create mode 100755 test/files/neg/t0842.scala create mode 100755 test/files/pos/t0872.scala create mode 100644 test/pending/pos/t0756.scala create mode 100644 test/pending/pos/t0774/unrelated.scala create mode 100644 test/pending/pos/t0805.scala create mode 100755 test/pending/run/t0508x.scala create mode 100644 test/pending/run/t0818.scala diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 8a96dfbb38..cbad27aea5 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -400,7 +400,7 @@ abstract class GenJVM extends SubComponent { def addGenericSignature(jmember: JMember, sym: Symbol, tp: Type) { if (settings.target.value == "jvm-1.5" && erasure.needsJavaSig(tp)) { val sig = erasure.javaSig(tp) - if (settings.verbose.value) println("add generic sig "+sym+":"+tp+" ==> "+sig) + if (settings.debug.value && settings.verbose.value) println("add generic sig "+sym+":"+tp+" ==> "+sig) val buf = ByteBuffer.allocate(2) buf.putShort(jmember.getConstantPool().addUtf8(sig).toShort) addAttribute(jmember, nme.SignatureATTR, buf) diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 3e0f336b60..e187a07138 100755 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -564,8 +564,7 @@ trait JavaParsers extends JavaScanners { in.nextToken if (in.token == IDENTIFIER) { // if there's an ident after the comma ... val name = ident() - in.nextToken - if (in.token == ASSIGN) { // ... followed by an `=', we know it's a real variable definition + if (in.token == ASSIGN || in.token == SEMI) { // ... followed by a `=' or `;', we know it's a real variable definition buf ++= maybe buf += varDecl(in.currentPos, mods, tpt.duplicate, name) maybe.clear() diff --git a/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala b/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala index 8bc68d8ff1..c1c251c9bd 100755 --- a/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala +++ b/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala @@ -87,7 +87,17 @@ trait BaseTypeSeqs { /** Compute new base type sequence where every element is mapped * with function `f'. Lazy types are mapped but not evaluated */ - def map(f: Type => Type): BaseTypeSeq = new BaseTypeSeq(parents, elems map f) + def map(f: Type => Type): BaseTypeSeq = { + // inlined `elems map f' for performance + val len = length + var arr = new Array[Type](len) + var i = 0 + while (i < len) { + arr(i) = f(elems(i)) + i += 1 + } + new BaseTypeSeq(parents, arr) + } def exists(p: Type => Boolean): Boolean = elems exists p // (0 until length) exists (i => p(this(i))) diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index 16eb6dd01b..de08a7ef66 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -181,14 +181,20 @@ trait StdNames { val WILDCARD = newTermName("_") val WILDCARD_STAR = newTermName("_*") val COMPOUND_NAME = newTermName("") + val ANON_CLASS_NAME = newTermName("$anon") + val ANON_CLASS_NAME_tn = ANON_CLASS_NAME.toTypeName val ANON_FUN_NAME = newTermName("$anonfun") + val ANON_FUN_NAME_tn = ANON_FUN_NAME.toTypeName val REFINE_CLASS_NAME = newTermName("") + val REFINE_CLASS_NAME_tn = REFINE_CLASS_NAME.toTypeName val EMPTY_PACKAGE_NAME = newTermName("") + val EMPTY_PACKAGE_NAME_tn = EMPTY_PACKAGE_NAME.toTypeName val IMPORT = newTermName("") val ZERO = newTermName("") val STAR = newTermName("*") val ROOT = newTermName("") + val ROOT_tn = ROOT.toTypeName val ROOTPKG = newTermName("_root_") val REPEATED_PARAM_CLASS_NAME = newTermName("") val BYNAME_PARAM_CLASS_NAME = newTermName("") @@ -336,6 +342,7 @@ trait StdNames { val runtime = newTermName("runtime") val sameElements = newTermName("sameElements") val scala_ = newTermName("scala") + val scala_tn = scala_.toTypeName val self = newTermName("self") val synchronized_ = newTermName("synchronized") val tag = newTermName("$tag") diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 1f4e9ec57e..ad3d99b680 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -388,7 +388,7 @@ trait Types { */ def asSeenFrom(pre: Type, clazz: Symbol): Type = if (!isTrivial && (!phase.erasedTypes || pre.typeSymbol == ArrayClass)) { - val m = new AsSeenFromMap(pre, clazz) + val m = new AsSeenFromMap(pre.normalize, clazz) val tp = m apply this existentialAbstraction(m.capturedParams, tp) } else this @@ -917,7 +917,7 @@ trait Types { override def safeToString: String = if (sym.isRoot) "" else if (sym.isEmptyPackageClass) "" - else super.toString + else super.safeToString override def narrow: Type = this override def kind = "ThisType" } @@ -1746,7 +1746,7 @@ A type's typeSymbol should never be inspected directly. val level = skolemizationLevel def setInst(tp: Type) { - assert(!(tp containsTp this), this) +// assert(!(tp containsTp this), this) constr.inst = tp } @@ -3073,14 +3073,6 @@ A type's typeSymbol should never be inspected directly. sym } else { var rebind0 = pre.findMember(sym.name, BRIDGE, 0, true)(NoSymbol) -/* - if (rebind0 == NoSymbol && (sym hasFlag EXPANDEDNAME)) { - // problem is that symbols with expanded names might be in the wrong hash bucket - // in a previous scope. We account for that by re-creating the hash as a last attempt. - sym.owner.info.decls.createHash() - rebind0 = pre.findMember(sym.name, BRIDGE, 0, true) - } -*/ if (rebind0 == NoSymbol) { assert(false, ""+pre+"."+sym+" does no longer exist, phase = "+phase) } /** The two symbols have the same fully qualified name */ def corresponds(sym1: Symbol, sym2: Symbol): Boolean = diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index ce98eac3ff..4da75b3e4f 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -707,29 +707,31 @@ abstract class ClassfileParser { } /** Parse and return a single annotation. If it is malformed, - * throw an exception. If it contains a nested annotation, - * return None. + * or it contains a nested annotation, return None. */ - def parseAnnotation(attrNameIndex: Char): Option[AnnotationInfo] = { - val attrType = pool.getType(attrNameIndex) - val nargs = in.nextChar - val nvpairs = new ListBuffer[(Name,AnnotationArgument)] - var nestedAnnot = false // if a nested annotation is seen, - // then skip this annotation - for (i <- 0 until nargs) { - val name = pool.getName(in.nextChar) - val argConst = parseTaggedConstant - if (argConst.tag == AnnotationTag) - nestedAnnot = true - else - nvpairs += ((name, new AnnotationArgument(argConst))) - } + def parseAnnotation(attrNameIndex: Char): Option[AnnotationInfo] = + try { + val attrType = pool.getType(attrNameIndex) + val nargs = in.nextChar + val nvpairs = new ListBuffer[(Name,AnnotationArgument)] + var nestedAnnot = false // if a nested annotation is seen, + // then skip this annotation + for (i <- 0 until nargs) { + val name = pool.getName(in.nextChar) + val argConst = parseTaggedConstant + if (argConst.tag == AnnotationTag) + nestedAnnot = true + else + nvpairs += ((name, new AnnotationArgument(argConst))) + } - if (nestedAnnot) - None - else - Some(AnnotationInfo(attrType, List(), nvpairs.toList)) - } + if (nestedAnnot) + None + else + Some(AnnotationInfo(attrType, List(), nvpairs.toList)) + } catch { + case ex: Throwable => None // ignore malformed annotations ==> t1135 + } /** Parse a sequence of annotations and attach them to the * current symbol sym. diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 3bf2931a70..52e247db02 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -90,10 +90,15 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { apply(restpe) case ExistentialType(tparams, restpe) => apply(restpe) - case MethodType(formals, restpe) => + case mt @ MethodType(formals, restpe) => MethodType( formals map apply, - if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass) else apply(restpe)) + if (restpe.typeSymbol == UnitClass) + erasedTypeRef(UnitClass) + else if (settings.Xexperimental.value) + apply(mt.resultType(formals)) // this gets rid of DeBruijnTypes + else + apply(restpe)) case RefinedType(parents, decls) => if (parents.isEmpty) erasedTypeRef(ObjectClass) else apply(parents.head) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 6974684ac2..d410bf6eee 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2963,10 +2963,10 @@ trait Typers { self: Analyzer => def typedAppliedTypeTree(tpt: Tree, args: List[Tree]) = { val tpt1 = typed1(tpt, mode | FUNmode | TAPPmode, WildcardType) - // @S: shouldn't be necessary now, fixed a problem with SimpleTypeProxy not relaying typeParams calls. - // if (inIDE) tpt1.symbol.info // @S: seems like typeParams call doesn't force completion of symbol type in IDE. if (tpt1.tpe.isError) { setError(tree) + } else if (!tpt1.hasSymbol) { + errorTree(tree, tpt1.tpe+" does not take type parameters") } else { val tparams = tpt1.symbol.typeParams if (tparams.length == args.length) { @@ -3280,7 +3280,7 @@ trait Typers { self: Analyzer => tree.tpe = null if (tree.hasSymbol) tree.symbol = NoSymbol } - //Console.println("typing "+tree+", "+context.undetparams);//DEBUG +// Console.println("typing "+tree+", "+context.undetparams);//DEBUG def dropExistential(tp: Type): Type = tp match { case ExistentialType(tparams, tpe) => if (settings.debug.value) println("drop ex "+tree+" "+tp) @@ -3291,14 +3291,13 @@ trait Typers { self: Analyzer => if (tp1 eq tp0) tp else tp1 case _ => tp } -// Console.println("typing "+tree+" at "+tree.pos);//DEBUG var tree1 = if (tree.tpe ne null) tree else typed1(tree, mode, dropExistential(pt)) -// Console.println("typed "+tree1+":"+tree1.tpe+", "+context.undetparams);//DEBUG +// Console.println("typed "+tree1+":"+tree1.tpe+", "+context.undetparams);//DEBUG tree1.tpe = addAnnotations(tree1, tree1.tpe) val result = if (tree1.isEmpty || (inIDE && tree1.tpe == null)) tree1 else adapt(tree1, mode, pt) -// Console.println("adapted "+tree1+":"+tree1.tpe+" to "+pt+", "+context.undetparams);//DEBUG +// Console.println("adapted "+tree1+":"+tree1.tpe+" to "+pt+", "+context.undetparams);//DEBUG // if ((mode & TYPEmode) != 0) println("type: "+tree1+" has type "+tree1.tpe) result } catch { diff --git a/src/library/scala/util/matching/Regex.scala b/src/library/scala/util/matching/Regex.scala index 0db6372655..56c90f1073 100644 --- a/src/library/scala/util/matching/Regex.scala +++ b/src/library/scala/util/matching/Regex.scala @@ -132,41 +132,61 @@ object Regex { /** The names of the groups, or some empty sequence if one defined */ val groupNames: Seq[String] - /** The index of the first matched character */ + /** The number of subgroups in the pattern (not all of these need to match!) */ + def groupCount: Int + + /** The index of the first matched character, or -1 if nothing was matched */ def start: Int - /** The index of the first matched character in group i */ + /** The index of the first matched character in group i, + * or -1 if nothing was matched for that group */ def start(i: Int): Int - /** The index of the last matched character */ + /** The index of the last matched character, or -1 if nothing was matched */ def end: Int - /** The number of subgroups */ - def groupCount: Int - - /** The index following the last matched character in group i */ + /** The index following the last matched character in group i, + * or -1 if nothing was matched for that group */ def end(i: Int): Int - /** The matched string */ - def matched: String = source.subSequence(start, end).toString + /** The matched string, + * of null if nothing was matched */ + def matched: String = + if (start >= 0) source.subSequence(start, end).toString + else null - /** The matched string in group i */ - def group(i: Int): String = source.subSequence(start(i), end(i)).toString + /** The matched string in group i, + * or null if nothing was matched */ + def group(i: Int): String = + if (start(i) >= 0) source.subSequence(start(i), end(i)).toString + else null /** All matched subgroups, i.e. not including group(0) */ def subgroups: List[String] = (1 to groupCount).toList map group - /** The char sequence before first character of match */ - def before: java.lang.CharSequence = source.subSequence(0, start) - - /** The char sequence before first character of match in group i */ - def before(i: Int): java.lang.CharSequence = source.subSequence(0, start(i)) - - /** Returns char sequence after last character of match */ - def after: java.lang.CharSequence = source.subSequence(end, source.length) - - /** The char sequence after last character of match in group i */ - def after(i: Int): java.lang.CharSequence = source.subSequence(end(i), source.length) + /** The char sequence before first character of match, + * or null if nothing was matched */ + def before: java.lang.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 = + 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 = + 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 = + if (end(i) >= 0) source.subSequence(end(i), source.length) + else null private lazy val nameToIndex: Map[String, Int] = Map() ++ ("" :: groupNames.toList).zipWithIndex diff --git a/test/files/neg/t0764.check b/test/files/neg/t0764.check index b622f17c5e..9f0cedc69b 100644 --- a/test/files/neg/t0764.check +++ b/test/files/neg/t0764.check @@ -1,5 +1,5 @@ t0764.scala:13: error: type mismatch; - found : java.lang.Object with Node{type T = _1.type} where val _1: Main.this.AType + found : java.lang.Object with Node{type T = _1.type} where val _1: Node{type T = NextType} required: Node{type T = Main.this.AType} new Main[AType]( (value: AType).prepend ) ^ diff --git a/test/files/neg/t0842.check b/test/files/neg/t0842.check new file mode 100644 index 0000000000..5f88f08194 --- /dev/null +++ b/test/files/neg/t0842.check @@ -0,0 +1,4 @@ +t0842.scala:1: error: A.this.type does not take type parameters +trait A[T] { def m: this.type[T] = this } + ^ +one error found diff --git a/test/files/neg/t0842.scala b/test/files/neg/t0842.scala new file mode 100755 index 0000000000..f32c2ba26d --- /dev/null +++ b/test/files/neg/t0842.scala @@ -0,0 +1 @@ +trait A[T] { def m: this.type[T] = this } diff --git a/test/files/pos/t0872.scala b/test/files/pos/t0872.scala new file mode 100755 index 0000000000..8f4c1c4436 --- /dev/null +++ b/test/files/pos/t0872.scala @@ -0,0 +1,8 @@ +object Main { + def main(args : Array[String]) { + val fn = (a : Int, str : String) => "a: " + a + ", str: " + str + implicit def fx[T](f : (T,String) => String) = (x:T) => f(x,null) + println(fn(1)) + () + } +} diff --git a/test/pending/pos/t0756.scala b/test/pending/pos/t0756.scala new file mode 100644 index 0000000000..a778bd63d0 --- /dev/null +++ b/test/pending/pos/t0756.scala @@ -0,0 +1,8 @@ +object Test { + for { + n <- Some(42) + + _ + m <- Some(24) + } yield n +} diff --git a/test/pending/pos/t0774/unrelated.scala b/test/pending/pos/t0774/unrelated.scala new file mode 100644 index 0000000000..1efdb2505e --- /dev/null +++ b/test/pending/pos/t0774/unrelated.scala @@ -0,0 +1,9 @@ +object Outer { + import Inner._ + + deathname + + object Inner { + def deathname: Int = 1 + } +} diff --git a/test/pending/pos/t0805.scala b/test/pending/pos/t0805.scala new file mode 100644 index 0000000000..565a2a6527 --- /dev/null +++ b/test/pending/pos/t0805.scala @@ -0,0 +1,9 @@ +package fr.up5.mi.noel.scala +object Test { + def make(t: Test) : Test = TestList(t.args.toList) +} +case class TestList[T](elements: List[T])(implicit f: T => Test) + +class Test { + val args: Array[Test] +} diff --git a/test/pending/run/t0508x.scala b/test/pending/run/t0508x.scala new file mode 100755 index 0000000000..0c1ffde3ed --- /dev/null +++ b/test/pending/run/t0508x.scala @@ -0,0 +1,21 @@ + final object Test extends java.lang.Object with Application { + + class Foo(val s: String, val n: Int) extends java.lang.Object { + }; + + def foo[A >: Nothing <: Any, B >: Nothing <: Any, C >: Nothing <: Any] + (unapply1: (A) => Option[(B, C)], v: A): Unit = + unapply1.apply(v) match { + case Some((fst @ _, snd @ _)) => + scala.Predef.println(scala.Tuple2.apply[java.lang.String, java.lang.String]("first: ".+(fst), " second: ".+(snd))) + case _ => scala.Predef.println(":(") + } + Test.this.foo[Test.Foo, String, Int]({ + ((eta$0$1: Test.Foo) => Test.this.Foo.unapply(eta$0$1)) + }, Test.this.Foo.apply("this might be fun", 10)); + final object Foo extends java.lang.Object with ((String, Int) => Test.Foo) { + def unapply(x$0: Test.Foo): Some[(String, Int)] = scala.Some.apply[(String, Int)](scala.Tuple2.apply[String, Int](x$0.s, x$0.n)); + def apply(s: String, n: Int): Test.Foo = new Test.this.Foo(s, n) + } + } + diff --git a/test/pending/run/t0818.scala b/test/pending/run/t0818.scala new file mode 100644 index 0000000000..677b85d920 --- /dev/null +++ b/test/pending/run/t0818.scala @@ -0,0 +1,4 @@ +object Seth extends Application { + println( + new java.util.ArrayList[String]().toArray(Array[String]())) +} -- cgit v1.2.3