From 7fb5a1b8ceceb67986b028815302762b2feefa34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreira?= Date: Sat, 24 Oct 2020 16:25:25 +0100 Subject: [PATCH 01/59] fix ClassTag cache leak JDK issues about the problem: * https://bugs.openjdk.java.net/browse/JDK-8136353 --- src/library/scala/reflect/ClassTag.scala | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala index 0c262954e24c..03548a6cec81 100644 --- a/src/library/scala/reflect/ClassTag.scala +++ b/src/library/scala/reflect/ClassTag.scala @@ -14,6 +14,7 @@ package scala package reflect import java.lang.{ Class => jClass } +import java.lang.ref.{WeakReference => jWeakReference} import scala.collection.mutable import scala.runtime.BoxedUnit @@ -136,15 +137,15 @@ object ClassTag { val Nothing : ClassTag[scala.Nothing] = Manifest.Nothing val Null : ClassTag[scala.Null] = Manifest.Null - private[this] val cache = new ClassValue[ClassTag[_]] { - override def computeValue(runtimeClass: jClass[_]): ClassTag[_] = { - runtimeClass match { + private[this] val cache = new ClassValue[jWeakReference[ClassTag[_]]] { + override def computeValue(runtimeClass: jClass[_]): jWeakReference[ClassTag[_]] = { + new jWeakReference(runtimeClass match { case x if x.isPrimitive => primitiveClassTag(runtimeClass) case ObjectTYPE => ClassTag.Object case NothingTYPE => ClassTag.Nothing case NullTYPE => ClassTag.Null case _ => new GenericClassTag[AnyRef](runtimeClass) - } + }) } private def primitiveClassTag[T](runtimeClass: Class[_]): ClassTag[_] = runtimeClass match { @@ -168,7 +169,15 @@ object ClassTag { } } - def apply[T](runtimeClass1: jClass[_]): ClassTag[T] = cache.get(runtimeClass1).asInstanceOf[ClassTag[T]] + def apply[T](runtimeClass1: jClass[_]): ClassTag[T] = { + val ref = cache.get(runtimeClass1).asInstanceOf[jWeakReference[ClassTag[T]]] + var tag = ref.get + if (tag == null) { + cache.remove(runtimeClass1) + tag = cache.get(runtimeClass1).asInstanceOf[jWeakReference[ClassTag[T]]].get + } + tag + } def unapply[T](ctag: ClassTag[T]): Option[Class[_]] = Some(ctag.runtimeClass) } From 79ae2603594d64a3908dcadc78199d0e34743cba Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 4 Nov 2020 13:45:56 +1000 Subject: [PATCH 02/59] [backport] Make annotation typechecking lazier Now that `Typer.stabilize` ends up checking for `@uncheckedStable` annotations to support defs's as stable paths, new opportunities arise for cyclic errors. This PR reduces the likelihood of cycles by typechecking the only core of an annotation (_not_ the full application to the annotation arguments) to determine its type symbol. pos/unchecked-stable-cyclic-error.scala test case started to fail since #8338 with: ``` |-- object Test BYVALmode-EXPRmode (site: package ) | |-- super APPSELmode-EXPRmode-POLYmode-QUALmode (silent: in Test) | | |-- this EXPRmode (silent: in Test) | | | \-> Test.type | | \-> Test.type | |-- def foo BYVALmode-EXPRmode (site: object Test) | | |-- attr EXPRmode (site: method foo in Test) | | | |-- Int TYPEmode (site: method attr in Test) | | | | \-> Int | | | |-- new anno APPSELmode-BYVALmode-EXPRmode-FUNmode-POLYmode (site: object Test) | | | | |-- new anno APPSELmode-EXPRmode-POLYmode-QUALmode (site: object Test) | | | | | |-- anno FUNmode-TYPEmode (site: object Test) | | | | | | \-> anno | | | | | \-> anno | | | | \-> (a: Any): anno | | | |-- (a: Any): anno : pt=anno EXPRmode (site: value in Test) | | | | |-- foo : pt=Any BYVALmode-EXPRmode (site: value in Test) | | | | | caught scala.reflect.internal.Symbols$CyclicReference: illegal cyclic reference involving method foo: while typing foo /Users/jz/code/scala/sandbox/test.scala:7: error: recursive method foo needs result type @anno(foo) def attr: Int = foo ^ | | | | \-> anno ``` Another variant, pos/annotation-cycle.scala, fails only on 2.12.x (after the backport of #8338). Backporting this fix makes that test start passing on 2.12.x. Backports #9302 --- .../scala/tools/nsc/typechecker/Namers.scala | 23 +++++-- .../reflect/internal/AnnotationInfos.scala | 10 +++- test/files/pos/annotation-cycle.scala | 7 +++ test/files/pos/t11870.scala | 60 +++++++++++++++++++ .../pos/unchecked-stable-cyclic-error.scala | 8 +++ 5 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 test/files/pos/annotation-cycle.scala create mode 100644 test/files/pos/t11870.scala create mode 100644 test/files/pos/unchecked-stable-cyclic-error.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index a88b296bb77c..60de89831879 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1883,11 +1883,24 @@ trait Namers extends MethodSynthesis { annotations filterNot (_ eq null) map { ann => val ctx = typer.context // need to be lazy, #1782. enteringTyper to allow inferView in annotation args, scala/bug#5892. - AnnotationInfo lazily { - enteringTyper { - val annotSig = newTyper(ctx.makeNonSilent(ann)).typedAnnotation(ann, Some(annotee)) - if (pred(annotSig)) annotSig else UnmappableAnnotation // UnmappableAnnotation will be dropped in typedValDef and typedDefDef - } + def computeInfo: AnnotationInfo = enteringTyper { + val annotSig = newTyper(ctx.makeNonSilent(ann)).typedAnnotation(ann, Some(annotee)) + if (pred(annotSig)) annotSig else UnmappableAnnotation // UnmappableAnnotation will be dropped in typedValDef and typedDefDef + } + ann match { + case treeInfo.Applied(Select(New(tpt), _), _, _) => + // We can defer typechecking the arguments of annotations. This is important to avoid cycles in + // checking `hasAnnotation(UncheckedStable)` during typechecking. + def computeSymbol = enteringTyper { + val tptCopy = tpt.duplicate + val silentTyper = newTyper(ctx.makeSilent(newtree = tptCopy)) + // Discard errors here, we'll report them in `computeInfo`. + val tpt1 = silentTyper.typedTypeConstructor(tptCopy) + tpt1.tpe.finalResultType.typeSymbol + } + AnnotationInfo.lazily(computeSymbol, computeInfo) + case _ => + AnnotationInfo.lazily(computeInfo) } } diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index e438b2d67714..6ed497528f7a 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -175,6 +175,9 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => def lazily(lazyInfo: => AnnotationInfo) = new LazyAnnotationInfo(lazyInfo) + def lazily(lazySymbol: => Symbol, lazyInfo: => AnnotationInfo) = + new ExtraLazyAnnotationInfo(lazySymbol, lazyInfo) + def apply(atp: Type, args: List[Tree], assocs: List[(Name, ClassfileAnnotArg)]): AnnotationInfo = new CompleteAnnotationInfo(atp, args, assocs) @@ -219,7 +222,7 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => /** Symbol annotations parsed in `Namer` (typeCompleter of * definitions) have to be lazy (#1782) */ - final class LazyAnnotationInfo(lazyInfo: => AnnotationInfo) extends AnnotationInfo { + class LazyAnnotationInfo(lazyInfo: => AnnotationInfo) extends AnnotationInfo { private var forced = false private lazy val forcedInfo = try lazyInfo finally forced = true @@ -237,6 +240,11 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => override def completeInfo(): Unit = forcedInfo } + final class ExtraLazyAnnotationInfo(sym: => Symbol, lazyInfo: => AnnotationInfo) extends LazyAnnotationInfo(lazyInfo) { + private[this] lazy val typeSymbol = sym + override def symbol: Symbol = typeSymbol + } + /** Typed information about an annotation. It can be attached to either * a symbol or an annotated type. * diff --git a/test/files/pos/annotation-cycle.scala b/test/files/pos/annotation-cycle.scala new file mode 100644 index 000000000000..1c4aa6e79551 --- /dev/null +++ b/test/files/pos/annotation-cycle.scala @@ -0,0 +1,7 @@ +import scala.annotation.StaticAnnotation + +class anno(attr: Boolean) extends StaticAnnotation + +object Test { + @anno(attr = true) def attr: Int = 1 +} diff --git a/test/files/pos/t11870.scala b/test/files/pos/t11870.scala new file mode 100644 index 000000000000..d566e866c1d3 --- /dev/null +++ b/test/files/pos/t11870.scala @@ -0,0 +1,60 @@ +class Annot(arg: Any) extends scala.annotation.StaticAnnotation + +abstract class Demo1 { + @Annot(x) + def x: String = "foo" +} + +abstract class Demo2 { + @Annot(y) + def x: String = "foo" + + @Annot(x) + def y: String = "bar" +} + +class Annot1(arg: Any) extends scala.annotation.StaticAnnotation +class Annot2(arg: Any) extends scala.annotation.StaticAnnotation + +abstract class Demo3 { + @Annot1(y) + def x: String = "foo" + + @Annot2(x) + def y: String = "bar" +} + +// test annotations without argument +import scala.annotation.unchecked + +class C { + class D +} + +class Test { + locally { + val c = new C + import c._ + new D + } + + locally { + import unchecked.uncheckedStable + @uncheckedStable def c = new C + import c._ + new D + } + + locally { + @unchecked.uncheckedStable def c = new C + import c._ + new D + } + + locally { + import unchecked.{uncheckedStable => uc} + @uc def c = new C + import c._ + new D + } +} diff --git a/test/files/pos/unchecked-stable-cyclic-error.scala b/test/files/pos/unchecked-stable-cyclic-error.scala new file mode 100644 index 000000000000..db320c3c6d56 --- /dev/null +++ b/test/files/pos/unchecked-stable-cyclic-error.scala @@ -0,0 +1,8 @@ +import scala.annotation.StaticAnnotation + +class anno(a: Any) extends StaticAnnotation + +object Test { + def foo = attr + @anno(foo) def attr: Int = foo +} From c18fb61ac73311b6e6c32e5d3a68e8976cb0d9ed Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 2 Nov 2020 16:04:57 +1000 Subject: [PATCH 03/59] Avoid possible NPE in ClassTag cache's weak reference --- build.sbt | 1 + src/library/scala/reflect/ClassTag.scala | 29 +++++++++++++++--------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/build.sbt b/build.sbt index e50c3016fa3b..32349c963726 100644 --- a/build.sbt +++ b/build.sbt @@ -567,6 +567,7 @@ val mimaFilterSettings = Seq { ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.api.Internals#InternalApi.markForAsyncTransform"), ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.ZipArchive.RootEntry"), + ProblemFilters.exclude[MissingClassProblem]("scala.reflect.ClassTag$cache$"), ) } diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala index 03548a6cec81..0dec26f43042 100644 --- a/src/library/scala/reflect/ClassTag.scala +++ b/src/library/scala/reflect/ClassTag.scala @@ -137,16 +137,19 @@ object ClassTag { val Nothing : ClassTag[scala.Nothing] = Manifest.Nothing val Null : ClassTag[scala.Null] = Manifest.Null - private[this] val cache = new ClassValue[jWeakReference[ClassTag[_]]] { - override def computeValue(runtimeClass: jClass[_]): jWeakReference[ClassTag[_]] = { - new jWeakReference(runtimeClass match { + private val cacheDisabledProp = scala.sys.Prop[String]("scala.reflect.classtag.cache.disable") + private[this] object cache extends ClassValue[jWeakReference[ClassTag[_]]] { + override def computeValue(runtimeClass: jClass[_]): jWeakReference[ClassTag[_]] = + new jWeakReference(computeTag(runtimeClass)) + + def computeTag(runtimeClass: jClass[_]): ClassTag[_] = + runtimeClass match { case x if x.isPrimitive => primitiveClassTag(runtimeClass) case ObjectTYPE => ClassTag.Object case NothingTYPE => ClassTag.Nothing case NullTYPE => ClassTag.Null case _ => new GenericClassTag[AnyRef](runtimeClass) - }) - } + } private def primitiveClassTag[T](runtimeClass: Class[_]): ClassTag[_] = runtimeClass match { case java.lang.Byte.TYPE => ClassTag.Byte @@ -170,13 +173,17 @@ object ClassTag { } def apply[T](runtimeClass1: jClass[_]): ClassTag[T] = { - val ref = cache.get(runtimeClass1).asInstanceOf[jWeakReference[ClassTag[T]]] - var tag = ref.get - if (tag == null) { - cache.remove(runtimeClass1) - tag = cache.get(runtimeClass1).asInstanceOf[jWeakReference[ClassTag[T]]].get + if (cacheDisabledProp.isSet) + cache.computeTag(runtimeClass1).asInstanceOf[ClassTag[T]] + else { + val ref = cache.get(runtimeClass1).asInstanceOf[jWeakReference[ClassTag[T]]] + var tag = ref.get + if (tag == null) { + cache.remove(runtimeClass1) + tag = cache.computeTag(runtimeClass1).asInstanceOf[ClassTag[T]] + } + tag } - tag } def unapply[T](ctag: ClassTag[T]): Option[Class[_]] = Some(ctag.runtimeClass) From b5e6d54a288963fe07eb01bdf230a0ad8eb7d613 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 11 Nov 2020 10:10:26 +1000 Subject: [PATCH 04/59] Avoid use of binary incompatbile super accessors in SortedMap/Set --- build.sbt | 4 ++++ src/library/scala/collection/GenMap.scala | 21 ++++++++++++++++++ src/library/scala/collection/GenMapLike.scala | 22 ++----------------- src/library/scala/collection/GenSet.scala | 7 ++++++ src/library/scala/collection/GenSetLike.scala | 7 ++---- .../collection/immutable/SortedMap.scala | 6 ++++- .../collection/immutable/SortedSet.scala | 5 ++++- .../tools/nsc/backend/jvm/BytecodeTest.scala | 13 +++++++++++ 8 files changed, 58 insertions(+), 27 deletions(-) diff --git a/build.sbt b/build.sbt index 5aa5f6aacc37..c48104f6fea8 100644 --- a/build.sbt +++ b/build.sbt @@ -568,7 +568,11 @@ val mimaFilterSettings = Seq { ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.api.Internals#InternalApi.markForAsyncTransform"), ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.mutable.HashMap.entriesIterator0"), ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.ZipArchive.RootEntry"), + ProblemFilters.exclude[MissingClassProblem]("scala.reflect.ClassTag$cache$"), + + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.GenSet.setEquals"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.GenMap.mapEquals"), ) } diff --git a/src/library/scala/collection/GenMap.scala b/src/library/scala/collection/GenMap.scala index d2eb28da9df9..fadbd494b599 100644 --- a/src/library/scala/collection/GenMap.scala +++ b/src/library/scala/collection/GenMap.scala @@ -14,6 +14,7 @@ package scala package collection import generic._ +import scala.runtime.AbstractFunction1 /** A trait for all traversable collections which may possibly * have their operations implemented in parallel. @@ -39,4 +40,24 @@ object GenMap extends GenMapFactory[GenMap] { ReusableCBF.asInstanceOf[CanBuildFrom[Coll, (K, V), GenMap[K, V]]] private[this] val ReusableCBF = new MapCanBuildFrom[Nothing, Nothing] + private[collection] def mapEquals[K1, V, K2](thisMap: GenMapLike[K1, V, _], thatMap: GenMap[K2, _]): Boolean = { + (thisMap eq thatMap) || + (thatMap canEqual thisMap) && + (thisMap.size == thatMap.size) && { + try { + val checker = new AbstractFunction1[(K1, V),Boolean] with Function0[V]{ + override def apply(kv: (K1,V)): Boolean = { + // Note: uncurry optimizes this to `get.getOrElse(..., this: Function0)`; there is no extra lambda allocated. + val v2 = thatMap.getOrElse(kv._1.asInstanceOf[K2], this.apply()) + // A mis-behaving user-defined equals method might not expect the sentinel value, and we should try to limit + // the chance of it escaping. Its also probably quicker to avoid the virtual call to equals. + (v2.asInstanceOf[AnyRef] ne this) && v2 == kv._2 + } + override def apply(): V = this.asInstanceOf[V] + } + thisMap forall checker + } catch { + case ex: ClassCastException => false + }} + } } diff --git a/src/library/scala/collection/GenMapLike.scala b/src/library/scala/collection/GenMapLike.scala index 8d0133a2d2cc..675ab68c782c 100644 --- a/src/library/scala/collection/GenMapLike.scala +++ b/src/library/scala/collection/GenMapLike.scala @@ -13,8 +13,6 @@ package scala package collection -import scala.runtime.AbstractFunction1 - /** A trait for all maps upon which operations may be * implemented in parallel. * @@ -117,25 +115,9 @@ trait GenMapLike[K, +V, +Repr] extends GenIterableLike[(K, V), Repr] with Equals * same mappings, `false` otherwise. */ override def equals(that: Any): Boolean = that match { + // copy/pasted to immutable.SortedMap.equals for binary compat reasons! case that: GenMap[b, _] => - (this eq that) || - (that canEqual this) && - (this.size == that.size) && { - try { - val checker = new AbstractFunction1[(K, V),Boolean] with Function0[V]{ - override def apply(kv: (K,V)): Boolean = { - // Note: uncurry optimizes this to `get.getOrElse(..., this: Function0)`; there is no extra lambda allocated. - val v2 = that.getOrElse(kv._1.asInstanceOf[b], this.apply()) - // A mis-behaving user-defined equals method might not expect the sentinel value, and we should try to limit - // the chance of it escaping. Its also probably quicker to avoid the virtual call to equals. - (v2.asInstanceOf[AnyRef] ne this) && v2 == kv._2 - } - override def apply(): V = this.asInstanceOf[V] - } - this forall checker - } catch { - case ex: ClassCastException => false - }} + GenMap.mapEquals(this, that) case _ => false } diff --git a/src/library/scala/collection/GenSet.scala b/src/library/scala/collection/GenSet.scala index a18ee461b90c..ffe9b8644804 100644 --- a/src/library/scala/collection/GenSet.scala +++ b/src/library/scala/collection/GenSet.scala @@ -37,5 +37,12 @@ extends GenSetLike[A, GenSet[A]] object GenSet extends GenTraversableFactory[GenSet] { implicit def canBuildFrom[A] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] def newBuilder[A] = Set.newBuilder + private[collection] def setEquals[A1, A2](thisSet: GenSetLike[A1, _], thatSet: GenSet[A2]): Boolean = { + (thisSet eq thatSet) || + (thatSet canEqual thisSet) && + (thisSet.size == thatSet.size) && + (try thisSet subsetOf thatSet.asInstanceOf[GenSet[A1]] + catch { case ex: ClassCastException => false }) + } } diff --git a/src/library/scala/collection/GenSetLike.scala b/src/library/scala/collection/GenSetLike.scala index 34f26810097a..1b2fa145a11b 100644 --- a/src/library/scala/collection/GenSetLike.scala +++ b/src/library/scala/collection/GenSetLike.scala @@ -117,12 +117,9 @@ extends GenIterableLike[A, Repr] * as this set. */ override def equals(that: Any): Boolean = that match { + // copy/pasted to immutable.SortedSet.equals for binary compat reasons! case that: GenSet[_] => - (this eq that) || - (that canEqual this) && - (this.size == that.size) && - (try this subsetOf that.asInstanceOf[GenSet[A]] - catch { case ex: ClassCastException => false }) + GenSet.setEquals(this, that) case _ => false } diff --git a/src/library/scala/collection/immutable/SortedMap.scala b/src/library/scala/collection/immutable/SortedMap.scala index 7a3744b506f0..59b1d833ab3a 100644 --- a/src/library/scala/collection/immutable/SortedMap.scala +++ b/src/library/scala/collection/immutable/SortedMap.scala @@ -114,7 +114,11 @@ self => allEqual = i1.next() == i2.next() allEqual } - case _ => super.equals(that) + // copy/pasted from super.equals for binary compat reasons! + case that: GenMap[b, _] => + GenMap.mapEquals(this, that) + case _ => + false && super.equals(that) // generate unused super accessor for binary compatibility (scala/scala#9311) } } diff --git a/src/library/scala/collection/immutable/SortedSet.scala b/src/library/scala/collection/immutable/SortedSet.scala index cf7865aa5be0..714302926247 100644 --- a/src/library/scala/collection/immutable/SortedSet.scala +++ b/src/library/scala/collection/immutable/SortedSet.scala @@ -41,8 +41,11 @@ trait SortedSet[A] extends Set[A] with scala.collection.SortedSet[A] with Sorted allEqual = i1.next() == i2.next allEqual } + // copy/pasted from super.equals for binary compat reasons! + case that: GenSet[_] => + GenSet.setEquals(this, that) case _ => - super.equals(that) + false && super.equals(that) // generate unused super accessor for binary compatibility (scala/scala#9311) } } /** $factoryInfo diff --git a/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala b/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala index 31cafe1c8875..7682bdf04084 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala @@ -312,4 +312,17 @@ class BytecodeTest extends BytecodeTesting { val a = A.fields.asScala.find(_.name == "a").get assertEquals(0, a.access & Opcodes.ACC_FINAL) } + + @Test + def sortedSetMapEqualsSuperAccessor(): Unit = { + // ensure super accessors are there (scala/scala#9311) + + val sn = "scala$collection$immutable$SortedSet$$super$equals" + val sm = classOf[scala.collection.immutable.TreeSet[_]].getDeclaredMethod(sn, classOf[Object]) + assertEquals(sn, sm.getName) + + val mn = "scala$collection$immutable$SortedMap$$super$equals" + val mm = classOf[scala.collection.immutable.TreeMap[_, _]].getDeclaredMethod(mn, classOf[Object]) + assertEquals(mn, mm.getName) + } } From 6d609f18623ccee520d1716550b92df026c858cc Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Thu, 29 Oct 2020 09:39:09 +0000 Subject: [PATCH 05/59] [backport] Make the CharSequence wrappers in Predef non-implicit, for JDK 15 In JDK 15 CharSequence has an isEmpty method with a default implementation, which clashes with our Array[Char]#isEmpty, IndexedSeq[Char]#isEmpty, as well as our StringBuilder and reflect's Name. Backport of #9292 from 2.13.x to 2.12.x --- src/library/scala/Predef.scala | 20 ++++++++----- .../collection/mutable/StringBuilder.scala | 9 ++++++ .../scala/reflect/internal/Names.scala | 10 +++++-- .../scala/reflect/internal/StdNames.scala | 2 +- test/files/run/array-charSeq.scala | 2 +- test/junit/scala/ArrayTest.scala | 30 +++++++++++++++++++ 6 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 test/junit/scala/ArrayTest.scala diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala index 4dde2599e727..4569e05b4612 100644 --- a/src/library/scala/Predef.scala +++ b/src/library/scala/Predef.scala @@ -97,9 +97,9 @@ import scala.io.StdIn * @groupprio implicit-classes-any 70 * @groupdesc implicit-classes-any These implicit classes add useful extension methods to every type. * - * @groupname implicit-classes-char CharSequence Conversions - * @groupprio implicit-classes-char 80 - * @groupdesc implicit-classes-char These implicit classes add CharSequence methods to Array[Char] and IndexedSeq[Char] instances. + * @groupname char-sequence-wrappers CharSequence Wrappers + * @groupprio char-sequence-wrappers 80 + * @groupdesc char-sequence-wrappers Wrappers that implements CharSequence and were implicit classes. * * @groupname conversions-java-to-anyval Java to Scala * @groupprio conversions-java-to-anyval 90 @@ -349,22 +349,28 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { // and `@deprecatedName(Symbol(""), "2.12.0")` crashes scalac with // scala.reflect.internal.Symbols$CyclicReference: illegal cyclic reference involving object Symbol // in run/repl-no-imports-no-predef-power.scala. - /** @group implicit-classes-char */ - implicit final class SeqCharSequence(@deprecated("will be made private", "2.12.0") @deprecatedName(null, "2.12.0") val __sequenceOfChars: scala.collection.IndexedSeq[Char]) extends CharSequence { + /** @group char-sequence-wrappers */ + final class SeqCharSequence(@deprecated("will be made private", "2.12.0") @deprecatedName(null, "2.12.0") val __sequenceOfChars: scala.collection.IndexedSeq[Char]) extends CharSequence { def length: Int = __sequenceOfChars.length def charAt(index: Int): Char = __sequenceOfChars(index) def subSequence(start: Int, end: Int): CharSequence = new SeqCharSequence(__sequenceOfChars.slice(start, end)) override def toString = __sequenceOfChars mkString "" } - /** @group implicit-classes-char */ - implicit final class ArrayCharSequence(@deprecated("will be made private", "2.12.0") @deprecatedName(null, "2.12.0") val __arrayOfChars: Array[Char]) extends CharSequence { + /** @group char-sequence-wrappers */ + def SeqCharSequence(sequenceOfChars: scala.collection.IndexedSeq[Char]): SeqCharSequence = new SeqCharSequence(sequenceOfChars) + + /** @group char-sequence-wrappers */ + final class ArrayCharSequence(@deprecated("will be made private", "2.12.0") @deprecatedName(null, "2.12.0") val __arrayOfChars: Array[Char]) extends CharSequence { def length: Int = __arrayOfChars.length def charAt(index: Int): Char = __arrayOfChars(index) def subSequence(start: Int, end: Int): CharSequence = new runtime.ArrayCharSequence(__arrayOfChars, start, end) override def toString = __arrayOfChars mkString "" } + /** @group char-sequence-wrappers */ + def ArrayCharSequence(arrayOfChars: Array[Char]): ArrayCharSequence = new ArrayCharSequence(arrayOfChars) + implicit val StringCanBuildFrom: CanBuildFrom[String, Char, String] = new CanBuildFrom[String, Char, String] { def apply(from: String) = apply() def apply() = mutable.StringBuilder.newBuilder diff --git a/src/library/scala/collection/mutable/StringBuilder.scala b/src/library/scala/collection/mutable/StringBuilder.scala index fb66d97168bd..9e655076c8f3 100644 --- a/src/library/scala/collection/mutable/StringBuilder.scala +++ b/src/library/scala/collection/mutable/StringBuilder.scala @@ -447,6 +447,15 @@ final class StringBuilder(private val underlying: JavaStringBuilder) * @return the string assembled by this StringBuilder */ def result(): String = toString + + + /** Tests whether this builder is empty. + * + * This method is required for JDK15+ compatibility + * + * @return `true` if this builder contains nothing, `false` otherwise. + */ + override def isEmpty: Boolean = underlying.length() == 0 } object StringBuilder { diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala index e133ffb4093c..5ab13cd8cc1e 100644 --- a/src/reflect/scala/reflect/internal/Names.scala +++ b/src/reflect/scala/reflect/internal/Names.scala @@ -188,12 +188,17 @@ trait Names extends api.Names { // Classes ---------------------------------------------------------------------- + // Dummy trait to make Name#isEmpty with override keyword at JDK before 15 + sealed trait NameHasIsEmpty { + def isEmpty: Boolean + } + /** The name class. * TODO - resolve schizophrenia regarding whether to treat Names as Strings * or Strings as Names. Give names the key functions the absence of which * make people want Strings all the time. */ - sealed abstract class Name(protected val index: Int, protected val len: Int, protected val cachedString: String) extends NameApi with CharSequence { + sealed abstract class Name(protected val index: Int, protected val len: Int, protected val cachedString: String) extends NameApi with NameHasIsEmpty with CharSequence { type ThisNameType >: Null <: Name protected[this] def thisName: ThisNameType @@ -209,8 +214,9 @@ trait Names extends api.Names { /** The length of this name. */ final def length: Int = len - final def isEmpty = length == 0 final def nonEmpty = !isEmpty + // This method is implements NameHasIsEmpty, and overrides CharSequence's isEmpty on JDK 15+ + override final def isEmpty = length == 0 def nameKind: String def isTermName: Boolean diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 248ba9f0ad98..3b75e95e7dd4 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -77,7 +77,7 @@ trait StdNames { val suffix = s takeRight edge val cs = s.toArray - val bytes = Codec toUTF8 cs + val bytes = Codec.toUTF8(new scala.runtime.ArrayCharSequence(cs, 0, cs.length)) md5 update bytes val md5chars = (md5.digest() map (b => (b & 0xFF).toHexString)).mkString diff --git a/test/files/run/array-charSeq.scala b/test/files/run/array-charSeq.scala index 53796bb9d571..86bfb829a69e 100644 --- a/test/files/run/array-charSeq.scala +++ b/test/files/run/array-charSeq.scala @@ -1,6 +1,6 @@ object Test { val arr = Array[Char]('a' to 'i': _*) - var xs: CharSequence = arr + var xs: CharSequence = ArrayCharSequence(arr) val hash = xs.hashCode def check(chars: CharSequence) { diff --git a/test/junit/scala/ArrayTest.scala b/test/junit/scala/ArrayTest.scala new file mode 100644 index 000000000000..fbf71dc9d45d --- /dev/null +++ b/test/junit/scala/ArrayTest.scala @@ -0,0 +1,30 @@ +package scala + +import org.junit.Assert.{ assertArrayEquals, assertFalse, assertTrue } +import org.junit.Test + +import scala.runtime.BoxedUnit + +class ArrayTest { + + @Test + def testArrayIsEmpty(): Unit = { + assertTrue(Array[Int]().isEmpty) + assertTrue(Array[Char]().isEmpty) // scala/bug#12172 + assertTrue(Array[String]().isEmpty) + + assertFalse(Array(1).isEmpty) + assertFalse(Array[Char](1).isEmpty) + assertFalse(Array("").isEmpty) + + def ge[T](a: Array[T]) = a.isEmpty + + assertTrue(ge(Array[Int]())) + assertTrue(ge(Array[Char]())) + assertTrue(ge(Array[String]())) + + assertFalse(ge(Array(1))) + assertFalse(ge(Array[Char]('x'))) + assertFalse(ge(Array(""))) + } +} From dd5782f8e01ccf73c80176ed3821245a2ed7d03d Mon Sep 17 00:00:00 2001 From: Darcy Shen Date: Wed, 18 Nov 2020 23:35:35 +0800 Subject: [PATCH 06/59] Catch exceptions --- .../backend/jvm/opt/ByteCodeRepository.scala | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala index b99c8ff6d05a..3a5491f5f40f 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala @@ -274,25 +274,30 @@ abstract class ByteCodeRepository extends PerRunInit { private def parseClass(internalName: InternalName): Either[ClassNotFound, ClassNode] = { val fullName = internalName.replace('/', '.') - backendClassPath.findClassFile(fullName) map { classFile => + backendClassPath.findClassFile(fullName).flatMap { classFile => val classNode = new ClassNode1 val classReader = new asm.ClassReader(classFile.toByteArray) - // Passing the InlineInfoAttributePrototype makes the ClassReader invoke the specific `read` - // method of the InlineInfoAttribute class, instead of putting the byte array into a generic - // Attribute. - // We don't need frames when inlining, but we want to keep the local variable table, so we - // don't use SKIP_DEBUG. - classReader.accept(classNode, Array[Attribute](InlineInfoAttributePrototype), asm.ClassReader.SKIP_FRAMES) - // SKIP_FRAMES leaves line number nodes. Remove them because they are not correct after - // inlining. - // TODO: we need to remove them also for classes that are not parsed from classfiles, why not simplify and do it once when inlining? - // OR: instead of skipping line numbers for inlined code, use write a SourceDebugExtension - // attribute that contains JSR-45 data that encodes debugging info. - // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.11 - // https://jcp.org/aboutJava/communityprocess/final/jsr045/index.html - removeLineNumbersAndAddLMFImplMethods(classNode) - classNode + try { + // Passing the InlineInfoAttributePrototype makes the ClassReader invoke the specific `read` + // method of the InlineInfoAttribute class, instead of putting the byte array into a generic + // Attribute. + // We don't need frames when inlining, but we want to keep the local variable table, so we + // don't use SKIP_DEBUG. + classReader.accept(classNode, Array[Attribute](InlineInfoAttributePrototype), asm.ClassReader.SKIP_FRAMES) + // SKIP_FRAMES leaves line number nodes. Remove them because they are not correct after + // inlining. + // TODO: we need to remove them also for classes that are not parsed from classfiles, why not simplify and do it once when inlining? + // OR: instead of skipping line numbers for inlined code, use write a SourceDebugExtension + // attribute that contains JSR-45 data that encodes debugging info. + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.11 + // https://jcp.org/aboutJava/communityprocess/final/jsr045/index.html + removeLineNumbersAndAddLMFImplMethods(classNode) + Some(classNode) + } catch { + case e: Exception => + None + } } match { case Some(node) => Right(node) case None => Left(ClassNotFound(internalName, javaDefinedClasses.get(internalName))) From b10abb48eb4ab3b56492e8f7f021c1880231d78d Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Wed, 18 Nov 2020 10:19:23 -0800 Subject: [PATCH 07/59] deprecate ArrayCharSequence as per discussion on scala/scala#9292 --- src/library/scala/Predef.scala | 3 ++- src/library/scala/runtime/SeqCharSequence.scala | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala index 4569e05b4612..e9194d34a12b 100644 --- a/src/library/scala/Predef.scala +++ b/src/library/scala/Predef.scala @@ -361,6 +361,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { def SeqCharSequence(sequenceOfChars: scala.collection.IndexedSeq[Char]): SeqCharSequence = new SeqCharSequence(sequenceOfChars) /** @group char-sequence-wrappers */ + @deprecated("use `java.nio.CharBuffer.wrap` instead", "2.12.13") final class ArrayCharSequence(@deprecated("will be made private", "2.12.0") @deprecatedName(null, "2.12.0") val __arrayOfChars: Array[Char]) extends CharSequence { def length: Int = __arrayOfChars.length def charAt(index: Int): Char = __arrayOfChars(index) @@ -553,7 +554,7 @@ private[scala] trait DeprecatedPredef { @deprecated("use `StringFormat`", "2.11.0") def any2stringfmt(x: Any): StringFormat[Any] = new StringFormat(x) @deprecated("use `Throwable` directly", "2.11.0") def exceptionWrapper(exc: Throwable) = new RichException(exc) @deprecated("use `SeqCharSequence`", "2.11.0") def seqToCharSequence(xs: scala.collection.IndexedSeq[Char]): CharSequence = new SeqCharSequence(xs) - @deprecated("use `ArrayCharSequence`", "2.11.0") def arrayToCharSequence(xs: Array[Char]): CharSequence = new ArrayCharSequence(xs) + @deprecated("use `java.nio.CharBuffer.wrap`", "2.11.0") def arrayToCharSequence(xs: Array[Char]): CharSequence = new ArrayCharSequence(xs) @deprecated("use the method in `scala.io.StdIn`", "2.11.0") def readLine(): String = StdIn.readLine() @deprecated("use the method in `scala.io.StdIn`", "2.11.0") def readLine(text: String, args: Any*) = StdIn.readLine(text, args: _*) diff --git a/src/library/scala/runtime/SeqCharSequence.scala b/src/library/scala/runtime/SeqCharSequence.scala index a53e0001147d..f14aab284ea0 100644 --- a/src/library/scala/runtime/SeqCharSequence.scala +++ b/src/library/scala/runtime/SeqCharSequence.scala @@ -21,8 +21,7 @@ final class SeqCharSequence(val xs: scala.collection.IndexedSeq[Char]) extends C override def toString = xs.mkString("") } -// Still need this one since the implicit class ArrayCharSequence only converts -// a single argument. +@deprecated("use `java.nio.CharBuffer.wrap` instead", "2.12.13") final class ArrayCharSequence(val xs: Array[Char], start: Int, end: Int) extends CharSequence { // yikes // java.lang.VerifyError: (class: scala/runtime/ArrayCharSequence, method: signature: ([C)V) From 398a94c2350c4f188bf16af1d3ea6b89ae7877bb Mon Sep 17 00:00:00 2001 From: Darcy Shen Date: Thu, 19 Nov 2020 19:11:23 +0800 Subject: [PATCH 08/59] Logging --- .../tools/nsc/backend/jvm/opt/ByteCodeRepository.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala index 3a5491f5f40f..c19148506f81 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala @@ -17,6 +17,7 @@ package opt import scala.collection.JavaConverters._ import scala.collection.{concurrent, mutable} +import scala.reflect.internal.util.NoPosition import scala.tools.asm import scala.tools.asm.Attribute import scala.tools.asm.tree._ @@ -33,7 +34,7 @@ abstract class ByteCodeRepository extends PerRunInit { import postProcessor.{bTypes, bTypesFromClassfile, callGraph} import bTypes._ - import frontendAccess.{backendClassPath, recordPerRunCache} + import frontendAccess.{backendReporting, backendClassPath, recordPerRunCache} /** * Contains ClassNodes and the canonical path of the source file path of classes being compiled in @@ -295,7 +296,9 @@ abstract class ByteCodeRepository extends PerRunInit { removeLineNumbersAndAddLMFImplMethods(classNode) Some(classNode) } catch { - case e: Exception => + case ex: Exception => + if (frontendAccess.compilerSettings.debug) ex.printStackTrace() + backendReporting.warning(NoPosition, s"Error while reading InlineInfoAttribute from ${fullName}\n${ex.getMessage}") None } } match { From 5e6676d99669fdfe8493cb75a692f90608c873e1 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Sat, 21 Nov 2020 11:53:53 -0800 Subject: [PATCH 09/59] fix regression where Array[Unit].empty caused NPE this regressed in #9091 the problem turned up in the Scala 2.12 community build -- when Scala 3 support was added to the scala-collection-compat repo, a test case there was altered in a way that happened to tickle this --- src/library/scala/reflect/ClassTag.scala | 2 +- test/junit/scala/ArrayTest.scala | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala index 0dec26f43042..c099dfc32b3d 100644 --- a/src/library/scala/reflect/ClassTag.scala +++ b/src/library/scala/reflect/ClassTag.scala @@ -53,7 +53,7 @@ trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serial @transient private[scala] lazy val emptyArray : Array[T] = { val componentType = - if (runtimeClass eq classOf[Void]) classOf[BoxedUnit] else runtimeClass + if (runtimeClass eq java.lang.Void.TYPE) classOf[BoxedUnit] else runtimeClass java.lang.reflect.Array.newInstance(componentType, 0).asInstanceOf[Array[T]] } @transient private[scala] lazy val emptyWrappedArray: mutable.WrappedArray[T] = diff --git a/test/junit/scala/ArrayTest.scala b/test/junit/scala/ArrayTest.scala index fbf71dc9d45d..6bfa9702ae37 100644 --- a/test/junit/scala/ArrayTest.scala +++ b/test/junit/scala/ArrayTest.scala @@ -1,17 +1,20 @@ package scala -import org.junit.Assert.{ assertArrayEquals, assertFalse, assertTrue } +import org.junit.Assert.{ assertFalse, assertTrue } import org.junit.Test -import scala.runtime.BoxedUnit - class ArrayTest { @Test def testArrayIsEmpty(): Unit = { assertTrue(Array[Int]().isEmpty) + assertTrue(Array.empty[Int].isEmpty) assertTrue(Array[Char]().isEmpty) // scala/bug#12172 + assertTrue(Array.empty[Char].isEmpty) assertTrue(Array[String]().isEmpty) + assertTrue(Array.empty[String].isEmpty) + assertTrue(Array[Unit]().isEmpty) + assertTrue(Array.empty[Unit].isEmpty) assertFalse(Array(1).isEmpty) assertFalse(Array[Char](1).isEmpty) From 229793158865ab90a643e9cb95f1c9dcc035a000 Mon Sep 17 00:00:00 2001 From: Tobias Schlatter Date: Tue, 24 Nov 2020 07:39:52 +0100 Subject: [PATCH 10/59] Allow annotated literals inside as annotation args This notably allows for silencing warnings inside annotation arguments (see scala-js/scala-js#3737, ghik/silencer#32). Further, this fixes scala/bug#11932. --- .../scala/reflect/internal/AnnotationInfos.scala | 16 ++++++++++++++-- .../neg/annotated-literal-annotation-arg.check | 7 +++++++ .../neg/annotated-literal-annotation-arg.scala | 16 ++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 test/files/neg/annotated-literal-annotation-arg.check create mode 100644 test/files/neg/annotated-literal-annotation-arg.scala diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index 6ed497528f7a..29b5e21e145a 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -347,8 +347,20 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => // !!! when annotation arguments are not literals, but any sort of // expression, there is a fair chance they will turn up here not as // Literal(const) but some arbitrary AST. - def constantAtIndex(index: Int): Option[Constant] = - argAtIndex(index) collect { case Literal(x) => x } + // + // We recurse over Typed / Annotated trees to allow things like: + // `@implicitNotFound("$foo": @nowarn)` + def constantAtIndex(index: Int): Option[Constant] = { + @tailrec + def lit(tree: Tree): Option[Constant] = tree match { + case Literal(c) => Some(c) + case Typed(t, _) => lit(t) + case Annotated(_, t) => lit(t) + case _ => None + } + + argAtIndex(index).flatMap(lit) + } def argAtIndex(index: Int): Option[Tree] = if (index < args.size) Some(args(index)) else None diff --git a/test/files/neg/annotated-literal-annotation-arg.check b/test/files/neg/annotated-literal-annotation-arg.check new file mode 100644 index 000000000000..e4d377d0ff5d --- /dev/null +++ b/test/files/neg/annotated-literal-annotation-arg.check @@ -0,0 +1,7 @@ +annotated-literal-annotation-arg.scala:14: error: $foo + implicitly[Foo] + ^ +annotated-literal-annotation-arg.scala:15: error: bar + implicitly[Bar] + ^ +two errors found diff --git a/test/files/neg/annotated-literal-annotation-arg.scala b/test/files/neg/annotated-literal-annotation-arg.scala new file mode 100644 index 000000000000..92a089f5948f --- /dev/null +++ b/test/files/neg/annotated-literal-annotation-arg.scala @@ -0,0 +1,16 @@ + +import annotation.implicitNotFound +import scala.annotation.nowarn + +// Ensure that an annotation doesn't break the message +@implicitNotFound("$foo": @nowarn) +trait Foo + +// Ensure that a type ascription doesn't break the message +@implicitNotFound("bar": String) +trait Bar + +object Example { + implicitly[Foo] + implicitly[Bar] +} From 892a56d9855d5c8fee6f49ab409b2f5849719abd Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 2 Dec 2020 10:09:33 +1000 Subject: [PATCH 11/59] Test showing position bug with `var x = _` The `= _` should be include in the range position of the ValDef. --- .../scala/tools/nsc/parser/ParserTest.scala | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/junit/scala/tools/nsc/parser/ParserTest.scala b/test/junit/scala/tools/nsc/parser/ParserTest.scala index e4fed1e7b1b7..37d590b141e4 100644 --- a/test/junit/scala/tools/nsc/parser/ParserTest.scala +++ b/test/junit/scala/tools/nsc/parser/ParserTest.scala @@ -3,6 +3,7 @@ package scala.tools.nsc.parser import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +import org.junit.Assert._ import scala.tools.testing.BytecodeTesting @@ -29,4 +30,19 @@ class ParserTest extends BytecodeTesting{ assert(!reporter.hasErrors) run.compileSources(newSourceFile(crlfCode) :: Nil) } + + @Test + def rangePosOfDefaultInitializer_t12213(): Unit = { + val code = + """object Other { var x: Int = _; var y: Int = 42 }""" + import compiler._, global._ + val run = new Run + run.compileSources(newSourceFile(code) :: Nil) + assert(!reporter.hasErrors) + val unit = run.units.toList.head + def codeOf(pos: Position) = new String(pos.source.content.slice(pos.start, pos.end)) + val List(x, y) = unit.body.collect { case vd : ValDef => vd }.takeRight(2) + assertEquals("var y: Int = 42", codeOf(y.pos)) + assertEquals("var x: Int", codeOf(x.pos)) // TODO fix parser to include `= _` + } } From 26ceba64ac465679921caa8753165fdea699b93f Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Fri, 4 Dec 2020 11:26:18 +1000 Subject: [PATCH 12/59] Remove pack200 ant task to make 2.12.x compilable on JDK 15 Removed from the JDK: https://openjdk.java.net/jeps/367 Ant support has been removed totally in 2.13.x, but remains in 2.12.x. Of the small number of remaining 2.12.x / Ant users, I suspect the number using the pack200 task is approximately zero. --- .../scala/tools/ant/Pack200Task.scala | 173 ------------------ src/compiler/scala/tools/ant/antlib.xml | 2 - 2 files changed, 175 deletions(-) delete mode 100644 src/compiler/scala/tools/ant/Pack200Task.scala diff --git a/src/compiler/scala/tools/ant/Pack200Task.scala b/src/compiler/scala/tools/ant/Pack200Task.scala deleted file mode 100644 index 653e5328efbe..000000000000 --- a/src/compiler/scala/tools/ant/Pack200Task.scala +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala.tools.ant - -import java.io.{BufferedOutputStream, File, FileOutputStream} -import java.util.jar.{JarFile, JarOutputStream, Pack200} -import java.util.jar.Pack200.Packer._ - -/** An [[http://ant.apache.org Ant]] task that applies the pack200 encoding - * to a JAR file. - * - * - `destdir` (mandatory), - * - `dir` (defaults to project's basedir), - * - `effort` (default 9), - * - `keepFileOrder` (default `'''false'''`), - * - `keepModificationTime` (default `'''false'''`), - * - `repack` (default false), - * - `segmentLimit` (default `-1` for no limit), - * - `suffix` (default ".pack") - * - * @author James Matlik - */ -class Pack200Task extends ScalaMatchingTask { - -/*============================================================================*\ -** Ant user-properties ** -\*============================================================================*/ - - var destdir: Option[File] = None - var srcdir: Option[File] = None - - var effort = 9 - var keepFileOrder = false - var keepModificationTime = false - var repack = false - var segmentLimit = -1 - - var packFileSuffix = ".pack" - - -/*============================================================================*\ -** Properties setters ** -\*============================================================================*/ - - def setDir(dir: File) { - if (dir.exists && dir.isDirectory) srcdir = Some(dir) - else buildError("Please specify a valid directory with Jar files for packing.") - } - - /** A level from 0 (none) to 9 (max) of effort for applying Pack200 */ - def setEffort(x: Int) { - if (effort < 10 && effort > -1) effort = x - else buildError("The effort level must be a value from 0 to 9") - } - - /** Set the flag to specify if file reordering should be performed. Reordering - * is used to remove empty packages and improve pack200 optimization. - * @param x - * `'''true'''` to retain file ordering. - * `'''false'''` to optimize directory structure (DEFAULT). */ - def setKeepFileOrder(x: Boolean) { keepFileOrder = x } - - /** If false, a single modification time is used for all contained files */ - def setKeepModificationTime(x: Boolean) { keepModificationTime = x } - - /** A flag that tells the task to pack and then unpack the source JAR file - * into another JAR file. This resulting JAR file can then be signed, - * packed again, compressed and distributed for securely distributed code. - */ - def setRepack(r: Boolean) { repack = r } - - - def setSegmentLimit(size: Int) { segmentLimit = size } - - /** Set the output directory */ - def setDestdir(file: File) { - if (file != null && file.exists && file.isDirectory) destdir = Some(file) - else buildError("The destination directory is invalid: " + file.getAbsolutePath) - } - - def setSuffix(s: String) { packFileSuffix = s } - -/*============================================================================*\ -** Properties getters ** -\*============================================================================*/ - - /** Gets the list of individual JAR files for processing. - * @return The list of JAR files */ - private def getFileList: List[File] = { - var files: List[File] = Nil - val fs = getImplicitFileSet - 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) - if(files.exists(file.equals(_)) == false) files = file :: files - } - files.reverse - } - -/*============================================================================*\ -** Compilation and support methods ** -\*============================================================================*/ - - private def makeJarOutputStream(file: File) = - new JarOutputStream(makeOutputStream(file)) - - private def makeOutputStream(file: File) = - new BufferedOutputStream(new FileOutputStream(file)) - -/*============================================================================*\ -** The big execute method ** -\*============================================================================*/ - - /** Performs the tool creation. */ - override def execute() = { - // Audits - val packDir = destdir.getOrElse(buildError("No output directory specified")) - - // Setup the inherited fileset for further processing - fileset.setDir(srcdir.getOrElse(getProject.getBaseDir)) - - val files = getFileList - if (files.isEmpty) buildError("No JAR files were selected for packing.") - - // Setup the packer - val packer = Pack200.newPacker - val p = packer.properties - p.put(EFFORT, effort.toString) - p.put(SEGMENT_LIMIT, segmentLimit.toString) - p.put(KEEP_FILE_ORDER, if(keepFileOrder) TRUE else FALSE) - p.put(MODIFICATION_TIME, if(keepModificationTime) LATEST else KEEP) - - for (file <- files) { - if (repack) { - val repackedFile = new File(packDir, file.getName) - if (file.lastModified > repackedFile.lastModified) { - println("Repacking " + file.toString + " to " + repackedFile.toString) - val tmpFile = new File(packDir, file.getName + ".tmp") - val os = makeOutputStream(tmpFile) - packer.pack(new JarFile(file), os) - os.close() - val jos = makeJarOutputStream(repackedFile) - Pack200.newUnpacker.unpack(tmpFile, jos) - jos.close() - tmpFile.delete() - } - } - else { - val packFile: File = { - val name = file.getName.substring(0, file.getName.lastIndexOf(".")) - new File(packDir, name + packFileSuffix) - } - if(file.lastModified > packFile.lastModified) { - println("Packing " + file.toString + " to " + packFile.toString) - val os = makeOutputStream(packFile) - packer.pack(new JarFile(file), os) - } - } - } - } -} diff --git a/src/compiler/scala/tools/ant/antlib.xml b/src/compiler/scala/tools/ant/antlib.xml index 7885534689e7..e3c3e370c6f7 100644 --- a/src/compiler/scala/tools/ant/antlib.xml +++ b/src/compiler/scala/tools/ant/antlib.xml @@ -11,6 +11,4 @@ classname="scala.tools.ant.Scaladoc"/> - From f4f64913061f99a0501095df71d9d878f484c90a Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Fri, 4 Dec 2020 13:09:23 +1000 Subject: [PATCH 13/59] Only look up the system prop controlling class tag caching once --- src/library/scala/reflect/ClassTag.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala index c099dfc32b3d..9158fbc514ed 100644 --- a/src/library/scala/reflect/ClassTag.scala +++ b/src/library/scala/reflect/ClassTag.scala @@ -137,7 +137,7 @@ object ClassTag { val Nothing : ClassTag[scala.Nothing] = Manifest.Nothing val Null : ClassTag[scala.Null] = Manifest.Null - private val cacheDisabledProp = scala.sys.Prop[String]("scala.reflect.classtag.cache.disable") + private val cacheDisabled = java.lang.Boolean.getBoolean("scala.reflect.classtag.cache.disable") private[this] object cache extends ClassValue[jWeakReference[ClassTag[_]]] { override def computeValue(runtimeClass: jClass[_]): jWeakReference[ClassTag[_]] = new jWeakReference(computeTag(runtimeClass)) @@ -173,9 +173,9 @@ object ClassTag { } def apply[T](runtimeClass1: jClass[_]): ClassTag[T] = { - if (cacheDisabledProp.isSet) + if (cacheDisabled) { cache.computeTag(runtimeClass1).asInstanceOf[ClassTag[T]] - else { + } else { val ref = cache.get(runtimeClass1).asInstanceOf[jWeakReference[ClassTag[T]]] var tag = ref.get if (tag == null) { From 7d81f22f4e7738f864dff3f3b86ae0f131149eec Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 2 Dec 2020 10:49:59 +1000 Subject: [PATCH 14/59] Fix and extend Array.apply varargs optimization The existing optimization for `Array.apply[T]` overreaches by assuming that the `ArrayValue` carrying the varargs will have the same element type as the implicit class tag. However, this is not the case when the type argument is a generic type: ``` scala> def foo[T <: AnyRef : reflect.ClassTag](t: T) = Array.apply[T](t); foo[String]("") java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String; ... 32 elided ``` This PR limits the existing optimization to cases where: - The class tag is an implicit arg - The class tag is materialized (not found via normal implicit search) The second criterion excludes the call above. A new, fallback optimization is provided that avoids a temporary array and collection wrapper by emitting: ``` val arr = classTag.newArray(N) ScalaRunTime.arrayUpdate(arr, N, elemN) ... arr } ``` --- .../scala/tools/nsc/transform/CleanUp.scala | 24 ++++++++++++++++--- .../scala/reflect/internal/Definitions.scala | 1 + test/files/instrumented/t11882a.check | 8 +++++++ test/files/instrumented/t11882a.scala | 23 ++++++++++++++++++ test/files/instrumented/t11882b.check | 8 +++++++ test/files/instrumented/t11882b.scala | 23 ++++++++++++++++++ test/files/instrumented/t11882c.check | 2 ++ test/files/instrumented/t11882c.scala | 14 +++++++++++ test/files/run/t11882-class-cast.scala | 8 +++++++ 9 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 test/files/instrumented/t11882a.check create mode 100644 test/files/instrumented/t11882a.scala create mode 100644 test/files/instrumented/t11882b.check create mode 100644 test/files/instrumented/t11882b.scala create mode 100644 test/files/instrumented/t11882c.check create mode 100644 test/files/instrumented/t11882c.scala create mode 100644 test/files/run/t11882-class-cast.scala diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 5e3a31a36026..7689cc652923 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -486,9 +486,27 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL { // with just `ArrayValue(...).$asInstanceOf[...]` // // See scala/bug#6611; we must *only* do this for literal vararg arrays. - case Apply(appMeth, Apply(wrapRefArrayMeth, (arg @ StripCast(ArrayValue(_, _))) :: Nil) :: _ :: Nil) - if wrapRefArrayMeth.symbol == currentRun.runDefinitions.Predef_wrapRefArray && appMeth.symbol == ArrayModule_genericApply => - super.transform(arg) + case Apply(appMeth, Apply(wrapRefArrayMeth, (arg @ StripCast(ArrayValue(elemtpt, elems))) :: Nil) :: classTagEvidence :: Nil) + if (wrapRefArrayMeth.symbol == currentRun.runDefinitions.Predef_genericWrapRefArray || wrapRefArrayMeth.symbol == currentRun.runDefinitions.Predef_wrapRefArray) && appMeth.symbol == ArrayModule_genericApply && + !elemtpt.tpe.typeSymbol.isBottomClass => + classTagEvidence.attachments.get[analyzer.MacroExpansionAttachment] match { + case Some(att) if att.expandee.symbol.name == nme.materializeClassTag && tree.isInstanceOf[ApplyToImplicitArgs] => + super.transform(arg) + case None => + localTyper.typedPos(tree.pos) { + gen.evalOnce(classTagEvidence, currentOwner, unit) { ev => + val arr = localTyper.typedPos(tree.pos)(gen.mkMethodCall(classTagEvidence, definitions.ClassTagClass.info.decl(nme.newArray), Nil, Literal(Constant(elems.size)) :: Nil)) + gen.evalOnce(arr, currentOwner, unit) { arr => + val stats = mutable.ListBuffer[Tree]() + foreachWithIndex(elems) { (elem, i) => + stats += gen.mkMethodCall(gen.mkAttributedRef(definitions.ScalaRunTimeModule), currentRun.runDefinitions.arrayUpdateMethod, + Nil, arr() :: Literal(Constant(i)) :: elem :: Nil) + } + super.transform(Block(stats.toList, arr())) + } + } + } + } case Apply(appMeth, elem0 :: Apply(wrapArrayMeth, (rest @ ArrayValue(elemtpt, _)) :: Nil) :: Nil) if wrapArrayMeth.symbol == Predef_wrapArray(elemtpt.tpe) && appMeth.symbol == ArrayModule_apply(elemtpt.tpe) => super.transform(treeCopy.ArrayValue(rest, rest.elemtpt, elem0 :: rest.elems)) diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index e2a06440f750..e328345550ee 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -1601,6 +1601,7 @@ trait Definitions extends api.StandardDefinitions { lazy val Predef_implicitly = getMemberMethod(PredefModule, nme.implicitly) lazy val Predef_wrapRefArray = getMemberMethod(PredefModule, nme.wrapRefArray) + lazy val Predef_genericWrapRefArray = getMemberMethod(PredefModule, nme.genericWrapArray) lazy val Predef_??? = DefinitionsClass.this.Predef_??? lazy val arrayApplyMethod = getMemberMethod(ScalaRunTimeModule, nme.array_apply) diff --git a/test/files/instrumented/t11882a.check b/test/files/instrumented/t11882a.check new file mode 100644 index 000000000000..cfb515adcc98 --- /dev/null +++ b/test/files/instrumented/t11882a.check @@ -0,0 +1,8 @@ +Method call statistics: + 1 OptimusSeq$.apply1(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Lscala/reflect/ClassTag;)LOptimusSeq; + 1 OptimusSeq$.unsafeFromAnyArray1([Ljava/lang/Object;)LOptimusSeq; + 1 Test$.doIt$1()LOptimusSeq; + 1 scala/reflect/ClassTag$.AnyRef()Lscala/reflect/ClassTag; + 1 scala/reflect/ManifestFactory$ObjectManifest.newArray(I)Ljava/lang/Object; + 1 scala/reflect/ManifestFactory$ObjectManifest.newArray(I)[Ljava/lang/Object; + 4 scala/runtime/ScalaRunTime$.array_update(Ljava/lang/Object;ILjava/lang/Object;)V diff --git a/test/files/instrumented/t11882a.scala b/test/files/instrumented/t11882a.scala new file mode 100644 index 000000000000..2988791c320b --- /dev/null +++ b/test/files/instrumented/t11882a.scala @@ -0,0 +1,23 @@ +import scala.reflect.ClassTag +import scala.tools.partest.instrumented._ +import scala.tools.partest.instrumented.Instrumentation._ + +class OptimusSeq[T] + +object OptimusSeq { + private def unsafeFromAnyArray1[T <: AnyRef](ts: Array[T]): OptimusSeq[T] = null; + def apply1[T <: AnyRef : ClassTag](p1: T, p2: T, p3: T, p4: T): OptimusSeq[T] = { + unsafeFromAnyArray1(Array(p1, p2, p3, p4)) + } +} + +object Test { + def main(args: Array[String]): Unit = { + def doIt = OptimusSeq.apply1[AnyRef](null, null, null, null) + doIt + startProfiling() + doIt + stopProfiling() + printStatistics() + } +} diff --git a/test/files/instrumented/t11882b.check b/test/files/instrumented/t11882b.check new file mode 100644 index 000000000000..2b4a809e6e7e --- /dev/null +++ b/test/files/instrumented/t11882b.check @@ -0,0 +1,8 @@ +Method call statistics: + 1 OptimusSeq$.apply1(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Lscala/reflect/ClassTag;)LOptimusSeq; + 1 OptimusSeq$.unsafeFromAnyArray1(Ljava/lang/Object;)LOptimusSeq; + 1 Test$.doIt$1()LOptimusSeq; + 1 scala/reflect/ClassTag$.AnyRef()Lscala/reflect/ClassTag; + 1 scala/reflect/ManifestFactory$ObjectManifest.newArray(I)Ljava/lang/Object; + 1 scala/reflect/ManifestFactory$ObjectManifest.newArray(I)[Ljava/lang/Object; + 4 scala/runtime/ScalaRunTime$.array_update(Ljava/lang/Object;ILjava/lang/Object;)V diff --git a/test/files/instrumented/t11882b.scala b/test/files/instrumented/t11882b.scala new file mode 100644 index 000000000000..2f1c33d72a2d --- /dev/null +++ b/test/files/instrumented/t11882b.scala @@ -0,0 +1,23 @@ +import scala.reflect.ClassTag +import scala.tools.partest.instrumented._ +import scala.tools.partest.instrumented.Instrumentation._ + +class OptimusSeq[T] + +object OptimusSeq { + private def unsafeFromAnyArray1[T](ts: Array[T]): OptimusSeq[T] = null; + def apply1[T : ClassTag](p1: T, p2: T, p3: T, p4: T): OptimusSeq[T] = { + unsafeFromAnyArray1(Array(p1, p2, p3, p4)) + } +} + +object Test { + def main(args: Array[String]): Unit = { + def doIt = OptimusSeq.apply1[AnyRef](null, null, null, null) + doIt + startProfiling() + doIt + stopProfiling() + printStatistics() + } +} diff --git a/test/files/instrumented/t11882c.check b/test/files/instrumented/t11882c.check new file mode 100644 index 000000000000..f80f495cf1d3 --- /dev/null +++ b/test/files/instrumented/t11882c.check @@ -0,0 +1,2 @@ +Method call statistics: + 1 Test$.doIt$1()[Ljava/lang/String; diff --git a/test/files/instrumented/t11882c.scala b/test/files/instrumented/t11882c.scala new file mode 100644 index 000000000000..f7b33ad864ed --- /dev/null +++ b/test/files/instrumented/t11882c.scala @@ -0,0 +1,14 @@ +import scala.reflect.ClassTag +import scala.tools.partest.instrumented._ +import scala.tools.partest.instrumented.Instrumentation._ + +object Test { + def main(args: Array[String]): Unit = { + def doIt = Array[String](null, null, null, null) + doIt + startProfiling() + doIt + stopProfiling() + printStatistics() + } +} diff --git a/test/files/run/t11882-class-cast.scala b/test/files/run/t11882-class-cast.scala new file mode 100644 index 000000000000..59221be93fe6 --- /dev/null +++ b/test/files/run/t11882-class-cast.scala @@ -0,0 +1,8 @@ +object Test { + def test[T <: AnyRef: reflect.ClassTag](t: T) = Array(t) + def main(args: Array[String]): Unit = { + // was: java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String; + val x: Array[String] = test[String]("x") + assert(x(0) == "x") + } +} From 96db33a8828f1681dfa245670b459e13ed6be6ec Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Thu, 24 Oct 2019 12:55:30 +1000 Subject: [PATCH 15/59] [backport] Avoid silence during CI, which Travis finds unacceptable --- .travis.yml | 8 ++--- build.sbt | 5 +++ project/TravisOutput.scala | 69 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 project/TravisOutput.scala diff --git a/.travis.yml b/.travis.yml index 8f66d39b3e2f..90abada3891a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,8 +26,8 @@ jobs: - deriveModuleVersions - removeExistingBuilds $integrationRepoUrl - if [ ! -z "$STARR_REF" ]; then buildStarr; fi - - travis_wait 90 buildLocker - - travis_wait 90 buildQuick + - buildLocker + - buildQuick - triggerScalaDist # pull request validation (w/ mini-bootstrap) @@ -40,9 +40,9 @@ jobs: name: "JDK 8 pr validation" if: type = pull_request script: - - travis_wait 90 sbt -warn setupPublishCore generateBuildCharacterPropertiesFile headerCheck publishLocal + - sbt -warn setupPublishCore generateBuildCharacterPropertiesFile headerCheck publishLocal - STARR=`cat buildcharacter.properties | grep ^maven.version.number | cut -d= -f2` && echo $STARR - - travis_wait 90 sbt -Dstarr.version=$STARR -warn setupValidateTest test:compile info testAll + - sbt -Dstarr.version=$STARR -warn setupValidateTest test:compile info testAll # build the spec using jekyll - stage: build diff --git a/build.sbt b/build.sbt index c48104f6fea8..c5bce14bbb7e 100644 --- a/build.sbt +++ b/build.sbt @@ -1796,3 +1796,8 @@ def findJar(files: Seq[Attributed[File]], dep: ModuleID): Option[Attributed[File whitesourceProduct := "Lightbend Reactive Platform" whitesourceAggregateProjectName := "scala-2.12-stable" whitesourceIgnoredScopes := Vector("test", "scala-tool") + +{ + scala.build.TravisOutput.installIfOnTravis() + Nil +} diff --git a/project/TravisOutput.scala b/project/TravisOutput.scala new file mode 100644 index 000000000000..dc61064dc053 --- /dev/null +++ b/project/TravisOutput.scala @@ -0,0 +1,69 @@ +package scala.build + +import java.util.TimerTask +import java.io._ +import java.util.concurrent.TimeUnit + +// Prints some output to console periodically if the build itself is silent to avoid Travis CI's 10 minute timeout +// from aborting the build. +// +// A hopefully better behaved version of travis_wait and travis_wait_enhanced. +object TravisOutput { + def install(): Unit = { + val out = System.out + if (out.getClass.getName != classOf[Redirecter].getName) { + schedule() + System.setOut(new Redirecter(out)) + savedOut = out + } + } + + def installIfOnTravis(): Unit = + if (sys.env.contains("TRAVIS")) install() + + private var savedOut: PrintStream = _ + private val delayMS = TimeUnit.MINUTES.toMillis(9) + private lazy val timer = new java.util.Timer(true) + private var task: TimerTask = _ + + private def schedule(): Unit = { + task = new PrintNewline + val period = delayMS + timer.schedule(task, delayMS, period) + } + + private def reschedule(): Unit = { + task.cancel() + schedule() + } + + private class PrintNewline extends java.util.TimerTask() { + override def run(): Unit = { + savedOut.println("") + } + } + + private class Redirecter(stream: PrintStream) extends PrintStream(new OutputStream { + def write(b: Int): Unit = { + reschedule() + stream.write(b) + } + override def write(b: Array[Byte]): Unit = { + reschedule() + stream.write(b) + } + override def write(b: Array[Byte], off: Int, len: Int): Unit = { + reschedule() + stream.write(b, off, len) + } + override def flush(): Unit = { + reschedule() + stream.flush() + } + override def close(): Unit = { + reschedule() + stream.close() + } + }) + +} From f39222d7bfa391a5c73736fb4d662d9ac81bd6b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Mon, 7 Dec 2020 18:27:04 +0100 Subject: [PATCH 16/59] Remove dead code testing for Array[Unit] after Array[AnyRef]. Since `Array[Unit]` is implemented as `Array[BoxedUnit]`, any `Array[Unit]` already qualifies as an `Array[AnyRef]`. Therefore, all the removed cases were dead code. --- src/library/scala/runtime/ScalaRunTime.scala | 5 ----- test/instrumented/srt.patch | 8 ++++---- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index 7d518048bd68..ec407ea97acf 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -64,7 +64,6 @@ object ScalaRunTime { case x: Array[Byte] => x(idx).asInstanceOf[Any] case x: Array[Short] => x(idx).asInstanceOf[Any] case x: Array[Boolean] => x(idx).asInstanceOf[Any] - case x: Array[Unit] => x(idx).asInstanceOf[Any] case null => throw new NullPointerException } } @@ -81,7 +80,6 @@ object ScalaRunTime { case x: Array[Byte] => x(idx) = value.asInstanceOf[Byte] case x: Array[Short] => x(idx) = value.asInstanceOf[Short] case x: Array[Boolean] => x(idx) = value.asInstanceOf[Boolean] - case x: Array[Unit] => x(idx) = value.asInstanceOf[Unit] case null => throw new NullPointerException } } @@ -97,7 +95,6 @@ object ScalaRunTime { case x: Array[Byte] => x.length case x: Array[Short] => x.length case x: Array[Boolean] => x.length - case x: Array[Unit] => x.length case null => throw new NullPointerException } @@ -111,7 +108,6 @@ object ScalaRunTime { case x: Array[Byte] => x.clone() case x: Array[Short] => x.clone() case x: Array[Boolean] => x.clone() - case x: Array[Unit] => x case null => throw new NullPointerException } @@ -143,7 +139,6 @@ object ScalaRunTime { case x: Array[Byte] => copy(x) case x: Array[Short] => copy(x) case x: Array[Boolean] => copy(x) - case x: Array[Unit] => copy(x) case null => throw new NullPointerException } } diff --git a/test/instrumented/srt.patch b/test/instrumented/srt.patch index 7c57c4c608f8..1d200f32ca98 100644 --- a/test/instrumented/srt.patch +++ b/test/instrumented/srt.patch @@ -9,14 +9,14 @@ def array_apply(xs: AnyRef, idx: Int): Any = { + arrayApplyCount += 1 xs match { -@@ -70,2 +73,3 @@ +@@ -69,2 +72,3 @@ } + var arrayApplyCount = 0 -@@ -73,2 +77,3 @@ +@@ -72,2 +76,3 @@ def array_update(xs: AnyRef, idx: Int, value: Any): Unit = { + arrayUpdateCount += 1 xs match { -@@ -87,2 +92,3 @@ +@@ -85,2 +90,3 @@ } -+ var arrayUpdateCount = 0 \ No newline at end of file ++ var arrayUpdateCount = 0 From cb865d353d5d923a50fb1f20c78e62cb87b05b10 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Mon, 14 May 2018 19:02:03 +0200 Subject: [PATCH 17/59] Build scaladocs for partest to make sonatype happy (cherry picked from commit a0026305125dcc814097b1fbb798fe925ca9f81f) --- build.sbt | 1 - 1 file changed, 1 deletion(-) diff --git a/build.sbt b/build.sbt index c5bce14bbb7e..b38d6aea62dd 100644 --- a/build.sbt +++ b/build.sbt @@ -1068,7 +1068,6 @@ lazy val scalap = configureAsSubproject(project) lazy val partest = configureAsSubproject(project) .dependsOn(library, reflect, compiler, scalap, replJlineEmbedded, scaladoc) - .settings(disableDocs) .settings(Osgi.settings) .settings(AutomaticModuleName.settings("scala.partest")) .settings( From 58c58212c442c396614e2e76436a1e94a3dd620c Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Thu, 17 May 2018 16:08:41 +0200 Subject: [PATCH 18/59] Remove non existing dependencies from scala-partest The `scala-repl-jline-embedded` and `scala-compiler-doc` sbt modules are merged into `scala-compiler`. (cherry picked from commit 9437be7cc8bb3e63d66af31fb22d62983acf0c22) --- build.sbt | 1 + 1 file changed, 1 insertion(+) diff --git a/build.sbt b/build.sbt index b38d6aea62dd..cdd402688fe4 100644 --- a/build.sbt +++ b/build.sbt @@ -1074,6 +1074,7 @@ lazy val partest = configureAsSubproject(project) name := "scala-partest", description := "Scala Compiler Testing Tool", libraryDependencies ++= List(testInterfaceDep, diffUtilsDep, junitDep), + pomDependencyExclusions ++= List((organization.value, "scala-repl-jline-embedded"), (organization.value, "scala-compiler-doc")), fixPom( "/project/name" -> Scala Partest, "/project/description" -> Scala Compiler Testing Tool, From 5f0210567f516277bca87ad0de9833518ed53f60 Mon Sep 17 00:00:00 2001 From: mkeskells Date: Tue, 8 Dec 2020 22:49:31 +0000 Subject: [PATCH 19/59] remove some tuples --- src/library/scala/collection/TraversableLike.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala index a62bb81b7ef2..6e1d39876eaa 100644 --- a/src/library/scala/collection/TraversableLike.scala +++ b/src/library/scala/collection/TraversableLike.scala @@ -491,10 +491,10 @@ trait TraversableLike[+A, +Repr] extends Any else if (k3 == key) v3 else { hashMap = new mutable.HashMap - hashMap += ((k0, v0)) - hashMap += ((k1, v1)) - hashMap += ((k2, v2)) - hashMap += ((k3, v3)) + hashMap(k0) = v0 + hashMap(k1) = v1 + hashMap(k2) = v2 + hashMap(k3) = v3 val bldr = apply() hashMap(key) = bldr bldr From bd800153a3e6e5aed55293ed2d0ee294acb3eb20 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Thu, 10 Dec 2020 17:47:49 -0800 Subject: [PATCH 20/59] [backport] backport .jvmopts from 2.13.x, sbt needs heap --- .jvmopts | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .jvmopts diff --git a/.jvmopts b/.jvmopts new file mode 100644 index 000000000000..f28c5328279c --- /dev/null +++ b/.jvmopts @@ -0,0 +1,2 @@ +-Xmx2G +-Xss1M From 13a425483099f390e8ef4a939736480fce9a14a4 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Tue, 29 Oct 2019 14:49:33 +0100 Subject: [PATCH 21/59] Fix box-unbox around branches - Support `pop` as BoxConsumer - consumer of box creation may be the consumer for multiple values Inspired by the tuple cases; extended to the ref/primitive cases. Co-Authored-By: "Harrison Houghton" --- .../tools/nsc/backend/jvm/opt/BoxUnbox.scala | 57 ++++++++++++------- .../nsc/backend/jvm/opt/BoxUnboxTest.scala | 37 +++++++++++- 2 files changed, 74 insertions(+), 20 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala index b5bd0546c2a5..2eda2438d5b9 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala @@ -264,6 +264,9 @@ abstract class BoxUnbox { case c: EscapingConsumer => assert(keepBox, s"found escaping consumer, but box is eliminated: $c") + case Drop(insn) => + if (keepBox) toReplace(insn) = List(getPop(1)) + case extraction => val (slot, tp) = localSlots(boxKind.extractedValueIndex(extraction)) val loadOps = new VarInsnNode(tp.getOpcode(ILOAD), slot) :: extraction.postExtractionAdaptationOps(tp) @@ -326,31 +329,38 @@ abstract class BoxUnbox { if (boxKind.boxedTypes.lengthCompare(1) == 0) { // fast path for single-value boxes allConsumers.foreach(extraction => extraction.postExtractionAdaptationOps(boxKind.boxedTypes.head) match { - case Nil => - toDelete ++= extraction.allInsns + case Nil => extraction match { + case Drop(_) => toReplace(extraction.consumer) = boxKind.boxedTypes.map(t => getPop(t.getSize)) + case _ => toDelete ++= extraction.allInsns + } case ops => toReplace(extraction.consumer) = ops toDelete ++= extraction.allInsns - extraction.consumer }) } else { for (extraction <- allConsumers) { - val valueIndex = boxKind.extractedValueIndex(extraction) - val replacementOps = if (valueIndex == 0) { - val pops = boxKind.boxedTypes.tail.map(t => getPop(t.getSize)) - pops ::: extraction.postExtractionAdaptationOps(boxKind.boxedTypes.head) - } else { - var loadOps: List[AbstractInsnNode] = null - val consumeStack = boxKind.boxedTypes.zipWithIndex reverseMap { - case (tp, i) => - if (i == valueIndex) { - val resultSlot = getLocal(tp.getSize) - loadOps = new VarInsnNode(tp.getOpcode(ILOAD), resultSlot) :: extraction.postExtractionAdaptationOps(tp) - new VarInsnNode(tp.getOpcode(ISTORE), resultSlot) - } else { - getPop(tp.getSize) + val replacementOps = extraction match { + case Drop(_) => + boxKind.boxedTypes.map(t => getPop(t.getSize)) + case _ => + val valueIndex = boxKind.extractedValueIndex(extraction) + if (valueIndex == 0) { + val pops = boxKind.boxedTypes.tail.map(t => getPop(t.getSize)) + pops ::: extraction.postExtractionAdaptationOps(boxKind.boxedTypes.head) + } else { + var loadOps: List[AbstractInsnNode] = null + val consumeStack = boxKind.boxedTypes.zipWithIndex reverseMap { + case (tp, i) => + if (i == valueIndex) { + val resultSlot = getLocal(tp.getSize) + loadOps = new VarInsnNode(tp.getOpcode(ILOAD), resultSlot) :: extraction.postExtractionAdaptationOps(tp) + new VarInsnNode(tp.getOpcode(ISTORE), resultSlot) + } else { + getPop(tp.getSize) + } } - } - consumeStack ::: loadOps + consumeStack ::: loadOps + } } toReplace(extraction.consumer) = replacementOps toDelete ++= extraction.allInsns - extraction.consumer @@ -617,7 +627,7 @@ abstract class BoxUnbox { val afterInit = initCall.getNext val stackTopAfterInit = prodCons.frameAt(afterInit).stackTop val initializedInstanceCons = prodCons.consumersOfValueAt(afterInit, stackTopAfterInit) - if (initializedInstanceCons == dupConsWithoutInit && prodCons.producersForValueAt(afterInit, stackTopAfterInit) == Set(dupOp)) { + if (initializedInstanceCons == dupConsWithoutInit) { return Some((dupOp, initCall)) } } @@ -704,6 +714,9 @@ abstract class BoxUnbox { val success = primBoxSupertypes(kind.boxClass).contains(ti.desc) Some(BoxedPrimitiveTypeCheck(ti, success)) + case i: InsnNode if i.getOpcode == POP => + Some(Drop(i)) + case _ => None } } @@ -757,6 +770,9 @@ abstract class BoxUnbox { case ti: TypeInsnNode if ti.getOpcode == INSTANCEOF => Some(BoxedPrimitiveTypeCheck(ti, ti.desc == kind.refClass || refSupertypes.contains(ti.desc))) + case i: InsnNode if i.getOpcode == POP => + Some(Drop(i)) + case _ => None } } @@ -820,6 +836,7 @@ abstract class BoxUnbox { } case _ => + if (insn.getOpcode == POP) return Some(Drop(insn)) } None } @@ -939,6 +956,8 @@ abstract class BoxUnbox { case class StaticSetterOrInstanceWrite(consumer: AbstractInsnNode) extends BoxConsumer /** `.\$isInstanceOf[T]` (can be statically proven true or false) */ case class BoxedPrimitiveTypeCheck(consumer: AbstractInsnNode, success: Boolean) extends BoxConsumer + /** POP */ + case class Drop(consumer: AbstractInsnNode) extends BoxConsumer /** An unknown box consumer */ case class EscapingConsumer(consumer: AbstractInsnNode) extends BoxConsumer } diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala index f38ba64fc4fd..07d8a24a8329 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala @@ -146,6 +146,13 @@ class BoxUnboxTest extends BytecodeTesting { | bi + li | } | + | def t17(x: Int) = { // this one's pretty contrived but tests that primitives can be unboxed through a branch + | val wat: Any = if (x > 0) x else -x + | wat match { + | case i: Int => String valueOf i + | case _ => "?" + | } + | } |} """.stripMargin @@ -199,10 +206,11 @@ class BoxUnboxTest extends BytecodeTesting { assertDoesNotInvoke(getInstructions(c, "t16"), "boxToLong") assertDoesNotInvoke(getInstructions(c, "t16"), "unboxToInt") assertDoesNotInvoke(getInstructions(c, "t16"), "unboxToLong") + assertDoesNotInvoke(getMethod(c, "t17"), "boxToInteger") } @Test - def refEliminiation(): Unit = { + def refElimination(): Unit = { val code = """class C { | import runtime._ @@ -245,6 +253,12 @@ class BoxUnboxTest extends BytecodeTesting { | val res: IntRef = if (b) r1 else r2 | res.elem // boxes remain: can't rewrite this read, don't know which local | } + | + | // this case is contemplated by BoxUnbox despite my inability to provide a motivating example + | def t7(b: Boolean) = { + | val r1 = if (b) IntRef.zero() else IntRef.create(1) + | r1.elem + | } |} """.stripMargin val c = compileClass(code) @@ -256,6 +270,7 @@ class BoxUnboxTest extends BytecodeTesting { List("scala/runtime/IntRef.elem")) assertEquals(getInstructions(c, "t6") collect { case Field(op, owner, name, _) => s"$op $owner.$name" }, List(s"$PUTFIELD scala/runtime/IntRef.elem", s"$GETFIELD scala/runtime/IntRef.elem")) + assertNoInvoke(getMethod(c, "t7")) } @Test @@ -309,6 +324,21 @@ class BoxUnboxTest extends BytecodeTesting { | case (x, y) if x == y => 0 | case (x, y) => x + y | } + | + | def t10(a: Int, b: Int) = { // tuple is optimized away + | val (greater, lesser) = if (a > b) (a, b) else (b, a) + | greater - lesser + | } + | + | def t11(n: Int)(j: Int) = { // tuple is optimized away + | val (a, b, c, _) = n match { + | case 0 => (j, 0, 1, 1) + | case 1 => (0, j, 0, 1) + | case 2 => (1, 0, j, 0) + | case 3 => (1, 1, 0, j) + | } + | a + b + c + | } |} """.stripMargin val c = compileClass(code, allowMessage = (info: StoreReporter.Info) => info.msg.contains("there was one deprecation warning")) @@ -328,6 +358,11 @@ class BoxUnboxTest extends BytecodeTesting { ILOAD, ILOAD, IADD, ILOAD, IADD, IRETURN)) assertNoInvoke(getMethod(c, "t8")) assertNoInvoke(getMethod(c, "t9")) + assertNoInvoke(getMethod(c, "t10")) + assertInvokedMethods(getMethod(c, "t11"), List( + "scala/runtime/BoxesRunTime.boxToInteger", // only once, for the MatchError + "scala/MatchError.", + )) } } From e5580a6f616eeee0680c3a167d86f4bb755fc951 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Wed, 16 Dec 2020 16:13:25 +0100 Subject: [PATCH 22/59] [nomerge] silence warning on nowarn --- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 2 +- src/library/scala/annotation/nowarn.scala | 1 + test/files/neg/annot-nonconst.check | 4 ++-- test/files/neg/nested-annotation.check | 2 +- test/files/neg/t6082.check | 2 +- test/files/neg/t6083.check | 2 +- test/files/run/reflection-scala-annotations.check | 2 +- test/files/run/reify_ann1b.check | 4 ++-- test/files/run/reify_classfileann_a.check | 2 +- test/files/run/reify_classfileann_b.check | 2 +- test/files/run/t5224.check | 2 +- 11 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 88b39430b53d..17c0bd524ac8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1841,7 +1841,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // It only extends ClassfileAnnotationClass instead of StaticAnnotation to get the enforcement // of constant argument values "for free". Related to scala/bug#7041. else if (clazz != SerialVersionUIDAttr) restrictionWarning(cdef.pos, unit, - """|subclassing Classfile does not + """|subclassing ClassfileAnnotation does not |make your annotation visible at runtime. If that is what |you want, you must write the annotation class in Java.""".stripMargin, WarningCategory.Other, clazz) } diff --git a/src/library/scala/annotation/nowarn.scala b/src/library/scala/annotation/nowarn.scala index 75640e78e6ae..8fb0a5549956 100644 --- a/src/library/scala/annotation/nowarn.scala +++ b/src/library/scala/annotation/nowarn.scala @@ -31,4 +31,5 @@ package scala.annotation * * To ensure that a `@nowarn` annotation actually suppresses a warning, enable `-Xlint:nowarn`. */ +@nowarn("msg=subclassing ClassfileAnnotation does not\nmake your annotation visible at runtime") class nowarn(value: String = "") extends ClassfileAnnotation diff --git a/test/files/neg/annot-nonconst.check b/test/files/neg/annot-nonconst.check index b7b9c3761b7b..58a13b10e9c3 100644 --- a/test/files/neg/annot-nonconst.check +++ b/test/files/neg/annot-nonconst.check @@ -4,12 +4,12 @@ annot-nonconst.scala:6: error: annotation argument needs to be a constant; found annot-nonconst.scala:7: error: annotation argument cannot be null @Ann2(null) def bar = "bar" ^ -annot-nonconst.scala:1: warning: Implementation restriction: subclassing Classfile does not +annot-nonconst.scala:1: warning: Implementation restriction: subclassing ClassfileAnnotation does not make your annotation visible at runtime. If that is what you want, you must write the annotation class in Java. class Length(value: Int) extends annotation.ClassfileAnnotation ^ -annot-nonconst.scala:2: warning: Implementation restriction: subclassing Classfile does not +annot-nonconst.scala:2: warning: Implementation restriction: subclassing ClassfileAnnotation does not make your annotation visible at runtime. If that is what you want, you must write the annotation class in Java. class Ann2(value: String) extends annotation.ClassfileAnnotation diff --git a/test/files/neg/nested-annotation.check b/test/files/neg/nested-annotation.check index 7c4c73844347..1cd3df5bb054 100644 --- a/test/files/neg/nested-annotation.check +++ b/test/files/neg/nested-annotation.check @@ -1,7 +1,7 @@ nested-annotation.scala:8: error: nested classfile annotations must be defined in java; found: inline @ComplexAnnotation(new inline) def bippy(): Int = 1 ^ -nested-annotation.scala:3: warning: Implementation restriction: subclassing Classfile does not +nested-annotation.scala:3: warning: Implementation restriction: subclassing ClassfileAnnotation does not make your annotation visible at runtime. If that is what you want, you must write the annotation class in Java. class ComplexAnnotation(val value: Annotation) extends ClassfileAnnotation diff --git a/test/files/neg/t6082.check b/test/files/neg/t6082.check index a6a44eb16be7..9f757d2db82a 100644 --- a/test/files/neg/t6082.check +++ b/test/files/neg/t6082.check @@ -4,7 +4,7 @@ t6082.scala:2: error: classfile annotation arguments have to be supplied as name t6082.scala:2: error: annotation annot is missing argument notValue @annot("") class C ^ -t6082.scala:1: warning: Implementation restriction: subclassing Classfile does not +t6082.scala:1: warning: Implementation restriction: subclassing ClassfileAnnotation does not make your annotation visible at runtime. If that is what you want, you must write the annotation class in Java. class annot(notValue: String) extends annotation.ClassfileAnnotation diff --git a/test/files/neg/t6083.check b/test/files/neg/t6083.check index 9a5b3f9e1c93..7116bda41d9a 100644 --- a/test/files/neg/t6083.check +++ b/test/files/neg/t6083.check @@ -1,7 +1,7 @@ t6083.scala:7: error: annotation argument needs to be a constant; found: conv.i2s(101) @annot(101) class C ^ -t6083.scala:6: warning: Implementation restriction: subclassing Classfile does not +t6083.scala:6: warning: Implementation restriction: subclassing ClassfileAnnotation does not make your annotation visible at runtime. If that is what you want, you must write the annotation class in Java. class annot(value: String) extends annotation.ClassfileAnnotation diff --git a/test/files/run/reflection-scala-annotations.check b/test/files/run/reflection-scala-annotations.check index 44062d8c4aa3..1a5806455ee8 100644 --- a/test/files/run/reflection-scala-annotations.check +++ b/test/files/run/reflection-scala-annotations.check @@ -1,4 +1,4 @@ -reflection-scala-annotations.scala:5: warning: Implementation restriction: subclassing Classfile does not +reflection-scala-annotations.scala:5: warning: Implementation restriction: subclassing ClassfileAnnotation does not make your annotation visible at runtime. If that is what you want, you must write the annotation class in Java. class jann(x: Int, y: Array[Int]) extends ClassfileAnnotation diff --git a/test/files/run/reify_ann1b.check b/test/files/run/reify_ann1b.check index 92db7046146e..2750e72ba177 100644 --- a/test/files/run/reify_ann1b.check +++ b/test/files/run/reify_ann1b.check @@ -1,9 +1,9 @@ -reify_ann1b.scala:6: warning: Implementation restriction: subclassing Classfile does not +reify_ann1b.scala:6: warning: Implementation restriction: subclassing ClassfileAnnotation does not make your annotation visible at runtime. If that is what you want, you must write the annotation class in Java. class ann0(bar: String) extends annotation.ClassfileAnnotation ^ -reify_ann1b.scala:7: warning: Implementation restriction: subclassing Classfile does not +reify_ann1b.scala:7: warning: Implementation restriction: subclassing ClassfileAnnotation does not make your annotation visible at runtime. If that is what you want, you must write the annotation class in Java. class ann1(bar: String) extends annotation.ClassfileAnnotation diff --git a/test/files/run/reify_classfileann_a.check b/test/files/run/reify_classfileann_a.check index 51f255b23295..bda0f06e755a 100644 --- a/test/files/run/reify_classfileann_a.check +++ b/test/files/run/reify_classfileann_a.check @@ -1,4 +1,4 @@ -reify_classfileann_a.scala:6: warning: Implementation restriction: subclassing Classfile does not +reify_classfileann_a.scala:6: warning: Implementation restriction: subclassing ClassfileAnnotation does not make your annotation visible at runtime. If that is what you want, you must write the annotation class in Java. class ann(bar: String, quux: Array[String] = Array(), baz: ann = null) extends annotation.ClassfileAnnotation diff --git a/test/files/run/reify_classfileann_b.check b/test/files/run/reify_classfileann_b.check index 05f2e5bfc6da..e9d8809e5372 100644 --- a/test/files/run/reify_classfileann_b.check +++ b/test/files/run/reify_classfileann_b.check @@ -1,4 +1,4 @@ -reify_classfileann_b.scala:6: warning: Implementation restriction: subclassing Classfile does not +reify_classfileann_b.scala:6: warning: Implementation restriction: subclassing ClassfileAnnotation does not make your annotation visible at runtime. If that is what you want, you must write the annotation class in Java. class ann(bar: String, quux: Array[String] = Array(), baz: ann = null) extends annotation.ClassfileAnnotation diff --git a/test/files/run/t5224.check b/test/files/run/t5224.check index b11480acdfb5..0a692814dae4 100644 --- a/test/files/run/t5224.check +++ b/test/files/run/t5224.check @@ -1,4 +1,4 @@ -t5224.scala:3: warning: Implementation restriction: subclassing Classfile does not +t5224.scala:3: warning: Implementation restriction: subclassing ClassfileAnnotation does not make your annotation visible at runtime. If that is what you want, you must write the annotation class in Java. class Foo(bar: String) extends annotation.ClassfileAnnotation From 4d30d48d7f1ecc406ce26b76e8b23f4693b54329 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Mon, 21 Dec 2020 10:37:58 +0100 Subject: [PATCH 23/59] Revert "Fix box-unbox around branches" This reverts commit 13a425483099f390e8ef4a939736480fce9a14a4, to be re-applied after 2.12.13 is released. --- .../tools/nsc/backend/jvm/opt/BoxUnbox.scala | 57 +++++++------------ .../nsc/backend/jvm/opt/BoxUnboxTest.scala | 37 +----------- 2 files changed, 20 insertions(+), 74 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala index 2eda2438d5b9..b5bd0546c2a5 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala @@ -264,9 +264,6 @@ abstract class BoxUnbox { case c: EscapingConsumer => assert(keepBox, s"found escaping consumer, but box is eliminated: $c") - case Drop(insn) => - if (keepBox) toReplace(insn) = List(getPop(1)) - case extraction => val (slot, tp) = localSlots(boxKind.extractedValueIndex(extraction)) val loadOps = new VarInsnNode(tp.getOpcode(ILOAD), slot) :: extraction.postExtractionAdaptationOps(tp) @@ -329,38 +326,31 @@ abstract class BoxUnbox { if (boxKind.boxedTypes.lengthCompare(1) == 0) { // fast path for single-value boxes allConsumers.foreach(extraction => extraction.postExtractionAdaptationOps(boxKind.boxedTypes.head) match { - case Nil => extraction match { - case Drop(_) => toReplace(extraction.consumer) = boxKind.boxedTypes.map(t => getPop(t.getSize)) - case _ => toDelete ++= extraction.allInsns - } + case Nil => + toDelete ++= extraction.allInsns case ops => toReplace(extraction.consumer) = ops toDelete ++= extraction.allInsns - extraction.consumer }) } else { for (extraction <- allConsumers) { - val replacementOps = extraction match { - case Drop(_) => - boxKind.boxedTypes.map(t => getPop(t.getSize)) - case _ => - val valueIndex = boxKind.extractedValueIndex(extraction) - if (valueIndex == 0) { - val pops = boxKind.boxedTypes.tail.map(t => getPop(t.getSize)) - pops ::: extraction.postExtractionAdaptationOps(boxKind.boxedTypes.head) - } else { - var loadOps: List[AbstractInsnNode] = null - val consumeStack = boxKind.boxedTypes.zipWithIndex reverseMap { - case (tp, i) => - if (i == valueIndex) { - val resultSlot = getLocal(tp.getSize) - loadOps = new VarInsnNode(tp.getOpcode(ILOAD), resultSlot) :: extraction.postExtractionAdaptationOps(tp) - new VarInsnNode(tp.getOpcode(ISTORE), resultSlot) - } else { - getPop(tp.getSize) - } + val valueIndex = boxKind.extractedValueIndex(extraction) + val replacementOps = if (valueIndex == 0) { + val pops = boxKind.boxedTypes.tail.map(t => getPop(t.getSize)) + pops ::: extraction.postExtractionAdaptationOps(boxKind.boxedTypes.head) + } else { + var loadOps: List[AbstractInsnNode] = null + val consumeStack = boxKind.boxedTypes.zipWithIndex reverseMap { + case (tp, i) => + if (i == valueIndex) { + val resultSlot = getLocal(tp.getSize) + loadOps = new VarInsnNode(tp.getOpcode(ILOAD), resultSlot) :: extraction.postExtractionAdaptationOps(tp) + new VarInsnNode(tp.getOpcode(ISTORE), resultSlot) + } else { + getPop(tp.getSize) } - consumeStack ::: loadOps - } + } + consumeStack ::: loadOps } toReplace(extraction.consumer) = replacementOps toDelete ++= extraction.allInsns - extraction.consumer @@ -627,7 +617,7 @@ abstract class BoxUnbox { val afterInit = initCall.getNext val stackTopAfterInit = prodCons.frameAt(afterInit).stackTop val initializedInstanceCons = prodCons.consumersOfValueAt(afterInit, stackTopAfterInit) - if (initializedInstanceCons == dupConsWithoutInit) { + if (initializedInstanceCons == dupConsWithoutInit && prodCons.producersForValueAt(afterInit, stackTopAfterInit) == Set(dupOp)) { return Some((dupOp, initCall)) } } @@ -714,9 +704,6 @@ abstract class BoxUnbox { val success = primBoxSupertypes(kind.boxClass).contains(ti.desc) Some(BoxedPrimitiveTypeCheck(ti, success)) - case i: InsnNode if i.getOpcode == POP => - Some(Drop(i)) - case _ => None } } @@ -770,9 +757,6 @@ abstract class BoxUnbox { case ti: TypeInsnNode if ti.getOpcode == INSTANCEOF => Some(BoxedPrimitiveTypeCheck(ti, ti.desc == kind.refClass || refSupertypes.contains(ti.desc))) - case i: InsnNode if i.getOpcode == POP => - Some(Drop(i)) - case _ => None } } @@ -836,7 +820,6 @@ abstract class BoxUnbox { } case _ => - if (insn.getOpcode == POP) return Some(Drop(insn)) } None } @@ -956,8 +939,6 @@ abstract class BoxUnbox { case class StaticSetterOrInstanceWrite(consumer: AbstractInsnNode) extends BoxConsumer /** `.\$isInstanceOf[T]` (can be statically proven true or false) */ case class BoxedPrimitiveTypeCheck(consumer: AbstractInsnNode, success: Boolean) extends BoxConsumer - /** POP */ - case class Drop(consumer: AbstractInsnNode) extends BoxConsumer /** An unknown box consumer */ case class EscapingConsumer(consumer: AbstractInsnNode) extends BoxConsumer } diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala index 07d8a24a8329..f38ba64fc4fd 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala @@ -146,13 +146,6 @@ class BoxUnboxTest extends BytecodeTesting { | bi + li | } | - | def t17(x: Int) = { // this one's pretty contrived but tests that primitives can be unboxed through a branch - | val wat: Any = if (x > 0) x else -x - | wat match { - | case i: Int => String valueOf i - | case _ => "?" - | } - | } |} """.stripMargin @@ -206,11 +199,10 @@ class BoxUnboxTest extends BytecodeTesting { assertDoesNotInvoke(getInstructions(c, "t16"), "boxToLong") assertDoesNotInvoke(getInstructions(c, "t16"), "unboxToInt") assertDoesNotInvoke(getInstructions(c, "t16"), "unboxToLong") - assertDoesNotInvoke(getMethod(c, "t17"), "boxToInteger") } @Test - def refElimination(): Unit = { + def refEliminiation(): Unit = { val code = """class C { | import runtime._ @@ -253,12 +245,6 @@ class BoxUnboxTest extends BytecodeTesting { | val res: IntRef = if (b) r1 else r2 | res.elem // boxes remain: can't rewrite this read, don't know which local | } - | - | // this case is contemplated by BoxUnbox despite my inability to provide a motivating example - | def t7(b: Boolean) = { - | val r1 = if (b) IntRef.zero() else IntRef.create(1) - | r1.elem - | } |} """.stripMargin val c = compileClass(code) @@ -270,7 +256,6 @@ class BoxUnboxTest extends BytecodeTesting { List("scala/runtime/IntRef.elem")) assertEquals(getInstructions(c, "t6") collect { case Field(op, owner, name, _) => s"$op $owner.$name" }, List(s"$PUTFIELD scala/runtime/IntRef.elem", s"$GETFIELD scala/runtime/IntRef.elem")) - assertNoInvoke(getMethod(c, "t7")) } @Test @@ -324,21 +309,6 @@ class BoxUnboxTest extends BytecodeTesting { | case (x, y) if x == y => 0 | case (x, y) => x + y | } - | - | def t10(a: Int, b: Int) = { // tuple is optimized away - | val (greater, lesser) = if (a > b) (a, b) else (b, a) - | greater - lesser - | } - | - | def t11(n: Int)(j: Int) = { // tuple is optimized away - | val (a, b, c, _) = n match { - | case 0 => (j, 0, 1, 1) - | case 1 => (0, j, 0, 1) - | case 2 => (1, 0, j, 0) - | case 3 => (1, 1, 0, j) - | } - | a + b + c - | } |} """.stripMargin val c = compileClass(code, allowMessage = (info: StoreReporter.Info) => info.msg.contains("there was one deprecation warning")) @@ -358,11 +328,6 @@ class BoxUnboxTest extends BytecodeTesting { ILOAD, ILOAD, IADD, ILOAD, IADD, IRETURN)) assertNoInvoke(getMethod(c, "t8")) assertNoInvoke(getMethod(c, "t9")) - assertNoInvoke(getMethod(c, "t10")) - assertInvokedMethods(getMethod(c, "t11"), List( - "scala/runtime/BoxesRunTime.boxToInteger", // only once, for the MatchError - "scala/MatchError.", - )) } } From 394e6d4d0b0b72ab4b0cb42881e562bef96e067a Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Tue, 22 Dec 2020 10:14:42 -0800 Subject: [PATCH 24/59] [backport] move from travis-ci.org to travis-ci.com backport of #9411 to 2.12.x also backports 98acd0f context: scala/scala-dev#728 --- .travis.yml | 2 +- scripts/common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 90abada3891a..b0b6e9083e2a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -66,7 +66,7 @@ env: - secure: "feE5A8mYNpkNQKVwCj3aXrwjVrJWh/4ENpRfFlr2HOD9ORk1GORD5Yq907WZd+dTkYK54Lh1gA+qHOCIDgJHbi9ZLU+kjzEjtYKF6lQy6Wb0LI8smTOnAA6IWVVYifiXw8d66MI2MKZb2jjGeIzy8Q00SZjLhEGjLyTeCIB88Ws=" # SONA_USER - secure: "ek3As5q2tL8UBXcxSBbv4v5YgsoPD41SCzPOSu72kzfbngyxgQxrcziU5pIM+Lib9KaWex7hVVWNL38tMyDbu+0OpDv8bPjMujzlDx5I2pJUfuOJo7QRYsJE1nsXcY4cA72cCLfbRcLEkvtDAhcdLSaUOqlyQe5BY4X4fY5eoPA=" # SONA_PASS - secure: "dbAvl6KEuLwZ0MVQPZihFsPzCdiLbX0EFk3so+hcfEbksrmLQ1tn4X5ZM7Wy1UDR8uN9lxngEwHch7a7lKqpugzmXMew9Wnikr9WBWbJT77Z+XJ/jHI6YuiCRpRo+nvxXGp9Ry80tSIgx5eju0J83IaJL41BWlBkvyAd7YAHORI=" # GPG_SUBKEY_SECRET - - secure: "ee0z/1jehBjFa2M2JlBHRjeo6OEn/zmVl72ukBP1ISeKqz18Cswc4gDI5tV9RW9SlYFLkIlGsR2qnRCyJ/pqgQLcNdrpsCRFFc79oyLhfEtmPdAHlWfj4RSP68zINRtDdFuJ8iSy8XYP0NaqpVIYpkNdv9I6q7N85ljmMQpHO+U=" # TRAVIS_TOKEN (login with GitHub as lrytz) + - secure: "RTyzS6nUgthupw5M0fPwTlcOym1sWgBo8eXYepB2xGiQnRu4g583BGuNBW1UZ3vIjRETi/UKQ1HtMR+i7D8ptF1cNpomopncVJA1iy7pU2w0MJ0xgIPMuvtkIa3kxocd/AnxAp+UhUad3nC8lDpkvZsUhhyA0fb4iPKipd2b2xY=" # TRAVIS_TOKEN (login with GitHub as SethTisue) # caching for sdkman / sbt / ivy / coursier imported from scala-dev cache: diff --git a/scripts/common b/scripts/common index ceb9a55ae521..f7d116f79c29 100644 --- a/scripts/common +++ b/scripts/common @@ -215,7 +215,7 @@ triggerScalaDist() { -H "Authorization: token $TRAVIS_TOKEN" \ -H "Content-Type: application/json" \ -d "$json" \ - https://api.travis-ci.org/repo/scala%2Fscala-dist/requests) + https://api.travis-ci.com/repo/scala%2Fscala-dist/requests) [[ "$curlStatus" == "202" ]] || { echo "failed to start job" From a398b9b939073d9af952625f79854526e5f2aa7c Mon Sep 17 00:00:00 2001 From: Alexey Kotlyarov Date: Tue, 5 Jan 2021 20:31:26 +1100 Subject: [PATCH 25/59] Enumeration documentation: remove nested class shadowing in "override" position --- src/library/scala/Enumeration.scala | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/library/scala/Enumeration.scala b/src/library/scala/Enumeration.scala index 03316d70c807..04208198a3fb 100644 --- a/src/library/scala/Enumeration.scala +++ b/src/library/scala/Enumeration.scala @@ -56,21 +56,21 @@ import scala.util.matching.Regex * @example {{{ * // Example of adding attributes to an enumeration by extending the Enumeration.Val class * object Planet extends Enumeration { - * protected case class Val(mass: Double, radius: Double) extends super.Val { + * protected case class PlanetVal(mass: Double, radius: Double) extends super.Val { * def surfaceGravity: Double = Planet.G * mass / (radius * radius) * def surfaceWeight(otherMass: Double): Double = otherMass * surfaceGravity * } - * implicit def valueToPlanetVal(x: Value): Val = x.asInstanceOf[Val] + * implicit def valueToPlanetVal(x: Value): PlanetVal = x.asInstanceOf[PlanetVal] * * val G: Double = 6.67300E-11 - * val Mercury = Val(3.303e+23, 2.4397e6) - * val Venus = Val(4.869e+24, 6.0518e6) - * val Earth = Val(5.976e+24, 6.37814e6) - * val Mars = Val(6.421e+23, 3.3972e6) - * val Jupiter = Val(1.9e+27, 7.1492e7) - * val Saturn = Val(5.688e+26, 6.0268e7) - * val Uranus = Val(8.686e+25, 2.5559e7) - * val Neptune = Val(1.024e+26, 2.4746e7) + * val Mercury = PlanetVal(3.303e+23, 2.4397e6) + * val Venus = PlanetVal(4.869e+24, 6.0518e6) + * val Earth = PlanetVal(5.976e+24, 6.37814e6) + * val Mars = PlanetVal(6.421e+23, 3.3972e6) + * val Jupiter = PlanetVal(1.9e+27, 7.1492e7) + * val Saturn = PlanetVal(5.688e+26, 6.0268e7) + * val Uranus = PlanetVal(8.686e+25, 2.5559e7) + * val Neptune = PlanetVal(1.024e+26, 2.4746e7) * } * * println(Planet.values.filter(_.radius > 7.0e6)) From 906f4cd178f9ba2423badcbc2ea743b5c6059848 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Tue, 5 Jan 2021 13:33:23 -0800 Subject: [PATCH 26/59] bump copyright year to 2021 in the usual places. based on 6de01bc, and verified with `git grep -w 2020` --- NOTICE | 4 ++-- doc/LICENSE.md | 4 ++-- doc/License.rtf | 4 ++-- project/VersionUtil.scala | 2 +- src/library/scala/util/Properties.scala | 2 +- src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala | 2 +- src/scalap/decoder.properties | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/NOTICE b/NOTICE index ac3a26b40f48..ba6f890b920f 100644 --- a/NOTICE +++ b/NOTICE @@ -1,6 +1,6 @@ Scala -Copyright (c) 2002-2020 EPFL -Copyright (c) 2011-2020 Lightbend, Inc. +Copyright (c) 2002-2021 EPFL +Copyright (c) 2011-2021 Lightbend, Inc. Scala includes software developed at LAMP/EPFL (https://lamp.epfl.ch/) and diff --git a/doc/LICENSE.md b/doc/LICENSE.md index fd85d2b5515d..fe5d1ee3a8d7 100644 --- a/doc/LICENSE.md +++ b/doc/LICENSE.md @@ -2,9 +2,9 @@ Scala is licensed under the [Apache License Version 2.0](https://www.apache.org/ ## Scala License -Copyright (c) 2002-2020 EPFL +Copyright (c) 2002-2021 EPFL -Copyright (c) 2011-2020 Lightbend, Inc. +Copyright (c) 2011-2021 Lightbend, Inc. All rights reserved. diff --git a/doc/License.rtf b/doc/License.rtf index dc99c3e1453f..ea9a4d9e6891 100644 --- a/doc/License.rtf +++ b/doc/License.rtf @@ -23,8 +23,8 @@ Scala is licensed under the\'a0{\field{\*\fldinst{HYPERLINK "https://www.apache. \fs48 \cf2 Scala License\ \pard\pardeftab720\sl360\sa320\partightenfactor0 -\f0\b0\fs28 \cf2 Copyright (c) 2002-2020 EPFL\ -Copyright (c) 2011-2020 Lightbend, Inc.\ +\f0\b0\fs28 \cf2 Copyright (c) 2002-2021 EPFL\ +Copyright (c) 2011-2021 Lightbend, Inc.\ All rights reserved.\ \pard\pardeftab720\sl360\sa320\partightenfactor0 \cf2 \cb4 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at {\field{\*\fldinst{HYPERLINK "http://www.apache.org/licenses/LICENSE-2.0"}}{\fldrslt http://www.apache.org/licenses/LICENSE-2.0}}.\ diff --git a/project/VersionUtil.scala b/project/VersionUtil.scala index 85bafd2d51d3..9bcc24953b39 100644 --- a/project/VersionUtil.scala +++ b/project/VersionUtil.scala @@ -30,7 +30,7 @@ object VersionUtil { ) lazy val generatePropertiesFileSettings = Seq[Setting[_]]( - copyrightString := "Copyright 2002-2020, LAMP/EPFL and Lightbend, Inc.", + copyrightString := "Copyright 2002-2021, LAMP/EPFL and Lightbend, Inc.", shellWelcomeString := """ | ________ ___ / / ___ | / __/ __// _ | / / / _ | diff --git a/src/library/scala/util/Properties.scala b/src/library/scala/util/Properties.scala index 3c71780584f9..0049282d79f3 100644 --- a/src/library/scala/util/Properties.scala +++ b/src/library/scala/util/Properties.scala @@ -108,7 +108,7 @@ private[scala] trait PropertiesTrait { * or "version (unknown)" if it cannot be determined. */ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)") - val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2020, LAMP/EPFL and Lightbend, Inc.") + val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2021, LAMP/EPFL and Lightbend, Inc.") /** This is the encoding to use reading in source files, overridden with -encoding. * Note that it uses "prop" i.e. looks in the scala jar, not the system properties. diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala index 8926d4ffabb7..c16987e3016c 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala @@ -407,7 +407,7 @@ trait EntityPage extends HtmlPage { { if (Set("epfl", "EPFL").contains(tpl.universe.settings.docfooter.value)) - + else } diff --git a/src/scalap/decoder.properties b/src/scalap/decoder.properties index 3607f029f024..9ac03dd79c51 100644 --- a/src/scalap/decoder.properties +++ b/src/scalap/decoder.properties @@ -1,2 +1,2 @@ version.number=2.0.1 -copyright.string=(c) 2002-2020 LAMP/EPFL +copyright.string=(c) 2002-2021 LAMP/EPFL From 8a460167cfda054955122868ab0d6719b47c7e8b Mon Sep 17 00:00:00 2001 From: tanishiking Date: Sat, 9 Jan 2021 17:59:57 +0900 Subject: [PATCH 27/59] Ensure SingletonTypeTree#ref has symbol after typing. Fixes scala/bug#12296 --- .../scala/tools/nsc/typechecker/Typers.scala | 3 +- test/files/run/reify-each-node-type.check | 2 +- .../tools/nsc/typechecker/TypedTreeTest.scala | 37 +++++++++++++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 88b39430b53d..d7a2c38e4518 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -5627,9 +5627,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (refTyped.isErrorTyped) setError(tree) else { - tree setType refTyped.tpe.resultType.deconst if (!treeInfo.admitsTypeSelection(refTyped)) UnstableTreeError(tree) - else tree + else SingletonTypeTree(refTyped).setType(refTyped.tpe.resultType.deconst) } } diff --git a/test/files/run/reify-each-node-type.check b/test/files/run/reify-each-node-type.check index afc65add7af2..5cff9e63731c 100644 --- a/test/files/run/reify-each-node-type.check +++ b/test/files/run/reify-each-node-type.check @@ -23,7 +23,7 @@ 23 new r.List[Int]() New 24 0: @unchecked Annotated 25 (null: r.Outer#Inner) SelectFromTypeTree -26 (null: Nil.type) SingletonTypeTree +26 (null: r.Nil.type) SingletonTypeTree 27 (null: T forSome { type T }) ExistentialTypeTree 28 { import r.{A, B=>C}; () } Import 29 { def f: Int = return 0; () } Return diff --git a/test/junit/scala/tools/nsc/typechecker/TypedTreeTest.scala b/test/junit/scala/tools/nsc/typechecker/TypedTreeTest.scala index 3baae9a85d61..2ca590c07804 100644 --- a/test/junit/scala/tools/nsc/typechecker/TypedTreeTest.scala +++ b/test/junit/scala/tools/nsc/typechecker/TypedTreeTest.scala @@ -24,4 +24,41 @@ class TypedTreeTest extends BytecodeTesting { val List(t) = tree.filter(_.attachments.all.nonEmpty).toList assertEquals(s"$t:${t.attachments.all}", "42:Set(OriginalTreeAttachment(O.x))") } + + + // Ensure SingletonTypeTree#ref is typed and it has symbol after typing. + // see: https://github.com/scala/bug/issues/12296 + @Test + def singletonTypeTreeRefTyped(): Unit = { + val code = + """|object root { + | object impl + | val f: impl.type => Unit = { + | case _: impl.type => () + | } + |} + """.stripMargin + val run = compiler.newRun + run.compileSources(List(BytecodeTesting.makeSourceFile(code, "UnitTestSingletonTypeTreeSource.scala"))) + val tree = run.units.next().body + + import compiler.global._ + + val singletonTypeTrees = new collection.mutable.MutableList[SingletonTypeTree] + object traverser extends Traverser { + override def traverse(t: Tree): Unit = { + t match { + case tt: TypeTree if tt.original != null => traverse(tt.original) + case st: SingletonTypeTree => + singletonTypeTrees += st + case _ => super.traverse(t) + } + } + } + traverser.traverse(tree) + + singletonTypeTrees.foreach { t => + assertEquals(t.ref.symbol.fullName, "root.impl") + } + } } From 288926661da4cc8d1b53a6aadb451524f5c89745 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Tue, 12 Jan 2021 13:31:04 +0100 Subject: [PATCH 28/59] Fix release script for sbt 1.x update Backport of scala/scala#7274 --- admin/init.sh | 4 ++-- scripts/common | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/admin/init.sh b/admin/init.sh index 9c3723542e9c..a07934cec719 100755 --- a/admin/init.sh +++ b/admin/init.sh @@ -15,5 +15,5 @@ sensitive >/dev/null 2>&1 gpg --list-keys gpg --list-secret-keys -mkdir -p ~/.sbt/0.13/plugins -cp files/gpg.sbt ~/.sbt/0.13/plugins/ +mkdir -p ~/.sbt/1.0/plugins +cp files/gpg.sbt ~/.sbt/1.0/plugins/ diff --git a/scripts/common b/scripts/common index f7d116f79c29..23c1c334b59d 100644 --- a/scripts/common +++ b/scripts/common @@ -88,7 +88,7 @@ function checkAvailability () { # Only used on Jenkins # Generate a repositories file with all allowed repositories in our build environment. # Takes a variable number of additional repositories as argument. -# See http://www.scala-sbt.org/0.13/docs/Proxy-Repositories.html +# See https://www.scala-sbt.org/1.0/docs/Proxy-Repositories.html function generateRepositoriesConfig() { echo > "$sbtRepositoryConfig" '[repositories]' if [[ $# -gt 0 ]]; then From 60b503bcfdd61e086fa6b978c38009f2604dd365 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Tue, 12 Jan 2021 15:34:20 +0100 Subject: [PATCH 29/59] give sonatype more time to close staging repos --- scripts/bootstrap_fun | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/bootstrap_fun b/scripts/bootstrap_fun index d92591514ba1..f657665811e1 100644 --- a/scripts/bootstrap_fun +++ b/scripts/bootstrap_fun @@ -287,11 +287,11 @@ constructUpdatedModuleVersions() { pollForStagingReposClosed() { OK=false - for i in $(seq 1 10); do + for i in $(seq 1 20); do OK=true for repo in $1; do if [[ "$(st_stagingRepoStatus $repo)" != "closed" ]]; then - echo "Staging repo $repo not yet closed, waiting 30 seconds ($i / 10)" + echo "Staging repo $repo not yet closed, waiting 30 seconds ($i / 20)" OK=false break fi @@ -301,7 +301,7 @@ pollForStagingReposClosed() { done if [ "$OK" = "false" ]; then - echo "Failed to close staging repos in 5 minutes: $1" + echo "Failed to close staging repos in 10 minutes: $1" exit 1 fi } From 457c7b44c4ca0a26c28bc5b1aceba2b53cfb5c19 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Tue, 12 Jan 2021 18:17:39 -0800 Subject: [PATCH 30/59] re-STARR on 2.12.13 --- build.sbt | 2 +- src/intellij/scala.ipr.SAMPLE | 10 +++++----- versions.properties | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build.sbt b/build.sbt index cdd402688fe4..578bee257f8c 100644 --- a/build.sbt +++ b/build.sbt @@ -92,7 +92,7 @@ lazy val publishSettings : Seq[Setting[_]] = Seq( // should not be set directly. It is the same as the Maven version and derived automatically from `baseVersion` and // `baseVersionSuffix`. globalVersionSettings -baseVersion in Global := "2.12.13" +baseVersion in Global := "2.12.14" baseVersionSuffix in Global := "SNAPSHOT" organization in ThisBuild := "org.scala-lang" homepage in ThisBuild := Some(url("https://www.scala-lang.org")) diff --git a/src/intellij/scala.ipr.SAMPLE b/src/intellij/scala.ipr.SAMPLE index 4a3de1caed3d..755999c6e54f 100644 --- a/src/intellij/scala.ipr.SAMPLE +++ b/src/intellij/scala.ipr.SAMPLE @@ -308,7 +308,7 @@ - + @@ -544,9 +544,9 @@ - - - + + + @@ -573,4 +573,4 @@ - \ No newline at end of file + diff --git a/versions.properties b/versions.properties index 4958952cacd1..46c0be31da9f 100644 --- a/versions.properties +++ b/versions.properties @@ -1,5 +1,5 @@ # Scala version used for bootstrapping (see README.md) -starr.version=2.12.12 +starr.version=2.12.13 # The scala.binary.version determines how modules are resolved. It is set as follows: # - After 2.x.0 is released, the binary version is 2.x From 2ebf54dafeac8118b439c437c0aa4544bbb82743 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Tue, 29 Oct 2019 14:49:33 +0100 Subject: [PATCH 31/59] Fix box-unbox around branches - Support `pop` as BoxConsumer - consumer of box creation may be the consumer for multiple values Inspired by the tuple cases; extended to the ref/primitive cases. Co-Authored-By: "Harrison Houghton" --- .../tools/nsc/backend/jvm/opt/BoxUnbox.scala | 57 ++++++++++++------- .../nsc/backend/jvm/opt/BoxUnboxTest.scala | 37 +++++++++++- 2 files changed, 74 insertions(+), 20 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala index b5bd0546c2a5..2eda2438d5b9 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala @@ -264,6 +264,9 @@ abstract class BoxUnbox { case c: EscapingConsumer => assert(keepBox, s"found escaping consumer, but box is eliminated: $c") + case Drop(insn) => + if (keepBox) toReplace(insn) = List(getPop(1)) + case extraction => val (slot, tp) = localSlots(boxKind.extractedValueIndex(extraction)) val loadOps = new VarInsnNode(tp.getOpcode(ILOAD), slot) :: extraction.postExtractionAdaptationOps(tp) @@ -326,31 +329,38 @@ abstract class BoxUnbox { if (boxKind.boxedTypes.lengthCompare(1) == 0) { // fast path for single-value boxes allConsumers.foreach(extraction => extraction.postExtractionAdaptationOps(boxKind.boxedTypes.head) match { - case Nil => - toDelete ++= extraction.allInsns + case Nil => extraction match { + case Drop(_) => toReplace(extraction.consumer) = boxKind.boxedTypes.map(t => getPop(t.getSize)) + case _ => toDelete ++= extraction.allInsns + } case ops => toReplace(extraction.consumer) = ops toDelete ++= extraction.allInsns - extraction.consumer }) } else { for (extraction <- allConsumers) { - val valueIndex = boxKind.extractedValueIndex(extraction) - val replacementOps = if (valueIndex == 0) { - val pops = boxKind.boxedTypes.tail.map(t => getPop(t.getSize)) - pops ::: extraction.postExtractionAdaptationOps(boxKind.boxedTypes.head) - } else { - var loadOps: List[AbstractInsnNode] = null - val consumeStack = boxKind.boxedTypes.zipWithIndex reverseMap { - case (tp, i) => - if (i == valueIndex) { - val resultSlot = getLocal(tp.getSize) - loadOps = new VarInsnNode(tp.getOpcode(ILOAD), resultSlot) :: extraction.postExtractionAdaptationOps(tp) - new VarInsnNode(tp.getOpcode(ISTORE), resultSlot) - } else { - getPop(tp.getSize) + val replacementOps = extraction match { + case Drop(_) => + boxKind.boxedTypes.map(t => getPop(t.getSize)) + case _ => + val valueIndex = boxKind.extractedValueIndex(extraction) + if (valueIndex == 0) { + val pops = boxKind.boxedTypes.tail.map(t => getPop(t.getSize)) + pops ::: extraction.postExtractionAdaptationOps(boxKind.boxedTypes.head) + } else { + var loadOps: List[AbstractInsnNode] = null + val consumeStack = boxKind.boxedTypes.zipWithIndex reverseMap { + case (tp, i) => + if (i == valueIndex) { + val resultSlot = getLocal(tp.getSize) + loadOps = new VarInsnNode(tp.getOpcode(ILOAD), resultSlot) :: extraction.postExtractionAdaptationOps(tp) + new VarInsnNode(tp.getOpcode(ISTORE), resultSlot) + } else { + getPop(tp.getSize) + } } - } - consumeStack ::: loadOps + consumeStack ::: loadOps + } } toReplace(extraction.consumer) = replacementOps toDelete ++= extraction.allInsns - extraction.consumer @@ -617,7 +627,7 @@ abstract class BoxUnbox { val afterInit = initCall.getNext val stackTopAfterInit = prodCons.frameAt(afterInit).stackTop val initializedInstanceCons = prodCons.consumersOfValueAt(afterInit, stackTopAfterInit) - if (initializedInstanceCons == dupConsWithoutInit && prodCons.producersForValueAt(afterInit, stackTopAfterInit) == Set(dupOp)) { + if (initializedInstanceCons == dupConsWithoutInit) { return Some((dupOp, initCall)) } } @@ -704,6 +714,9 @@ abstract class BoxUnbox { val success = primBoxSupertypes(kind.boxClass).contains(ti.desc) Some(BoxedPrimitiveTypeCheck(ti, success)) + case i: InsnNode if i.getOpcode == POP => + Some(Drop(i)) + case _ => None } } @@ -757,6 +770,9 @@ abstract class BoxUnbox { case ti: TypeInsnNode if ti.getOpcode == INSTANCEOF => Some(BoxedPrimitiveTypeCheck(ti, ti.desc == kind.refClass || refSupertypes.contains(ti.desc))) + case i: InsnNode if i.getOpcode == POP => + Some(Drop(i)) + case _ => None } } @@ -820,6 +836,7 @@ abstract class BoxUnbox { } case _ => + if (insn.getOpcode == POP) return Some(Drop(insn)) } None } @@ -939,6 +956,8 @@ abstract class BoxUnbox { case class StaticSetterOrInstanceWrite(consumer: AbstractInsnNode) extends BoxConsumer /** `.\$isInstanceOf[T]` (can be statically proven true or false) */ case class BoxedPrimitiveTypeCheck(consumer: AbstractInsnNode, success: Boolean) extends BoxConsumer + /** POP */ + case class Drop(consumer: AbstractInsnNode) extends BoxConsumer /** An unknown box consumer */ case class EscapingConsumer(consumer: AbstractInsnNode) extends BoxConsumer } diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala index f38ba64fc4fd..07d8a24a8329 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala @@ -146,6 +146,13 @@ class BoxUnboxTest extends BytecodeTesting { | bi + li | } | + | def t17(x: Int) = { // this one's pretty contrived but tests that primitives can be unboxed through a branch + | val wat: Any = if (x > 0) x else -x + | wat match { + | case i: Int => String valueOf i + | case _ => "?" + | } + | } |} """.stripMargin @@ -199,10 +206,11 @@ class BoxUnboxTest extends BytecodeTesting { assertDoesNotInvoke(getInstructions(c, "t16"), "boxToLong") assertDoesNotInvoke(getInstructions(c, "t16"), "unboxToInt") assertDoesNotInvoke(getInstructions(c, "t16"), "unboxToLong") + assertDoesNotInvoke(getMethod(c, "t17"), "boxToInteger") } @Test - def refEliminiation(): Unit = { + def refElimination(): Unit = { val code = """class C { | import runtime._ @@ -245,6 +253,12 @@ class BoxUnboxTest extends BytecodeTesting { | val res: IntRef = if (b) r1 else r2 | res.elem // boxes remain: can't rewrite this read, don't know which local | } + | + | // this case is contemplated by BoxUnbox despite my inability to provide a motivating example + | def t7(b: Boolean) = { + | val r1 = if (b) IntRef.zero() else IntRef.create(1) + | r1.elem + | } |} """.stripMargin val c = compileClass(code) @@ -256,6 +270,7 @@ class BoxUnboxTest extends BytecodeTesting { List("scala/runtime/IntRef.elem")) assertEquals(getInstructions(c, "t6") collect { case Field(op, owner, name, _) => s"$op $owner.$name" }, List(s"$PUTFIELD scala/runtime/IntRef.elem", s"$GETFIELD scala/runtime/IntRef.elem")) + assertNoInvoke(getMethod(c, "t7")) } @Test @@ -309,6 +324,21 @@ class BoxUnboxTest extends BytecodeTesting { | case (x, y) if x == y => 0 | case (x, y) => x + y | } + | + | def t10(a: Int, b: Int) = { // tuple is optimized away + | val (greater, lesser) = if (a > b) (a, b) else (b, a) + | greater - lesser + | } + | + | def t11(n: Int)(j: Int) = { // tuple is optimized away + | val (a, b, c, _) = n match { + | case 0 => (j, 0, 1, 1) + | case 1 => (0, j, 0, 1) + | case 2 => (1, 0, j, 0) + | case 3 => (1, 1, 0, j) + | } + | a + b + c + | } |} """.stripMargin val c = compileClass(code, allowMessage = (info: StoreReporter.Info) => info.msg.contains("there was one deprecation warning")) @@ -328,6 +358,11 @@ class BoxUnboxTest extends BytecodeTesting { ILOAD, ILOAD, IADD, ILOAD, IADD, IRETURN)) assertNoInvoke(getMethod(c, "t8")) assertNoInvoke(getMethod(c, "t9")) + assertNoInvoke(getMethod(c, "t10")) + assertInvokedMethods(getMethod(c, "t11"), List( + "scala/runtime/BoxesRunTime.boxToInteger", // only once, for the MatchError + "scala/MatchError.", + )) } } From e5ff46e361c696c64cadd0910b1e1a61545c259f Mon Sep 17 00:00:00 2001 From: Andrii Date: Wed, 13 Jan 2021 11:22:39 +0200 Subject: [PATCH 32/59] Fix typo in comment in Names.scala --- src/reflect/scala/reflect/internal/Names.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala index 5ab13cd8cc1e..8e3f8fcab91f 100644 --- a/src/reflect/scala/reflect/internal/Names.scala +++ b/src/reflect/scala/reflect/internal/Names.scala @@ -215,7 +215,7 @@ trait Names extends api.Names { /** The length of this name. */ final def length: Int = len final def nonEmpty = !isEmpty - // This method is implements NameHasIsEmpty, and overrides CharSequence's isEmpty on JDK 15+ + // This method implements NameHasIsEmpty, and overrides CharSequence's isEmpty on JDK 15+ override final def isEmpty = length == 0 def nameKind: String From b990bff0e9448a338a72832e12b03ee7e347e621 Mon Sep 17 00:00:00 2001 From: mkeskells Date: Mon, 16 Nov 2020 23:12:38 +0000 Subject: [PATCH 33/59] Deletion from a TreeSet/TreeMap of a key that doesn't exist should not allocate pass the tree into balance/balLeft/balRight methods so that is can be reused is unchanged prefer use of isBlack/isRed to isRedTree when we know the tree is not null --- .../collection/immutable/RedBlackTree.scala | 173 ++++++++++++------ .../collection/immutable/TreeMapTest.scala | 8 + .../collection/immutable/TreeSetTest.scala | 6 + 3 files changed, 126 insertions(+), 61 deletions(-) diff --git a/src/library/scala/collection/immutable/RedBlackTree.scala b/src/library/scala/collection/immutable/RedBlackTree.scala index 7717feb97d83..d800814a377e 100644 --- a/src/library/scala/collection/immutable/RedBlackTree.scala +++ b/src/library/scala/collection/immutable/RedBlackTree.scala @@ -211,19 +211,25 @@ private[collection] object NewRedBlackTree { def tail[A, B](tree: Tree[A, B]): Tree[A, B] = { def _tail(tree: Tree[A, B]): Tree[A, B] = - if(tree eq null) throw new NoSuchElementException("empty tree") - else if(tree.left eq null) tree.right - else if(isBlackTree(tree.left)) balLeft(tree.key, tree.value, _tail(tree.left), tree.right) - else RedTree(tree.key, tree.value, _tail(tree.left), tree.right) + if (tree eq null) throw new NoSuchElementException("empty tree") + else { + val tl = tree.left + if (tl eq null) tree.right + else if (tl.isBlack) balLeft(tree, _tail(tl), tree.right) + else tree.redWithLeft(_tail(tree.left)) + } blacken(_tail(tree)) } def init[A, B](tree: Tree[A, B]): Tree[A, B] = { def _init(tree: Tree[A, B]): Tree[A, B] = - if(tree eq null) throw new NoSuchElementException("empty tree") - else if(tree.right eq null) tree.left - else if(isBlackTree(tree.right)) balRight(tree.key, tree.value, tree.left, _init(tree.right)) - else RedTree(tree.key, tree.value, tree.left, _init(tree.right)) + if (tree eq null) throw new NoSuchElementException("empty tree") + else { + val tr = tree.right + if (tr eq null) tree.left + else if (tr.isBlack) balRight(tree, tree.left, _init(tr)) + else tree.redWithRight(_init(tr)) + } blacken(_init(tree)) } @@ -306,7 +312,7 @@ private[collection] object NewRedBlackTree { else tree } - def isBlack(tree: Tree[_, _]) = (tree eq null) || isBlackTree(tree) + def isBlack(tree: Tree[_, _]) = (tree eq null) || tree.isBlack @`inline` private[this] def isRedTree(tree: Tree[_, _]) = (tree ne null) && tree.isRed @`inline` private[this] def isBlackTree(tree: Tree[_, _]) = (tree ne null) && tree.isBlack @@ -318,8 +324,10 @@ private[collection] object NewRedBlackTree { private[this] def maybeBlacken[A, B](t: Tree[A, B]): Tree[A, B] = if(isBlack(t)) t else if(isRedTree(t.left) || isRedTree(t.right)) t.black else t - private[this] def mkTree[A, B](isBlack: Boolean, k: A, v: B, l: Tree[A, B], r: Tree[A, B]) = - if (isBlack) BlackTree(k, v, l, r) else RedTree(k, v, l, r) + private[this] def mkTree[A, B](isBlack: Boolean, key: A, value: B, left: Tree[A, B], right: Tree[A, B]) = { + val sizeAndColour = sizeOf(left) + sizeOf(right) + 1 | (if(isBlack) initialBlackCount else initialRedCount) + new Tree(key, value.asInstanceOf[AnyRef], left, right, sizeAndColour) + } /** Create a new balanced tree where `newLeft` replaces `tree.left`. */ private[this] def balanceLeft[A, B1](tree: Tree[A, B1], newLeft: Tree[A, B1]): Tree[A, B1] = { @@ -722,6 +730,15 @@ private[collection] object NewRedBlackTree { new Tree(key, value.asInstanceOf[AnyRef], newLeft, _right, initialBlackCount | size) } } + private[NewRedBlackTree] def redWithLeft[B1 >: B](newLeft: Tree[A, B1]): Tree[A, B1] = { + //assertNotMutable(this) + //assertNotMutable(newLeft) + if ((newLeft eq _left) && isRed) this + else { + val size = sizeOf(newLeft) + sizeOf(_right) + 1 + new Tree(key, value.asInstanceOf[AnyRef], newLeft, _right, initialRedCount | size) + } + } private[NewRedBlackTree] def blackWithRight[B1 >: B](newRight: Tree[A, B1]): Tree[A, B1] = { //assertNotMutable(this) //assertNotMutable(newRight) @@ -731,6 +748,15 @@ private[collection] object NewRedBlackTree { new Tree(key, value.asInstanceOf[AnyRef], _left, newRight, initialBlackCount | size) } } + private[NewRedBlackTree] def redWithRight[B1 >: B](newRight: Tree[A, B1]): Tree[A, B1] = { + //assertNotMutable(this) + //assertNotMutable(newLeft) + if ((newRight eq _right) && isRed) this + else { + val size = sizeOf(_left) + sizeOf(newRight) + 1 + new Tree(key, value.asInstanceOf[AnyRef], _left, newRight, initialRedCount | size) + } + } private[NewRedBlackTree] def withLeftRight[B1 >: B](newLeft: Tree[A, B1], newRight: Tree[A, B1]): Tree[A, B1] = { //assertNotMutable(this) //assertNotMutable(newLeft) @@ -741,6 +767,26 @@ private[collection] object NewRedBlackTree { new Tree(key, value.asInstanceOf[AnyRef], newLeft, newRight, (_count & colourBit) | size) } } + private[NewRedBlackTree] def redWithLeftRight[B1 >: B](newLeft: Tree[A, B1], newRight: Tree[A, B1]): Tree[A, B1] = { + //assertNotMutable(this) + //assertNotMutable(newLeft) + //assertNotMutable(newRight) + if ((newLeft eq _left) && (newRight eq _right) && isRed) this + else { + val size = sizeOf(newLeft) + sizeOf(newRight) + 1 + new Tree(key, value.asInstanceOf[AnyRef], newLeft, newRight, initialRedCount | size) + } + } + private[NewRedBlackTree] def blackWithLeftRight[B1 >: B](newLeft: Tree[A, B1], newRight: Tree[A, B1]): Tree[A, B1] = { + //assertNotMutable(this) + //assertNotMutable(newLeft) + //assertNotMutable(newRight) + if ((newLeft eq _left) && (newRight eq _right) && isBlack) this + else { + val size = sizeOf(newLeft) + sizeOf(newRight) + 1 + new Tree(key, value.asInstanceOf[AnyRef], newLeft, newRight, initialBlackCount | size) + } + } } //see #Tree docs "Colour, mutablity and size encoding" //we make these final vals because the optimiser inlines them, without reference to the enclosing module @@ -956,7 +1002,7 @@ private[collection] object NewRedBlackTree { if((v2.asInstanceOf[AnyRef] eq v.asInstanceOf[AnyRef]) && (l2 eq l) && (r2 eq r)) t.asInstanceOf[Tree[A, C]] - else mkTree(isBlackTree(t), k, v2, l2, r2) + else mkTree(t.isBlack, k, v2, l2, r2) } def filterEntries[A, B](t: Tree[A, B], f: (A, B) => Boolean): Tree[A, B] = if(t eq null) null else { @@ -1064,67 +1110,72 @@ private[collection] object NewRedBlackTree { // Red-Black Trees in a Functional Setting, Chris Okasaki: [[https://wiki.rice.edu/confluence/download/attachments/2761212/Okasaki-Red-Black.pdf]] */ private[this] def del[A, B](tree: Tree[A, B], k: A)(implicit ordering: Ordering[A]): Tree[A, B] = if (tree eq null) null else { - def delLeft = - if (isBlackTree(tree.left)) balLeft(tree.key, tree.value, del(tree.left, k), tree.right) - else RedTree(tree.key, tree.value, del(tree.left, k), tree.right) - def delRight = - if (isBlackTree(tree.right)) balRight(tree.key, tree.value, tree.left, del(tree.right, k)) - else RedTree(tree.key, tree.value, tree.left, del(tree.right, k)) val cmp = ordering.compare(k, tree.key) - if (cmp < 0) delLeft - else if (cmp > 0) delRight - else append(tree.left, tree.right) + if (cmp < 0) { + val newLeft = del(tree.left, k) + if (newLeft eq tree.left) tree + else if (isBlackTree(tree.left)) balLeft(tree, newLeft, tree.right) + else tree.redWithLeft(newLeft) + } else if (cmp > 0) { + val newRight = del(tree.right, k) + if (newRight eq tree.right) tree + else if (isBlackTree(tree.right)) balRight(tree, tree.left, newRight) + else tree.redWithRight(newRight) + } else append(tree.left, tree.right) } - private[this] def balance[A, B](x: A, xv: B, tl: Tree[A, B], tr: Tree[A, B]) = + private[this] def balance[A, B](tree: Tree[A,B], tl: Tree[A, B], tr: Tree[A, B]): Tree[A, B] = if (isRedTree(tl)) { - if (isRedTree(tr)) RedTree(x, xv, tl.black, tr.black) - else if (isRedTree(tl.left)) RedTree(tl.key, tl.value, tl.left.black, BlackTree(x, xv, tl.right, tr)) - else if (isRedTree(tl.right)) - RedTree(tl.right.key, tl.right.value, BlackTree(tl.key, tl.value, tl.left, tl.right.left), BlackTree(x, xv, tl.right.right, tr)) - else BlackTree(x, xv, tl, tr) + if (isRedTree(tr)) tree.redWithLeftRight(tl.black, tr.black) + else if (isRedTree(tl.left)) tl.withLeftRight(tl.left.black, tree.blackWithLeftRight(tl.right, tr)) + else if (isRedTree(tl.right)) tl.right.withLeftRight(tl.blackWithRight(tl.right.left), tree.blackWithLeftRight(tl.right.right, tr)) + else tree.blackWithLeftRight(tl, tr) } else if (isRedTree(tr)) { - if (isRedTree(tr.right)) RedTree(tr.key, tr.value, BlackTree(x, xv, tl, tr.left), tr.right.black) - else if (isRedTree(tr.left)) - RedTree(tr.left.key, tr.left.value, BlackTree(x, xv, tl, tr.left.left), BlackTree(tr.key, tr.value, tr.left.right, tr.right)) - else BlackTree(x, xv, tl, tr) - } else BlackTree(x, xv, tl, tr) - - private[this] def balLeft[A, B](x: A, xv: B, tl: Tree[A, B], tr: Tree[A, B]) = - if (isRedTree(tl)) RedTree(x, xv, tl.black, tr) - else if (isBlackTree(tr)) balance(x, xv, tl, tr.red) + if (isRedTree(tr.right)) tr.withLeftRight(tree.blackWithLeftRight(tl, tr.left), tr.right.black) + else if (isRedTree(tr.left)) tr.left.withLeftRight(tree.blackWithLeftRight(tl, tr.left.left), tr.blackWithLeftRight(tr.left.right, tr.right)) + else tree.blackWithLeftRight(tl, tr) + } else tree.blackWithLeftRight(tl, tr) + + private[this] def balLeft[A, B](tree: Tree[A,B], tl: Tree[A, B], tr: Tree[A, B]): Tree[A, B] = + if (isRedTree(tl)) tree.redWithLeftRight(tl.black, tr) + else if (isBlackTree(tr)) balance(tree, tl, tr.red) else if (isRedTree(tr) && isBlackTree(tr.left)) - RedTree(tr.left.key, tr.left.value, BlackTree(x, xv, tl, tr.left.left), balance(tr.key, tr.value, tr.left.right, tr.right.red)) + tr.left.redWithLeftRight(tree.blackWithLeftRight(tl, tr.left.left), balance(tr, tr.left.right, tr.right.red)) else sys.error("Defect: invariance violation") - private[this] def balRight[A, B](x: A, xv: B, tl: Tree[A, B], tr: Tree[A, B]) = - if (isRedTree(tr)) RedTree(x, xv, tl, tr.black) - else if (isBlackTree(tl)) balance(x, xv, tl.red, tr) + private[this] def balRight[A, B](tree: Tree[A,B], tl: Tree[A, B], tr: Tree[A, B]): Tree[A, B] = + if (isRedTree(tr)) tree.redWithLeftRight(tl, tr.black) + else if (isBlackTree(tl)) balance(tree, tl.red, tr) else if (isRedTree(tl) && isBlackTree(tl.right)) - RedTree(tl.right.key, tl.right.value, balance(tl.key, tl.value, tl.left.red, tl.right.left), BlackTree(x, xv, tl.right.right, tr)) + tl.right.redWithLeftRight(balance(tl, tl.left.red, tl.right.left), tree.blackWithLeftRight(tl.right.right, tr)) else sys.error("Defect: invariance violation") /** `append` is similar to `join2` but requires that both subtrees have the same black height */ - private[this] def append[A, B](tl: Tree[A, B], tr: Tree[A, B]): Tree[A, B] = + private[this] def append[A, B](tl: Tree[A, B], tr: Tree[A, B]): Tree[A, B] = { if (tl eq null) tr else if (tr eq null) tl - else if (isRedTree(tl) && isRedTree(tr)) { - val bc = append(tl.right, tr.left) - if (isRedTree(bc)) { - RedTree(bc.key, bc.value, RedTree(tl.key, tl.value, tl.left, bc.left), RedTree(tr.key, tr.value, bc.right, tr.right)) - } else { - RedTree(tl.key, tl.value, tl.left, RedTree(tr.key, tr.value, bc, tr.right)) - } - } else if (isBlackTree(tl) && isBlackTree(tr)) { - val bc = append(tl.right, tr.left) - if (isRedTree(bc)) { - RedTree(bc.key, bc.value, BlackTree(tl.key, tl.value, tl.left, bc.left), BlackTree(tr.key, tr.value, bc.right, tr.right)) - } else { - balLeft(tl.key, tl.value, tl.left, BlackTree(tr.key, tr.value, bc, tr.right)) - } - } else if (isRedTree(tr)) RedTree(tr.key, tr.value, append(tl, tr.left), tr.right) - else if (isRedTree(tl)) RedTree(tl.key, tl.value, tl.left, append(tl.right, tr)) - else sys.error("unmatched tree on append: " + tl + ", " + tr) + else if (tl.isRed) { + if (tr.isRed) { + //tl is red, tr is red + val bc = append(tl.right, tr.left) + if (isRedTree(bc)) bc.withLeftRight(tl.withRight(bc.left), tr.withLeft(bc.right)) + else tl.withRight(tr.withLeft(bc)) + } else { + //tl is red, tr is black + tl.withRight(append(tl.right, tr)) + } + } else { + if (tr.isBlack) { + //tl is black tr is black + val bc = append(tl.right, tr.left) + if (isRedTree(bc)) bc.withLeftRight(tl.withRight(bc.left), tr.withLeft(bc.right)) + else balLeft(tl, tl.left, tr.withLeft(bc)) + } else { + //tl is black tr is red + tr.withLeft(append(tl, tr.left)) + } + } + } // Bulk operations based on "Just Join for Parallel Ordered Sets" (https://www.cs.cmu.edu/~guyb/papers/BFS16.pdf) @@ -1142,7 +1193,7 @@ private[collection] object NewRedBlackTree { /** Compute the rank from a tree and its black height */ @`inline` private[this] def rank(t: Tree[_, _], bh: Int): Int = { if(t eq null) 0 - else if(isBlackTree(t)) 2*(bh-1) + else if(t.isBlack) 2*(bh-1) else 2*bh-1 } @@ -1178,7 +1229,7 @@ private[collection] object NewRedBlackTree { private[this] def join[A, B](tl: Tree[A, B], k: A, v: B, tr: Tree[A, B]): Tree[A, B] = { @tailrec def h(t: Tree[_, _], i: Int): Int = - if(t eq null) i+1 else h(t.left, if(isBlackTree(t)) i+1 else i) + if(t eq null) i+1 else h(t.left, if(t.isBlack) i+1 else i) val bhtl = h(tl, 0) val bhtr = h(tr, 0) if(bhtl > bhtr) { diff --git a/test/junit/scala/collection/immutable/TreeMapTest.scala b/test/junit/scala/collection/immutable/TreeMapTest.scala index e96a7f059622..f54649dcef5c 100644 --- a/test/junit/scala/collection/immutable/TreeMapTest.scala +++ b/test/junit/scala/collection/immutable/TreeMapTest.scala @@ -228,4 +228,12 @@ class TreeMapTest extends AllocationTest { assertEquals(Map("A" -> "2"), r) } + + @Test def removeNonContent(): Unit = { + val src: Map[Int, String] = TreeMap(Range(0, 100, 2).map((_, "")) :_*) + for (i <- Range(-1, 101, 2)) { + src - i + assertSame(i.toString, src, nonAllocating(src - i, text = i.toString)) + } + } } diff --git a/test/junit/scala/collection/immutable/TreeSetTest.scala b/test/junit/scala/collection/immutable/TreeSetTest.scala index 3c8cd577f7af..495df41edb33 100644 --- a/test/junit/scala/collection/immutable/TreeSetTest.scala +++ b/test/junit/scala/collection/immutable/TreeSetTest.scala @@ -288,4 +288,10 @@ class TreeSetTest extends AllocationTest{ assertEquals(expected, src filter set) } } + @Test def removeNonContent(): Unit = { + val src = TreeSet(Range(0, 100, 2) :_*) + for (i <- Range(-1, 101, 2)) { + assertSame(src, nonAllocating(src - i)) + } + } } From bc742216fda4e311104d16920341b802ad88e8d2 Mon Sep 17 00:00:00 2001 From: mkeskells Date: Mon, 8 Jun 2020 00:16:11 +0100 Subject: [PATCH 34/59] de-duplicate code code filter and partition is common other than the supplied function --- .../collection/immutable/RedBlackTree.scala | 49 ------------------- .../scala/collection/immutable/TreeSet.scala | 4 +- 2 files changed, 2 insertions(+), 51 deletions(-) diff --git a/src/library/scala/collection/immutable/RedBlackTree.scala b/src/library/scala/collection/immutable/RedBlackTree.scala index 7717feb97d83..02d6f429235d 100644 --- a/src/library/scala/collection/immutable/RedBlackTree.scala +++ b/src/library/scala/collection/immutable/RedBlackTree.scala @@ -975,21 +975,6 @@ private[collection] object NewRedBlackTree { blacken(fk(t)) } - def filterKeys[A, B](t: Tree[A, B], f: A => Boolean, isFlipped: Boolean): Tree[A, B] = if(t eq null) null else { - def fk(t: Tree[A, B]): Tree[A, B] = { - val k = t.key - val l = t.left - val r = t.right - val l2 = if(l eq null) null else fk(l) - val keep = isFlipped ^ f(k) - val r2 = if(r eq null) null else fk(r) - if(!keep) join2(l2, r2) - else if((l2 eq l) && (r2 eq r)) t - else join(l2, k, t.value, r2) - } - blacken(fk(t)) - } - def partitionEntries[A, B](t: Tree[A, B], p: (A, B) => Boolean): (Tree[A, B], Tree[A, B]) = if(t eq null) (null, null) else { var tmpk, tmpd = null: Tree[A, B] // shared vars to avoid returning tuples from fk def fk(t: Tree[A, B]): Unit = { @@ -1024,40 +1009,6 @@ private[collection] object NewRedBlackTree { (blacken(tmpk), blacken(tmpd)) } - def partitionKeys[A, B](t: Tree[A, B], p: A => Boolean): (Tree[A, B], Tree[A, B]) = if(t eq null) (null, null) else { - var tmpk, tmpd = null: Tree[A, B] // shared vars to avoid returning tuples from fk - def fk(t: Tree[A, B]): Unit = { - val k = t.key - val v = t.value - val l = t.left - val r = t.right - var l2k, l2d, r2k, r2d = null: Tree[A, B] - if(l ne null) { - fk(l) - l2k = tmpk - l2d = tmpd - } - val keep = p(k) - if(r ne null) { - fk(r) - r2k = tmpk - r2d = tmpd - } - val jk = - if(!keep) join2(l2k, r2k) - else if((l2k eq l) && (r2k eq r)) t - else join(l2k, k, v, r2k) - val jd = - if(keep) join2(l2d, r2d) - else if((l2d eq l) && (r2d eq r)) t - else join(l2d, k, v, r2d) - tmpk = jk - tmpd = jd - } - fk(t) - (blacken(tmpk), blacken(tmpd)) - } - // Based on Stefan Kahrs' Haskell version of Okasaki's Red&Black Trees // Constructing Red-Black Trees, Ralf Hinze: [[http://www.cs.ox.ac.uk/ralf.hinze/publications/WAAAPL99b.ps.gz]] diff --git a/src/library/scala/collection/immutable/TreeSet.scala b/src/library/scala/collection/immutable/TreeSet.scala index 76bf678cb38e..3fc7a39e564f 100644 --- a/src/library/scala/collection/immutable/TreeSet.scala +++ b/src/library/scala/collection/immutable/TreeSet.scala @@ -292,10 +292,10 @@ final class TreeSet[A] private[immutable] (private[immutable] val tree: RB.Tree[ } override private[scala] def filterImpl(f: A => Boolean, isFlipped: Boolean) = - newSetOrSelf(RB.filterKeys(tree, f, isFlipped)) + newSetOrSelf(RB.filterEntries[A, Any](tree, {(k, _) => isFlipped ^ f(k)})) override def partition(p: A => Boolean): (TreeSet[A], TreeSet[A]) = { - val (l, r) = RB.partitionKeys(tree, p) + val (l, r) = RB.partitionEntries(tree, {(a:A, _: Any) => p(a)}) (newSetOrSelf(l), newSetOrSelf(r)) } From 789fe0dc93f1dd24bf489cf7f3924583cc348682 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Thu, 19 Nov 2020 15:24:27 +0000 Subject: [PATCH 35/59] [bport] Move & truncate the MiMa filters Backport cherry-pick of 710c91e076e7c4984b011e9777bfa5f45cbb401d. First of all, move the damn MiMa filters outside of build.sbt! In build.sbt it overpowers the rest of the build definition and also (it would seem) IntelliJ is better at handling Scala files than sbt files. Now, if a contributor needs to add filters, they can be advised to change "project/MimaFilters.scala". Secondly, bump the `mimaReferenceVersion` (which is used to define `mimaPreviousArtifacts`). Normal projects (without forwards compatibility) want to always bump that, so that new methods don't go missing. But for Scala it's less of a problem. However, it is because it means we have an always appended list of exclusions, and those might end up hiding real problems. While I was at it I fixed `mimaReportBinaryIssues` it can be called directly, by resetting `ThisBuild / mimaFailOnNoPrevious`. --- build.sbt | 482 +----------------------------------- project/BuildSettings.scala | 1 - project/MimaFilters.scala | 34 +++ 3 files changed, 38 insertions(+), 479 deletions(-) create mode 100644 project/MimaFilters.scala diff --git a/build.sbt b/build.sbt index 578bee257f8c..631c7b8516e8 100644 --- a/build.sbt +++ b/build.sbt @@ -32,10 +32,7 @@ * - to modularize the Scala compiler or library further */ -import sbt.{Global, TestResult} - -import scala.build._ -import VersionUtil._ +import scala.build._, VersionUtil._ // Scala dependencies: val scalaSwingDep = scalaDep("org.scala-lang.modules", "scala-swing") @@ -111,471 +108,6 @@ headerLicense in ThisBuild := Some(HeaderLicense.Custom( |""".stripMargin )) -Global / mimaReferenceVersion := Some("2.12.0") - -import com.typesafe.tools.mima.core._ -val mimaFilterSettings = Seq { - mimaBinaryIssueFilters ++= Seq( - ProblemFilters.exclude[IncompatibleSignatureProblem]("*"), - ProblemFilters.exclude[InaccessibleMethodProblem]("java.lang.Object."), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Vector.debug"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.VectorBuilder.debug"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.VectorPointer.debug"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.VectorIterator.debug"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.mutable.OpenHashMap.nextPositivePowerOfTwo"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.mutable.HashTable.powerOfTwo"), - ProblemFilters.exclude[MissingClassProblem]("scala.concurrent.impl.ExecutionContextImpl$AdaptedForkJoinTask"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.sys.process.ProcessImpl#CompoundProcess.getExitValue"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.sys.process.ProcessImpl#CompoundProcess.futureValue"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.sys.process.ProcessImpl#CompoundProcess.futureThread"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.mutable.HashTable.nextPositivePowerOfTwo"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.util.hashing.MurmurHash3.wrappedBytesHash"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.util.hashing.MurmurHash3.wrappedArrayHash"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap.contains0"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashTrieMap.contains0"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashMapCollision1.contains0"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashMap1.contains0"), - - ProblemFilters.exclude[MissingClassProblem]("scala.annotation.showAsInfix$"), - ProblemFilters.exclude[MissingClassProblem]("scala.annotation.showAsInfix"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.util.PropertiesTrait.coloredOutputEnabled"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.util.Properties.coloredOutputEnabled"), - - // https://github.com/scala/scala/pull/6101 - ProblemFilters.exclude[MissingTypesProblem]("scala.runtime.LazyRef"), - ProblemFilters.exclude[MissingTypesProblem]("scala.runtime.LazyDouble"), - ProblemFilters.exclude[MissingTypesProblem]("scala.runtime.LazyChar"), - ProblemFilters.exclude[MissingTypesProblem]("scala.runtime.LazyUnit"), - ProblemFilters.exclude[MissingTypesProblem]("scala.runtime.LazyShort"), - ProblemFilters.exclude[MissingTypesProblem]("scala.runtime.LazyInt"), - ProblemFilters.exclude[MissingTypesProblem]("scala.runtime.LazyByte"), - ProblemFilters.exclude[MissingTypesProblem]("scala.runtime.LazyLong"), - ProblemFilters.exclude[MissingTypesProblem]("scala.runtime.LazyBoolean"), - ProblemFilters.exclude[MissingTypesProblem]("scala.runtime.LazyFloat"), - ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.LazyRef.serialVersionUID"), - ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.LazyDouble.serialVersionUID"), - ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.LazyChar.serialVersionUID"), - ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.LazyUnit.serialVersionUID"), - ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.LazyShort.serialVersionUID"), - ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.LazyInt.serialVersionUID"), - ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.LazyByte.serialVersionUID"), - ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.LazyLong.serialVersionUID"), - ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.LazyBoolean.serialVersionUID"), - ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.LazyFloat.serialVersionUID"), - - // https://github.com/scala/scala/pull/6138 - ProblemFilters.exclude[MissingFieldProblem]("scala.collection.immutable.Map#EmptyMap.serialVersionUID"), - ProblemFilters.exclude[MissingFieldProblem]("scala.collection.immutable.Map#Map1.serialVersionUID"), - ProblemFilters.exclude[MissingFieldProblem]("scala.collection.immutable.Map#Map2.serialVersionUID"), - ProblemFilters.exclude[MissingFieldProblem]("scala.collection.immutable.Map#Map3.serialVersionUID"), - ProblemFilters.exclude[MissingFieldProblem]("scala.collection.immutable.Map#Map4.serialVersionUID"), - ProblemFilters.exclude[DirectAbstractMethodProblem]("scala.collection.GenTraversableOnce.toList"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap.foreachEntry"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.Map$HashCodeAccumulator"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashTrieMap.foreachEntry"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.ListMap.foreachEntry"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashMap1.foreachEntry"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashMapCollision1.foreachEntry"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.util.hashing.MurmurHash3.product2Hash"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.util.hashing.MurmurHash3.emptyMapHash"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.HashMap$HashMapKeys"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.HashMap$HashMapValues"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree.*"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.RedBlackTree$NList"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.RedBlackTree$NList$"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.RedBlackTree$EntriesIterator"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.RedBlackTree$ValuesIterator"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.RedBlackTree$TreeIterator"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.generic.SortedMapFactory#SortedMapCanBuildFrom.ordering"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#TreeIterator.ordering"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.TreeMap.removeAllImpl"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.TreeMap.filterImpl"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.TreeSet.tree"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.TreeSet.addAllTreeSetImpl"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.TreeSet.addAllImpl"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.TreeSet.removeAll"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.TreeSet.filterImpl"), - - ProblemFilters.exclude[MissingClassProblem]("scala.collection.package$WrappedCanBuildFrom"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.HashMap$HashMapBuilder"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#Merger.retainIdentical"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashTrieMap.size0"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashMap1.kv"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashMap1.kv_="), - - ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.collection.immutable.HashSet#HashSetCollision1.union0"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashSet#HashSetCollision1.union0"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashSet#HashSetCollision1.this"), - ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.collection.immutable.HashSet.union0"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashSet.union0"), - ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.collection.immutable.HashSet#HashTrieSet.union0"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashSet#HashTrieSet.union0"), - ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.collection.immutable.HashSet#HashSet1.union0"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashSet#HashSet1.union0"), - ProblemFilters.exclude[FinalMethodProblem]("scala.collection.immutable.HashSet#LeafHashSet.hash"), - ProblemFilters.exclude[DirectAbstractMethodProblem]("scala.collection.immutable.HashSet#LeafHashSet.hash"), - ProblemFilters.exclude[ReversedAbstractMethodProblem]("scala.collection.immutable.HashSet#LeafHashSet.hash"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashSet#LeafHashSet.this"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashSet.elemHashCode"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashSet.computeHash"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashSet.improve"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashSet#HashTrieSet.bitmap"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashSet#HashTrieSet.bitmap_="), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashSet#HashTrieSet.elems_="), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashSet#HashTrieSet.size0"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashSet#HashTrieSet.size0_="), - ProblemFilters.exclude[FinalMethodProblem]("scala.collection.immutable.HashSet#HashTrieSet.size"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.HashSet$HashSetBuilder"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.Set$SetBuilderImpl"), - - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.RedBlackTree$EqualsIterator"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#TreeIterator.findLeftMostOrPopOnEmpty"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#TreeIterator.popNext"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#TreeIterator.lookahead"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#TreeIterator.lookahead_="), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#TreeIterator.goRight"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#TreeIterator.stackOfNexts"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.TreeMap.this"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.TreeMap$TreeMapBuilder$adder$"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.TreeMap$TreeMapBuilder"), - - // Some static forwarder changes detected after a MiMa upgrade. - // e.g. static method apply(java.lang.Object)java.lang.Object in class scala.Symbol does not have a correspondent in current version - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.Symbol.apply"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.sys.process.Process.Future"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.sys.process.Process.Spawn"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.takeWhile"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.slice"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.drop"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.take"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.seq"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.seq"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.seq"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.seq"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.toSeq"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.reverse"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.toCollection"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.thisCollection"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.seq"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.andThen"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.view"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.view"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.dropRight"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.takeRight"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.takeWhile"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.drop"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.take"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.slice"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.head"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.thisCollection"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.seq"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.reversed"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.view"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.view"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.dropWhile"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.tail"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.thisCollection"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Nil.seq"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.List.empty"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Queue.empty"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Vector.empty"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Stream.iterate"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Stream.range"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Stream.tabulate"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Stream.fill"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Stream.empty"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.mutable.LinkedList.empty"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.util.Properties.scalaProps"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.util.Properties.propFilename"), - - // https://github.com/scala/scala/pull/8630 - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap.transformImpl"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashTrieMap.transformImpl"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashMap1.transformImpl"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashMapCollision1.transformImpl"), - - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.HasForeachEntry"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.TreeMap.foreachEntry"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Map#EmptyMap.foreachEntry"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Map#Map1.foreachEntry"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Map#Map2.foreachEntry"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Map#Map3.foreachEntry"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Map#Map4.foreachEntry"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.ListMap"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.TreeMap"), - ProblemFilters.exclude[MissingFieldProblem]("scala.collection.immutable.TreeMap.serialVersionUID"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.HashMap"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.HashMap$HashMap1"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.HashMap$HashTrieMap"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.HashMap$HashMapCollision1"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.ListMap$Node"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.ListMap$EmptyListMap$"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.HashMap$EmptyHashMap$"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.Map$Map1"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.Map$Map2"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.Map$Map3"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.Map$Map4"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.Map$EmptyMap$"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Map#Map1.addTo"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Map#Map2.addTo"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Map#Map3.addTo"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Map#Map4.addTo"), - - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.TreeSet$TreeSetBuilder"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.TreeSet.this"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.TreeSet$TreeSetBuilder$adder$"), - - ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.collection.immutable.SortedSet.scala$collection$immutable$SortedSet$$super=uals"), - ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.collection.immutable.SortedMap.scala$collection$immutable$SortedMap$$super=uals"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap.elemHashCode"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap.improve"), - ProblemFilters.exclude[FinalMethodProblem]("scala.collection.immutable.HashMap#HashTrieMap.bitmap"), - ProblemFilters.exclude[FinalMethodProblem]("scala.collection.immutable.HashMap#HashTrieMap.elems"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.Map$MapBuilderImpl"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.HashMap$HashMapBuilder"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashTrieMap.bitmap0"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashTrieMap.bitmap0_="), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashTrieMap.elems0"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashTrieMap.elems0_="), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashTrieMap.size0_="), - ProblemFilters.exclude[FinalMethodProblem]("scala.collection.immutable.HashMap#HashTrieMap.size"), - - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.Map$MapNIterator"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.Map$Map2$Map2Iterator"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.Map$Map3$Map3Iterator"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.Map$Map4$Map4Iterator"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.generic.SortedMapFactory#SortedMapCanBuildFrom.factory"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.generic.SortedSetFactory#SortedSetCanBuildFrom.factory"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.generic.SortedSetFactory#SortedSetCanBuildFrom.ordering"), - - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.TreeMap$TreeMapProxy"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.TreeMap.this"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.TreeSet$TreeSetProxy"), - //old red-black tree removed (mostly). Just kept for serialisation - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.RedBlackTree$RedTree$"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.RedBlackTree$EntriesIterator"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.RedBlackTree$KeysIterator"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.RedBlackTree$ValuesIterator"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.RedBlackTree$TreeIterator"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.RedBlackTree$BlackTree$"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#BlackTree.black"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#BlackTree.red"), - ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.collection.immutable.RedBlackTree#BlackTree.this"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#RedTree.black"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#RedTree.red"), - ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.collection.immutable.RedBlackTree#RedTree.this"), - ProblemFilters.exclude[IncompatibleResultTypeProblem]("scala.collection.immutable.RedBlackTree#Tree.left"), - ProblemFilters.exclude[IncompatibleResultTypeProblem]("scala.collection.immutable.RedBlackTree#Tree.right"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#Tree.black"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#Tree.red"), - ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.collection.immutable.RedBlackTree#Tree.this"), - ProblemFilters.exclude[MissingFieldProblem]("scala.collection.immutable.RedBlackTree#BlackTree.serialVersionUID"), - ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.collection.immutable.RedBlackTree#BlackTree.this"), - ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.collection.immutable.RedBlackTree#RedTree.this"), - ProblemFilters.exclude[MissingFieldProblem]("scala.collection.immutable.RedBlackTree#Tree.serialVersionUID"), - ProblemFilters.exclude[IncompatibleResultTypeProblem]("scala.collection.immutable.RedBlackTree#Tree.left"), - ProblemFilters.exclude[IncompatibleResultTypeProblem]("scala.collection.immutable.RedBlackTree#Tree.right"), - ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.collection.immutable.RedBlackTree#Tree.this"), - ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.collection.immutable.RedBlackTree#Tree.black"), - ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.collection.immutable.RedBlackTree#Tree.red"), - - //new red-black tree added - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.NewRedBlackTree$EntriesIterator"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.NewRedBlackTree$EqualsIterator"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.NewRedBlackTree$"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.NewRedBlackTree$ValuesIterator"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.NewRedBlackTree$Tree"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.NewRedBlackTree$KeysIterator"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.NewRedBlackTree"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.NewRedBlackTree$Helper"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.NewRedBlackTree$SetHelper"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.NewRedBlackTree$MapHelper"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.NewRedBlackTree$TreeIterator"), - ProblemFilters.exclude[MissingFieldProblem]("scala.collection.immutable.RedBlackTree#RedTree.serialVersionUID"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.TreeMap.tree0"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.TreeMap$Adder"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.Array.emptyUnitArray"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.*Tag.emptyArray"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.*Tag.emptyWrappedArray"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.*Manifest.emptyArray"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.*Manifest.emptyWrappedArray"), - - // - // scala-reflect - // - ProblemFilters.exclude[Problem]("scala.reflect.internal.*"), - ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.reflect.runtime.JavaMirrors#JavaMirror.unpickleClass"), - ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.reflect.runtime.SymbolLoaders#TopClassCompleter.this"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.SynchronizedOps#SynchronizedBaseTypeSeq.lateMap"), - ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.reflect.runtime.SynchronizedSymbols#SynchronizedSymbol.scala$reflect$runtime$SynchronizedSymbols$SynchronizedSymbol$$super$exists"), - ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.reflect.runtime.SynchronizedSymbols#SynchronizedSymbol.scala$reflect$runtime$SynchronizedSymbols$SynchronizedSymbol$$super$getFlag"), - ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.reflect.runtime.SynchronizedSymbols#SynchronizedSymbol.scala$reflect$runtime$SynchronizedSymbols$SynchronizedSymbol$$super$privateWithin"), - ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.reflect.runtime.SynchronizedSymbols#SynchronizedSymbol.scala$reflect$runtime$SynchronizedSymbols$SynchronizedSymbol$$super$annotations"), - ProblemFilters.exclude[MissingClassProblem]("scala.reflect.io.IOStats"), - ProblemFilters.exclude[MissingClassProblem]("scala.reflect.io.IOStats$"), - ProblemFilters.exclude[MissingTypesProblem]("scala.reflect.runtime.JavaUniverse"), - ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.reflect.io.ZipArchive.close"), - ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.reflect.io.ZipArchive.getDir"), - ProblemFilters.exclude[IncompatibleResultTypeProblem]("scala.reflect.io.FileZipArchive.allDirs"), - ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.reflect.runtime.SynchronizedSymbols#SynchronizedSymbol.scala$reflect$runtime$SynchronizedSymbols$SynchronizedSymbol$$super$typeConstructor"), - ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.reflect.runtime.SynchronizedTypes.scala$reflect$runtime$SynchronizedTypes$$super$defineNormalized"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.SynchronizedTypes.defineNormalized"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.JavaUniverse.defineNormalized"), - - ProblemFilters.exclude[Problem]("scala.reflect.internal.*"), - - ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.reflect.runtime.JavaMirrors#JavaMirror.unpickleClass"), - ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.reflect.runtime.SymbolLoaders#TopClassCompleter.this"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.Settings.Yvirtpatmat"), - ProblemFilters.exclude[MissingClassProblem]("scala.reflect.io.PlainNioFile"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.SynchronizedOps.newMappedBaseTypeSeq"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.JavaUniverse.newMappedBaseTypeSeq"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.JavaUniverse.statistics"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.JavaMirrors#JavaMirror#JavaAnnotationProxy.transformArgs"), - - ProblemFilters.exclude[MissingClassProblem]("scala.reflect.io.FileZipArchive$LazyEntry"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.ZipArchive.closeZipFile"), - ProblemFilters.exclude[MissingClassProblem]("scala.reflect.io.FileZipArchive$LeakyEntry"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.SynchronizedSymbols#SynchronizedSymbol.exists"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.SynchronizedSymbols#SynchronizedSymbol.getFlag"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.SynchronizedSymbols#SynchronizedSymbol.privateWithin"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.SynchronizedSymbols#SynchronizedSymbol.annotations"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.Settings.isScala213"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.FileZipArchive.this"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.ZipArchive.this"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.ZipArchive.getDir"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.FileZipArchive.allDirsByDottedName"), - - ProblemFilters.exclude[MissingClassProblem]("scala.reflect.io.RootPath"), - ProblemFilters.exclude[MissingClassProblem]("scala.reflect.io.RootPath$"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.URLZipArchive.close"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.FileZipArchive.close"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.ManifestResources.close"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.ZipArchive.close"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.JavaMirrors#JavaMirror.typeTag"), - ProblemFilters.exclude[MissingClassProblem]("scala.reflect.runtime.JavaMirrors$JavaMirror$typeTagCache$"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.api.TypeTags.TypeTagImpl"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.api.Universe.TypeTagImpl"), - - ProblemFilters.exclude[MissingClassProblem]("scala.reflect.macros.Attachments$"), - - ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.reflect.io.ZipArchive.getDir"), - ProblemFilters.exclude[IncompatibleResultTypeProblem]("scala.reflect.io.FileZipArchive.allDirs"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.SynchronizedSymbols#SynchronizedSymbol.typeConstructor"), - - ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.reflect.runtime.SynchronizedTypes.scala$reflect$runtime$SynchronizedTypes$$super$defineNormalized"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.SynchronizedTypes.defineNormalized"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.JavaUniverse.defineNormalized"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.AbstractFile.unsafeToByteArray"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.VirtualFile.unsafeToByteArray"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.ZipArchive#Entry.unsafeToByteArray"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.NoAbstractFile.unsafeToByteArray"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.JavaUniverse#PerRunReporting.deprecationWarning"), - ProblemFilters.exclude[MissingClassProblem]("scala.annotation.nowarn$"), - ProblemFilters.exclude[MissingClassProblem]("scala.annotation.nowarn"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.Settings#*.clearSetByUser"), - - // in current version, classes mixing scala.math.Ordering$FloatOrdering need be recompiled to wire to the new static mixin forwarder method all super calls to method reverse()scala.math.Ordering - // in current version, classes mixing scala.math.Ordering$DoubleOrdering .. reverse()scala.math.Ordering - // in other version, classes mixing scala.math.Ordering$IntOrdering .. reverse()scala.math.Ordering - // in other version, classes mixing scala.collection.IndexedSeqOptimized .. toList()scala.collection.immutable.List - // in other version, classes mixing scala.collection.LinearSeqOptimized .. tails()scala.collection.Iterator - // in other version, classes mixing scala.collection.TraversableViewLike$Transformed .. last()java.lang.Object - // in other version, classes mixing scala.collection.immutable.SortedSet .. equals(java.lang.Object)Boolean - // in other version, classes mixing scala.collection.immutable.SortedMap .. equals(java.lang.Object)Boolean - ProblemFilters.exclude[NewMixinForwarderProblem]("scala.math.Ordering#FloatOrdering.reverse"), - ProblemFilters.exclude[NewMixinForwarderProblem]("scala.math.Ordering#DoubleOrdering.reverse"), - ProblemFilters.exclude[NewMixinForwarderProblem]("scala.math.Ordering#IntOrdering.reverse"), - ProblemFilters.exclude[NewMixinForwarderProblem]("scala.collection.IndexedSeqOptimized.toList"), - ProblemFilters.exclude[NewMixinForwarderProblem]("scala.collection.LinearSeqOptimized.tails"), - ProblemFilters.exclude[NewMixinForwarderProblem]("scala.collection.TraversableViewLike#Transformed.last"), - ProblemFilters.exclude[NewMixinForwarderProblem]("scala.collection.immutable.SortedSet.equals"), - ProblemFilters.exclude[NewMixinForwarderProblem]("scala.collection.immutable.SortedMap.equals"), - - // method equals(java.lang.Object)Boolean in interface scala.math.Ordering#OptionOrdering does not have a correspondent in other version - // method hashCode()Int in interface scala.math.Ordering#OptionOrdering does not have a correspondent in other version - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.math.Ordering#OptionOrdering.equals"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.math.Ordering#OptionOrdering.hashCode"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.NoAbstractFile.seq"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.NoAbstractFile.view"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.NoAbstractFile.view"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Map#Map1.filterImpl"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Map#Map2.filterImpl"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Map#Map3.filterImpl"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Map#Map4.filterImpl"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Set#Set1.filterImpl"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Set#Set2.filterImpl"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Set#Set3.filterImpl"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.Set#Set4.filterImpl"), - ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.Set$SetNIterator"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.ReflectSetup.phaseWithId"), - ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.reflect.runtime.ReflectSetup.scala$reflect$runtime$ReflectSetup$_setter_$phaseWithId_="), - ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.reflect.runtime.ReflectSetup.phaseWithId"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap.getOrElse0"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashTrieMap.getOrElse0"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashMap1.getOrElse0"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap#HashMapCollision1.getOrElse0"), - ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.reflect.runtime.ReflectSetup.phaseWithId"), - - ProblemFilters.exclude[MissingClassProblem]("scala.math.Ordering$IterableOrdering"), - ProblemFilters.exclude[MissingClassProblem]("scala.math.Ordering$Tuple4Ordering"), - ProblemFilters.exclude[MissingClassProblem]("scala.math.Ordering$Tuple9Ordering"), - ProblemFilters.exclude[MissingClassProblem]("scala.math.Ordering$Reverse"), - ProblemFilters.exclude[MissingClassProblem]("scala.math.Ordering$Tuple2Ordering"), - ProblemFilters.exclude[MissingClassProblem]("scala.math.Ordering$Tuple3Ordering"), - ProblemFilters.exclude[MissingClassProblem]("scala.math.Ordering$Tuple7Ordering"), - ProblemFilters.exclude[MissingClassProblem]("scala.math.Ordering$Tuple6Ordering"), - ProblemFilters.exclude[MissingClassProblem]("scala.math.Ordering$Tuple8Ordering"), - ProblemFilters.exclude[MissingClassProblem]("scala.math.Ordering$Tuple5Ordering"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.macros.Attachments.removeElement"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.macros.Attachments.addElement"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.macros.Attachments.containsElement"), - // https://github.com/scala/scala/pull/7960: these only cause problems if someone is implausibly extending Attachments somehow - ProblemFilters.exclude[DirectAbstractMethodProblem]("scala.reflect.macros.Attachments.all"), - ProblemFilters.exclude[ReversedAbstractMethodProblem]("scala.reflect.macros.Attachments.all"), - ProblemFilters.exclude[DirectAbstractMethodProblem]("scala.reflect.macros.Attachments.isEmpty"), - ProblemFilters.exclude[ReversedAbstractMethodProblem]("scala.reflect.macros.Attachments.isEmpty"), - ProblemFilters.exclude[MissingClassProblem]("scala.reflect.macros.EmptyAttachments"), - ProblemFilters.exclude[MissingClassProblem]("scala.reflect.macros.SingleAttachment"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.Settings.async"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.api.Internals#InternalApi.markForAsyncTransform"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.mutable.HashMap.entriesIterator0"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.ZipArchive.RootEntry"), - - ProblemFilters.exclude[MissingClassProblem]("scala.reflect.ClassTag$cache$"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.GenSet.setEquals"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.GenMap.mapEquals"), - ) -} - scalaVersion in Global := versionProps("starr.version") lazy val instanceSettings = Seq[Setting[_]]( @@ -836,9 +368,7 @@ lazy val library = configureAsSubproject(project) ), // Remove the dependency on "forkjoin" from the POM because it is included in the JAR: pomDependencyExclusions += ((organization.value, "forkjoin")), - mimaPreviousArtifacts := mimaReferenceVersion.value.map(organization.value % name.value % _).toSet, - mimaCheckDirection := "both", - mimaFilterSettings, + MimaFilters.mimaSettings, ) .settings(filterDocSources("*.scala" -- (regexFileFilter(".*/runtime/.*\\$\\.scala") || regexFileFilter(".*/runtime/ScalaRunTime\\.scala") || @@ -848,7 +378,6 @@ lazy val reflect = configureAsSubproject(project) .settings(generatePropertiesFileSettings) .settings(Osgi.settings) .settings(AutomaticModuleName.settings("scala.reflect")) - .settings(mimaFilterSettings) .settings( name := "scala-reflect", description := "Scala Reflection Library", @@ -865,9 +394,7 @@ lazy val reflect = configureAsSubproject(project) "/project/description" -> Compiler for the Scala Programming Language, "/project/packaging" -> jar ), - mimaPreviousArtifacts := mimaReferenceVersion.value.map(organization.value % name.value % _).toSet, - mimaCheckDirection := "both", - mimaFilterSettings, + MimaFilters.mimaSettings, ) .dependsOn(library) @@ -1412,8 +939,7 @@ lazy val root: Project = (project in file(".")) (testOnly in IntegrationTest in testP).toTask(" -- --srcpath async").result map (_ -> "partest --srcpath async"), (Keys.test in Test in osgiTestFelix).result map (_ -> "osgiTestFelix/test"), (Keys.test in Test in osgiTestEclipse).result map (_ -> "osgiTestEclipse/test"), - (mimaReportBinaryIssues in library).result map (_ -> "library/mimaReportBinaryIssues"), - (mimaReportBinaryIssues in reflect).result map (_ -> "reflect/mimaReportBinaryIssues"), + (mimaReportBinaryIssues).result map (_ -> "mimaReportBinaryIssues"), (compile in Compile in bench).map(_ => ()).result map (_ -> "bench/compile"), Def.task(()).dependsOn( // Run these in parallel: doc in Compile in library, diff --git a/project/BuildSettings.scala b/project/BuildSettings.scala index 86d6658648a4..3cec68215323 100644 --- a/project/BuildSettings.scala +++ b/project/BuildSettings.scala @@ -7,6 +7,5 @@ object BuildSettings extends AutoPlugin { object autoImport { lazy val baseVersion = settingKey[String]("The base version number from which all others are derived") lazy val baseVersionSuffix = settingKey[String]("Identifies the kind of version to build") - lazy val mimaReferenceVersion = settingKey[Option[String]]("Scala version number to run MiMa against") } } diff --git a/project/MimaFilters.scala b/project/MimaFilters.scala new file mode 100644 index 000000000000..434377fef376 --- /dev/null +++ b/project/MimaFilters.scala @@ -0,0 +1,34 @@ +package scala.build + +import sbt._, Keys._ +import com.typesafe.tools.mima.core._ +import com.typesafe.tools.mima.plugin.MimaPlugin, MimaPlugin.autoImport._ + +object MimaFilters extends AutoPlugin { + override def trigger = allRequirements + + object autoImport { + val mimaReferenceVersion = settingKey[Option[String]]("Scala version number to run MiMa against") + } + import autoImport._ + + override val globalSettings = Seq( + mimaReferenceVersion := Some("2.12.13"), + ) + + val mimaFilters: Seq[ProblemFilter] = Seq[ProblemFilter]( + // KEEP: scala.reflect.internal isn't public API + ProblemFilters.exclude[Problem]("scala.reflect.internal.*"), + ) + + override val buildSettings = Seq( + mimaFailOnNoPrevious := false, // we opt everything out, knowing we only check library/reflect + ) + + val mimaSettings: Seq[Setting[_]] = Def.settings( + mimaPreviousArtifacts := mimaReferenceVersion.value.map(organization.value % name.value % _).toSet, + mimaCheckDirection := "both", + mimaBinaryIssueFilters ++= mimaFilters, +// mimaReportSignatureProblems := true, // TODO: enable + ) +} From 0678aeaa9a5b57bc63a8b839aac008e5e5f09dca Mon Sep 17 00:00:00 2001 From: mkeskells Date: Fri, 13 Nov 2020 17:27:28 +0000 Subject: [PATCH 36/59] reuse common code for filter/partition for RedBlackTree based Set/Map --- .../collection/immutable/RedBlackTree.scala | 71 ++++++++++--------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/src/library/scala/collection/immutable/RedBlackTree.scala b/src/library/scala/collection/immutable/RedBlackTree.scala index c7217a4bc0e5..ca4c706d171f 100644 --- a/src/library/scala/collection/immutable/RedBlackTree.scala +++ b/src/library/scala/collection/immutable/RedBlackTree.scala @@ -1021,41 +1021,48 @@ private[collection] object NewRedBlackTree { blacken(fk(t)) } - def partitionEntries[A, B](t: Tree[A, B], p: (A, B) => Boolean): (Tree[A, B], Tree[A, B]) = if(t eq null) (null, null) else { - var tmpk, tmpd = null: Tree[A, B] // shared vars to avoid returning tuples from fk - def fk(t: Tree[A, B]): Unit = { - val k = t.key - val v = t.value - val l = t.left - val r = t.right - var l2k, l2d, r2k, r2d = null: Tree[A, B] - if(l ne null) { - fk(l) - l2k = tmpk - l2d = tmpd - } - val keep = p(k, v) - if(r ne null) { - fk(r) - r2k = tmpk - r2d = tmpd + private[this] val null2 = (null, null) + + def partitionEntries[A, B](t: Tree[A, B], p: (A, B) => Boolean): (Tree[A, B], Tree[A, B]) = { + if (t eq null) null2 + else { + object partitioner { + var tmpk, tmpd = null: Tree[A, B] // shared vars to avoid returning tuples from fk + def fk(t: Tree[A, B]): Unit = { + val k = t.key + val v = t.value + val l = t.left + val r = t.right + var l2k, l2d, r2k, r2d = null: Tree[A, B] + if (l ne null) { + fk(l) + l2k = tmpk + l2d = tmpd + } + val keep = p(k, v) + if (r ne null) { + fk(r) + r2k = tmpk + r2d = tmpd + } + val jk = + if (!keep) join2(l2k, r2k) + else if ((l2k eq l) && (r2k eq r)) t + else join(l2k, k, v, r2k) + val jd = + if (keep) join2(l2d, r2d) + else if ((l2d eq l) && (r2d eq r)) t + else join(l2d, k, v, r2d) + tmpk = jk + tmpd = jd + } } - val jk = - if(!keep) join2(l2k, r2k) - else if((l2k eq l) && (r2k eq r)) t - else join(l2k, k, v, r2k) - val jd = - if(keep) join2(l2d, r2d) - else if((l2d eq l) && (r2d eq r)) t - else join(l2d, k, v, r2d) - tmpk = jk - tmpd = jd + + partitioner.fk(t) + (blacken(partitioner.tmpk), blacken(partitioner.tmpd)) } - fk(t) - (blacken(tmpk), blacken(tmpd)) } - // Based on Stefan Kahrs' Haskell version of Okasaki's Red&Black Trees // Constructing Red-Black Trees, Ralf Hinze: [[http://www.cs.ox.ac.uk/ralf.hinze/publications/WAAAPL99b.ps.gz]] // Red-Black Trees in a Functional Setting, Chris Okasaki: [[https://wiki.rice.edu/confluence/download/attachments/2761212/Okasaki-Red-Black.pdf]] */ @@ -1253,4 +1260,4 @@ private[collection] object NewRedBlackTree { val tr = _difference(r1, t2.right) join2(tl, tr) } -} \ No newline at end of file +} From 50c2bb71c73bd6f1c229070145175ab45a58e7bb Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 2 Dec 2020 10:11:19 +1000 Subject: [PATCH 37/59] Fix range position for vars with default initializer Pass the position of the RHS explicitly rather than using `rhs.pos` within TreeBuilder, as that doesn't carry the position of the `_` represented by the singleton tree `EmptyTree`. Change the quasiquote parser to also pick up the change. Also, tweaks in DefinitionConstructionProps that came out of fixing the quasiquote parser change. Co-authored-by: Dale Wijnand --- .../scala/reflect/quasiquotes/Parsers.scala | 6 +++--- .../scala/tools/nsc/ast/parser/Parsers.scala | 14 ++++++++------ .../scala/tools/nsc/ast/parser/TreeBuilder.scala | 3 ++- src/reflect/scala/reflect/internal/TreeGen.scala | 11 ++++++----- test/files/run/position-val-def.check | 4 ++-- test/junit/scala/tools/nsc/parser/ParserTest.scala | 2 +- .../quasiquotes/DefinitionConstructionProps.scala | 6 ++++-- .../reflect/quasiquotes/QuasiquoteProperties.scala | 8 +++++++- 8 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/compiler/scala/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/reflect/quasiquotes/Parsers.scala index 815618a8496d..785751eea814 100644 --- a/src/compiler/scala/reflect/quasiquotes/Parsers.scala +++ b/src/compiler/scala/reflect/quasiquotes/Parsers.scala @@ -98,9 +98,9 @@ trait Parsers { self: Quasiquotes => override def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = FunctionTypePlaceholder(argtpes, restpe) // make q"val (x: T) = rhs" be equivalent to q"val x: T = rhs" for sake of bug compatibility (scala/bug#8211) - override def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree) = pat match { - case TuplePlaceholder(inParensPat :: Nil) => super.makePatDef(mods, inParensPat, rhs) - case _ => super.makePatDef(mods, pat, rhs) + override def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree, rhsPos: Position) = pat match { + case TuplePlaceholder(inParensPat :: Nil) => super.makePatDef(mods, inParensPat, rhs, rhsPos) + case _ => super.makePatDef(mods, pat, rhs, rhsPos) } } import treeBuilder.{global => _, unit => _} diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 12faea9fe7c0..650dc1722ba6 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2620,25 +2620,27 @@ self => in.nextToken() val lhs = commaSeparated(stripParens(noSeq.pattern2())) val tp = typedOpt() - val rhs = + + val (rhs, rhsPos) = if (tp.isEmpty || in.token == EQUALS) { accept(EQUALS) if (!tp.isEmpty && newmods.isMutable && (lhs.toList forall (_.isInstanceOf[Ident])) && in.token == USCORE) { - in.nextToken() + val start = in.skipToken() newmods = newmods | Flags.DEFAULTINIT - EmptyTree + (EmptyTree, r2p(start, in.offset)) } else { - expr() + val t = expr() + (t, t.pos) } } else { newmods = newmods | Flags.DEFERRED - EmptyTree + (EmptyTree, NoPosition) } def mkDefs(p: Tree, tp: Tree, rhs: Tree): List[Tree] = { val trees = { val pat = if (tp.isEmpty) p else Typed(p, tp) setPos (p.pos union tp.pos) - makePatDef(newmods, pat, rhs) + makePatDef(newmods, pat, rhs, rhsPos) } if (newmods.isDeferred) { trees match { diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index ea7e9f1b0cc5..63249dd88a6e 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -143,5 +143,6 @@ abstract class TreeBuilder { } } - def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree) = gen.mkPatDef(mods, pat, rhs) + final def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree): List[ValDef] = makePatDef(mods, pat, rhs, rhs.pos) + def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree, rhsPos: Position) = gen.mkPatDef(mods, pat, rhs, rhsPos) } diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index def719082754..a2fda093ef08 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -753,9 +753,10 @@ abstract class TreeGen { propagateNoWarnAttachment(from, to).updateAttachment(PatVarDefAttachment) /** Create tree for pattern definition */ - def mkPatDef(mods: Modifiers, pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator): List[ValDef] = matchVarPattern(pat) match { + def mkPatDef(mods: Modifiers, pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator): List[ValDef] = mkPatDef(mods, pat, rhs, rhs.pos)(fresh) + def mkPatDef(mods: Modifiers, pat: Tree, rhs: Tree, rhsPos: Position)(implicit fresh: FreshNameCreator): List[ValDef] = matchVarPattern(pat) match { case Some((name, tpt)) => - List(atPos(pat.pos union rhs.pos) { + List(atPos(pat.pos union rhsPos) { propagateNoWarnAttachment(pat, ValDef(mods, name.toTermName, tpt, rhs)) }) @@ -782,13 +783,13 @@ abstract class TreeGen { case Typed(expr, tpt) if !expr.isInstanceOf[Ident] => val rhsTypedUnchecked = if (tpt.isEmpty) rhsUnchecked - else Typed(rhsUnchecked, tpt) setPos (rhs.pos union tpt.pos) + else Typed(rhsUnchecked, tpt) setPos (rhsPos union tpt.pos) (expr, rhsTypedUnchecked) case ok => (ok, rhsUnchecked) } val vars = getVariables(pat1) - val matchExpr = atPos((pat1.pos union rhs.pos).makeTransparent) { + val matchExpr = atPos((pat1.pos union rhsPos).makeTransparent) { Match( rhs1, List( @@ -799,7 +800,7 @@ abstract class TreeGen { } vars match { case List((vname, tpt, pos, original)) => - List(atPos(pat.pos union pos union rhs.pos) { + List(atPos(pat.pos union pos union rhsPos) { propagatePatVarDefAttachments(original, ValDef(mods, vname.toTermName, tpt, matchExpr)) }) case _ => diff --git a/test/files/run/position-val-def.check b/test/files/run/position-val-def.check index a92c77c68cff..b0ce48239ba9 100644 --- a/test/files/run/position-val-def.check +++ b/test/files/run/position-val-def.check @@ -6,14 +6,14 @@ var x = 0 val x, y = 0 [NoPosition]{ - [0:5]val x = [11]0; + [4]val x = [11]0; [7:12]val y = [11:12]0; [NoPosition]() } var x, y = 0 [NoPosition]{ - [0:5]var x = [11]0; + [4]var x = [11]0; [7:12]var y = [11:12]0; [NoPosition]() } diff --git a/test/junit/scala/tools/nsc/parser/ParserTest.scala b/test/junit/scala/tools/nsc/parser/ParserTest.scala index 37d590b141e4..d5a1a90e4780 100644 --- a/test/junit/scala/tools/nsc/parser/ParserTest.scala +++ b/test/junit/scala/tools/nsc/parser/ParserTest.scala @@ -43,6 +43,6 @@ class ParserTest extends BytecodeTesting{ def codeOf(pos: Position) = new String(pos.source.content.slice(pos.start, pos.end)) val List(x, y) = unit.body.collect { case vd : ValDef => vd }.takeRight(2) assertEquals("var y: Int = 42", codeOf(y.pos)) - assertEquals("var x: Int", codeOf(x.pos)) // TODO fix parser to include `= _` + assertEquals("var x: Int = _", codeOf(x.pos)) } } diff --git a/test/scalacheck/scala/reflect/quasiquotes/DefinitionConstructionProps.scala b/test/scalacheck/scala/reflect/quasiquotes/DefinitionConstructionProps.scala index 5056a9fc4536..f0f475d27589 100644 --- a/test/scalacheck/scala/reflect/quasiquotes/DefinitionConstructionProps.scala +++ b/test/scalacheck/scala/reflect/quasiquotes/DefinitionConstructionProps.scala @@ -12,8 +12,10 @@ object DefinitionConstructionProps with PatDefConstruction with DefConstruction with PackageConstruction - with ImportConstruction { + with ImportConstruction + with QuasiquoteSliceTypeTests +trait QuasiquoteSliceTypeTests { self: QuasiquoteProperties => val x: Tree = q"val x: Int" property("scala/bug#6842 a1") = test { assertEqAst(q"def f($x) = 0", "def f(x: Int) = 0") } property("scala/bug#6842 a2") = test { assertEqAst(q"class C($x)", "class C(val x: Int)") } @@ -229,7 +231,7 @@ trait ValDefConstruction { self: QuasiquoteProperties => q"var $name: $tpt = $rhs" ≈ ValDef(Modifiers(MUTABLE), name, tpt, rhs) } - // left tree is not a pattern due to Si-8211 + // left tree is not a pattern due to scala/bug#8211 property("scala/bug#8202") = test { assertEqAst(q"val (x: Int) = 1", "val x: Int = 1") } diff --git a/test/scalacheck/scala/reflect/quasiquotes/QuasiquoteProperties.scala b/test/scalacheck/scala/reflect/quasiquotes/QuasiquoteProperties.scala index acfd579cb70d..6b232bc37470 100644 --- a/test/scalacheck/scala/reflect/quasiquotes/QuasiquoteProperties.scala +++ b/test/scalacheck/scala/reflect/quasiquotes/QuasiquoteProperties.scala @@ -75,7 +75,13 @@ trait Helpers { assert(false, "exception wasn't thrown") } - def assertEqAst(tree: Tree, code: String) = assert(eqAst(tree, code)) + def assertEqAst(tree: Tree, code: String) = + assert(eqAst(tree, code), + s"""quasiquote tree != parse(code) tree + |quasiquote: $tree + |parse tree: ${parse(code)} + |code (str): $code""".stripMargin) + def eqAst(tree: Tree, code: String) = tree ≈ parse(code) val toolbox = currentMirror.mkToolBox() From 646e6b7adb246ded2435c8ef414989039169d7a1 Mon Sep 17 00:00:00 2001 From: mkeskells Date: Fri, 13 Nov 2020 17:06:55 +0000 Subject: [PATCH 38/59] less allocation on deserialisation of RedBlackTree (SortedMap) reuse deserialisation logic for map and set --- project/MimaFilters.scala | 3 ++ .../collection/immutable/RedBlackTree.scala | 26 ++++------------- .../scala/collection/immutable/TreeMap.scala | 28 +++++++++++++------ .../scala/collection/immutable/TreeSet.scala | 26 +++++++++++++---- 4 files changed, 49 insertions(+), 34 deletions(-) diff --git a/project/MimaFilters.scala b/project/MimaFilters.scala index 434377fef376..82413b377722 100644 --- a/project/MimaFilters.scala +++ b/project/MimaFilters.scala @@ -19,6 +19,9 @@ object MimaFilters extends AutoPlugin { val mimaFilters: Seq[ProblemFilter] = Seq[ProblemFilter]( // KEEP: scala.reflect.internal isn't public API ProblemFilters.exclude[Problem]("scala.reflect.internal.*"), + + // #9314 introduced private[this] object + ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.TreeSet$unitsIterator$"), ) override val buildSettings = Seq( diff --git a/src/library/scala/collection/immutable/RedBlackTree.scala b/src/library/scala/collection/immutable/RedBlackTree.scala index ca4c706d171f..15cbbab64cc4 100644 --- a/src/library/scala/collection/immutable/RedBlackTree.scala +++ b/src/library/scala/collection/immutable/RedBlackTree.scala @@ -955,34 +955,20 @@ private[collection] object NewRedBlackTree { override def nextResult(tree: Tree[A, B]) = tree.value } - /** Build a Tree suitable for a TreeSet from an ordered sequence of keys */ - def fromOrderedKeys[A](xs: Iterator[A], size: Int): Tree[A, Null] = { - val maxUsedDepth = 32 - Integer.numberOfLeadingZeros(size) // maximum depth of non-leaf nodes - def f(level: Int, size: Int): Tree[A, Null] = size match { - case 0 => null - case 1 => mkTree(level != maxUsedDepth || level == 1, xs.next(), null, null, null) - case n => - val leftSize = (size-1)/2 - val left = f(level+1, leftSize) - val x = xs.next() - val right = f(level+1, size-1-leftSize) - BlackTree(x, null, left, right) - } - f(1, size) - } - - /** Build a Tree suitable for a TreeMap from an ordered sequence of key/value pairs */ - def fromOrderedEntries[A, B](xs: Iterator[(A, B)], size: Int): Tree[A, B] = { + /** Build a Tree from an ordered sequence of key and values */ + def fromOrderedEntries[A, B](keys: Iterator[A], values: Iterator[B], size: Int): Tree[A, B] = { val maxUsedDepth = 32 - Integer.numberOfLeadingZeros(size) // maximum depth of non-leaf nodes def f(level: Int, size: Int): Tree[A, B] = size match { case 0 => null case 1 => - val (k, v) = xs.next() + val k = keys.next() + val v = values.next() mkTree(level != maxUsedDepth || level == 1, k, v, null, null) case n => val leftSize = (size-1)/2 val left = f(level+1, leftSize) - val (k, v) = xs.next() + val k = keys.next() + val v = values.next() val right = f(level+1, size-1-leftSize) BlackTree(k, v, left, right) } diff --git a/src/library/scala/collection/immutable/TreeMap.scala b/src/library/scala/collection/immutable/TreeMap.scala index 2d72396e04d1..49e2f99d546a 100644 --- a/src/library/scala/collection/immutable/TreeMap.scala +++ b/src/library/scala/collection/immutable/TreeMap.scala @@ -106,16 +106,26 @@ object TreeMap extends ImmutableSortedMapFactory[TreeMap] { private[this] def readObject(in: java.io.ObjectInputStream) = { val size = in.readInt() ordering = in.readObject().asInstanceOf[Ordering[A]] - implicit val ord = ordering - - val data = Array.newBuilder[(A, B)] - data.sizeHint(size) - for (i <- 0 until size) { - val key = in.readObject().asInstanceOf[A] - val value = in.readObject().asInstanceOf[B] - data += ((key, value)) + size match { + case 0 => //tree is null already + case 1 => + val key = in.readObject().asInstanceOf[A] + val value = in.readObject().asInstanceOf[B] + tree = RB.update(null, key, value, true)(ordering) + case _ => + val keys = new Array[Any](size) + val values = new Array[Any](size) + var i = 0 + while (i < size) { + keys(i) = in.readObject() + values(i) = in.readObject() + i += 1 + } + tree = RB.fromOrderedEntries( + keys.iterator.asInstanceOf[Iterator[A]], + values.iterator.asInstanceOf[Iterator[B]], + size) } - tree = RB.fromOrderedEntries(data.result.iterator, size) } @throws[IOException] private[this] def readResolve(): AnyRef = diff --git a/src/library/scala/collection/immutable/TreeSet.scala b/src/library/scala/collection/immutable/TreeSet.scala index 3fc7a39e564f..6ce7aed096e0 100644 --- a/src/library/scala/collection/immutable/TreeSet.scala +++ b/src/library/scala/collection/immutable/TreeSet.scala @@ -85,16 +85,32 @@ object TreeSet extends ImmutableSortedSetFactory[TreeSet] { private[this] def readObject(in: java.io.ObjectInputStream) = { val size = in.readInt() ordering = in.readObject().asInstanceOf[Ordering[A]] - val data = Iterable.newBuilder[A] - data.sizeHint(size) - for (i <- 0 until size) - data += in.readObject().asInstanceOf[A] - tree = RB.fromOrderedKeys(data.result.iterator, size) + size match { + case 0 => //tree is null already + case 1 => + val entry = in.readObject().asInstanceOf[A] + tree = RB.update(null, entry, (), false)(ordering) + case _ => + val entries = new Array[Any](size) + var i = 0 + while (i < size) { + entries(i) = in.readObject() + i += 1 + } + tree = RB.fromOrderedEntries( + entries.iterator.asInstanceOf[Iterator[A]], + unitsIterator, + size) + } } @throws[IOException] private[this] def readResolve(): AnyRef = new TreeSet(tree)(ordering) } + private[this] object unitsIterator extends AbstractIterator[Unit] { + override def hasNext: Boolean = true + override def next(): Unit = () + } } /** This class implements immutable sets using a tree. From 9a5fc06d527ca18d19e1c154c850afc302c9ba17 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Tue, 19 Jan 2021 23:34:24 -0800 Subject: [PATCH 39/59] Use Run reporter for wconf --- src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 6 +++--- test/files/pos/t12315.scala | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 test/files/pos/t12315.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 83e48cd85015..0b02e96a58ae 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -478,7 +478,7 @@ abstract class RefChecks extends Transform { checkOverrideDeprecated() if (settings.warnNullaryOverride) { if (other.paramss.isEmpty && !member.paramss.isEmpty && !member.isJavaDefined) { - reporter.warning(member.pos, "non-nullary method overrides nullary method") + refchecksWarning(member.pos, "non-nullary method overrides nullary method", WarningCategory.LintNullaryOverride) } } } @@ -1376,8 +1376,8 @@ abstract class RefChecks extends Transform { tree match { case DefDef(_, name, _, params :: _, _, _) => if (settings.warnByNameRightAssociative && !treeInfo.isLeftAssoc(name.decodedName) && params.exists(p => isByName(p.symbol))) - reporter.warning(tree.pos, - "by-name parameters will be evaluated eagerly when called as a right-associative infix operator. For more details, see scala/bug#1980.") + refchecksWarning(tree.pos, + "by-name parameters will be evaluated eagerly when called as a right-associative infix operator. For more details, see scala/bug#1980.", WarningCategory.Other) case _ => } } diff --git a/test/files/pos/t12315.scala b/test/files/pos/t12315.scala new file mode 100644 index 000000000000..c94dc9f2be78 --- /dev/null +++ b/test/files/pos/t12315.scala @@ -0,0 +1,8 @@ +// scalac: -Xfatal-warnings -Xlint +import annotation._ + +class Thingy[T] extends Iterator[T] with java.util.Iterator[T] { + @nowarn + def hasNext: Boolean = ??? + def next(): T = ??? +} From e309433964133125117c0e57b5e6fe401fbf6ffb Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 24 Jun 2020 16:20:39 +1000 Subject: [PATCH 40/59] async: await under synchronized is an error Co-authored-by: Lukas Rytz --- .../tools/nsc/transform/async/AnfTransform.scala | 2 ++ .../tools/nsc/transform/async/AsyncAnalysis.scala | 4 ++-- .../tools/nsc/transform/async/LiveVariables.scala | 2 +- .../tools/nsc/transform/async/TransformUtils.scala | 11 ++++++----- test/async/neg/ill-nested-await.check | 8 +++++++- test/async/neg/ill-nested-await.scala | 5 +++++ 6 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/compiler/scala/tools/nsc/transform/async/AnfTransform.scala b/src/compiler/scala/tools/nsc/transform/async/AnfTransform.scala index 9489de6464b3..3220388036c5 100644 --- a/src/compiler/scala/tools/nsc/transform/async/AnfTransform.scala +++ b/src/compiler/scala/tools/nsc/transform/async/AnfTransform.scala @@ -55,6 +55,8 @@ private[async] trait AnfTransform extends TransformUtils { tree case _ if !treeContainsAwait => tree + case Apply(TypeApply(sel@Select(_, _), _), arg :: Nil) if sel.symbol == definitions.Object_synchronized && containsAwait(arg) => + tree // pass through unchanged, this will be reported as an error later case Apply(sel@Select(fun, _), arg :: Nil) if isBooleanAnd(sel.symbol) && containsAwait(arg) => transform(treeCopy.If(tree, fun, arg, literalBool(false))) case Apply(sel@Select(fun, _), arg :: Nil) if isBooleanOr(sel.symbol) && containsAwait(arg) => diff --git a/src/compiler/scala/tools/nsc/transform/async/AsyncAnalysis.scala b/src/compiler/scala/tools/nsc/transform/async/AsyncAnalysis.scala index 2fae40c492e1..201e474628a4 100644 --- a/src/compiler/scala/tools/nsc/transform/async/AsyncAnalysis.scala +++ b/src/compiler/scala/tools/nsc/transform/async/AsyncAnalysis.scala @@ -45,8 +45,8 @@ trait AsyncAnalysis extends TransformUtils { reportUnsupportedAwait(defDef, "nested method") } - override def byNameArgument(arg: Tree): Unit = { - reportUnsupportedAwait(arg, "by-name argument") + override def synchronizedCall(arg: Tree): Unit = { + reportUnsupportedAwait(arg, "synchronized call") } override def function(function: Function): Unit = { diff --git a/src/compiler/scala/tools/nsc/transform/async/LiveVariables.scala b/src/compiler/scala/tools/nsc/transform/async/LiveVariables.scala index b4d8de489fc8..c5431adba1c3 100644 --- a/src/compiler/scala/tools/nsc/transform/async/LiveVariables.scala +++ b/src/compiler/scala/tools/nsc/transform/async/LiveVariables.scala @@ -90,7 +90,7 @@ trait LiveVariables extends ExprBuilder { override def nestedMethod(defdef: DefDef): Unit = capturingCheck(defdef) - override def byNameArgument(arg: Tree): Unit = capturingCheck(arg) + override def synchronizedCall(arg: Tree): Unit = capturingCheck(arg) override def function(function: Function): Unit = capturingCheck(function) override def function(expandedFunction: ClassDef): Unit = capturingCheck(expandedFunction) diff --git a/src/compiler/scala/tools/nsc/transform/async/TransformUtils.scala b/src/compiler/scala/tools/nsc/transform/async/TransformUtils.scala index 06b515538efc..ce395ade59fe 100644 --- a/src/compiler/scala/tools/nsc/transform/async/TransformUtils.scala +++ b/src/compiler/scala/tools/nsc/transform/async/TransformUtils.scala @@ -122,7 +122,7 @@ private[async] trait TransformUtils extends AsyncTransformStates { def nestedMethod(defdef: DefDef): Unit = { } - def byNameArgument(arg: Tree): Unit = { + def synchronizedCall(arg: Tree): Unit = { } def function(function: Function): Unit = { @@ -133,13 +133,14 @@ private[async] trait TransformUtils extends AsyncTransformStates { override def traverse(tree: Tree): Unit = { tree match { - case cd: ClassDef => + case cd: ClassDef => if (cd.symbol.isAnonymousClass) function(cd) else if (cd.symbol.isModuleClass) nestedModuleClass(cd) else nestedClass(cd) - case dd: DefDef => nestedMethod(dd) - case fun: Function => function(fun) - case _ => super.traverse(tree) + case dd: DefDef => nestedMethod(dd) + case fun: Function => function(fun) + case Apply(TypeApply(fun, _), arg :: Nil) if fun.symbol == definitions.Object_synchronized => synchronizedCall(arg) + case _ => super.traverse(tree) } } } diff --git a/test/async/neg/ill-nested-await.check b/test/async/neg/ill-nested-await.check index 683f821350e0..5be43d6d7f44 100644 --- a/test/async/neg/ill-nested-await.check +++ b/test/async/neg/ill-nested-await.check @@ -34,7 +34,13 @@ ill-nested-await.scala:70: error: await must not be used under a lazy val initia ill-nested-await.scala:76: error: await must not be used under a nested method. async { fooAsByNameLambda(await(f(""))) } ^ +ill-nested-await.scala:81: error: await must not be used under a synchronized call. + async { lock.synchronized { await(f(1)) + await(f(2)) } } + ^ +ill-nested-await.scala:81: error: await must not be used under a synchronized call. + async { lock.synchronized { await(f(1)) + await(f(2)) } } + ^ ill-nested-await.scala:10: error: `await` must be enclosed in an `async` block await[Any](f(null)) ^ -13 errors found +15 errors found diff --git a/test/async/neg/ill-nested-await.scala b/test/async/neg/ill-nested-await.scala index 956ee0aba9bd..00c50b9d4be7 100644 --- a/test/async/neg/ill-nested-await.scala +++ b/test/async/neg/ill-nested-await.scala @@ -75,4 +75,9 @@ class NakedAwait { def fooAsByNameLambda = foo("") _ // : (_ => String) = String async { fooAsByNameLambda(await(f(""))) } } + + def underSynchronized(): Unit = { + val lock = new Object + async { lock.synchronized { await(f(1)) + await(f(2)) } } + } } From cf0b02796b93334207c71066f9fc8056d209b2d0 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 25 Jan 2021 14:54:27 +1000 Subject: [PATCH 41/59] Fix race condition in PipelineMainTest This stack, for example, touches the shared reporter from a background thread, so we need to add synchronization. ``` scala.reflect.internal.Reporter.echo(Reporting.scala:109) scala.tools.nsc.PipelineMainClass.scala$tools$nsc$PipelineMainClass$$reporterEcho(PipelineMain.scala:63) scala.tools.nsc.PipelineMainClass$Task.log(PipelineMain.scala:586) scala.tools.nsc.PipelineMainClass$Task.javaCompile(PipelineMain.scala:548) scala.tools.nsc.PipelineMainClass.$anonfun$process$40(PipelineMain.scala:214) scala.tools.nsc.PipelineMainClass.$anonfun$process$40$adapted(PipelineMain.scala:212) scala.util.Success.$anonfun$map$1(Try.scala:255) scala.util.Try$.apply(Try.scala:213) scala.util.Success.map(Try.scala:255) scala.concurrent.Future.$anonfun$map$1(Future.scala:292) scala.concurrent.impl.Promise.liftedTree1$1(Promise.scala:33) scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:33) scala.concurrent.impl.CallbackRunnable.run(Promise.scala:64) java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402) ``` --- .../scala/tools/nsc/PipelineMain.scala | 49 +++++++++++-------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/src/compiler/scala/tools/nsc/PipelineMain.scala b/src/compiler/scala/tools/nsc/PipelineMain.scala index fb4d0c000cc5..3fe5d7853cb8 100644 --- a/src/compiler/scala/tools/nsc/PipelineMain.scala +++ b/src/compiler/scala/tools/nsc/PipelineMain.scala @@ -52,10 +52,19 @@ class PipelineMainClass(argFiles: Seq[Path], pipelineSettings: PipelineMain.Pipe /** Forward errors to the (current) reporter. */ protected def scalacError(msg: String): Unit = { - reporter.error(FakePos("scalac"), msg + "\n scalac -help gives more information") + reporterError(FakePos("scalac"), msg + "\n scalac -help gives more information") } private var reporter: Reporter = _ + private def reporterEcho(pos: Position, msg: String): Unit = synchronized { + reporter.echo(pos, msg) + } + private def reporterEcho(msg: String): Unit = synchronized { + reporter.echo(NoPosition, msg) + } + private def reporterError(pos: Position, msg: String): Unit = synchronized { + reporter.echo(msg) + } private object handler extends UncaughtExceptionHandler { override def uncaughtException(t: Thread, e: Throwable): Unit = { @@ -89,14 +98,14 @@ class PipelineMainClass(argFiles: Seq[Path], pipelineSettings: PipelineMain.Pipe builder.append("}\n") val path = logDir.resolve("projects.dot") Files.write(path, builder.toString.getBytes(java.nio.charset.StandardCharsets.UTF_8)) - reporter.echo("Wrote project dependency graph to: " + path.toAbsolutePath) + reporterEcho("Wrote project dependency graph to: " + path.toAbsolutePath) } private case class Dependency(t: Task, isMacro: Boolean, isPlugin: Boolean) def process(): Boolean = { reporter = createReporter(new Settings(scalacError)) - reporter.echo(s"parallelism = $parallelism, strategy = $strategy") + reporterEcho(s"parallelism = $parallelism, strategy = $strategy") def commandFor(argFileArg: Path): Task = { val ss = new Settings(scalacError) @@ -134,13 +143,13 @@ class PipelineMainClass(argFiles: Seq[Path], pipelineSettings: PipelineMain.Pipe } else { PickleExtractor.process(entry, extracted) Files.setLastModifiedTime(extracted, sourceTimeStamp) - reporter.echo(s"Exported pickles from $entry to $extracted") + reporterEcho(s"Exported pickles from $entry to $extracted") Files.setLastModifiedTime(extracted, sourceTimeStamp) } strippedAndExportedClassPath(entry) = extracted } exportTimer.stop() - reporter.echo(f"Exported external classpath in ${exportTimer.durationMs}%.0f ms") + reporterEcho(f"Exported external classpath in ${exportTimer.durationMs}%.0f ms") } } @@ -165,14 +174,14 @@ class PipelineMainClass(argFiles: Seq[Path], pipelineSettings: PipelineMain.Pipe Await.result(awaitAllFutures, Duration(60, "s")) timer.stop() val numCompleted = allFutures.count(_.isCompleted) - reporter.echo(s"PROGRESS: $numCompleted / $numAllFutures") + reporterEcho(s"PROGRESS: $numCompleted / $numAllFutures") return } catch { case _: TimeoutException => val numCompleted = allFutures.count(_.isCompleted) if (numCompleted == lastNumCompleted) { - reporter.echo(s"STALLED: $numCompleted / $numAllFutures") - reporter.echo("Outline/Scala/Javac") + reporterEcho(s"STALLED: $numCompleted / $numAllFutures") + reporterEcho("Outline/Scala/Javac") projects.map { p => def toX(b: Future[_]): String = b.value match { case None => "-"; case Some(Success(_)) => "x"; case Some(Failure(_)) => "!" } @@ -180,7 +189,7 @@ class PipelineMainClass(argFiles: Seq[Path], pipelineSettings: PipelineMain.Pipe reporter.echo(s + " " + p.label) } } else { - reporter.echo(s"PROGRESS: $numCompleted / $numAllFutures") + reporterEcho(s"PROGRESS: $numCompleted / $numAllFutures") lastNumCompleted = numCompleted } } @@ -222,9 +231,9 @@ class PipelineMainClass(argFiles: Seq[Path], pipelineSettings: PipelineMain.Pipe if (parallelism == 1) { val criticalPath = projects.maxBy(_.regularCriticalPathMs) - reporter.echo(f"Critical path: ${criticalPath.regularCriticalPathMs}%.0f ms. Wall Clock: ${timer.durationMs}%.0f ms") + reporterEcho(f"Critical path: ${criticalPath.regularCriticalPathMs}%.0f ms. Wall Clock: ${timer.durationMs}%.0f ms") } else - reporter.echo(f" Wall Clock: ${timer.durationMs}%.0f ms") + reporterEcho(f" Wall Clock: ${timer.durationMs}%.0f ms") case Pipeline => projects.foreach { p => val depsReady = Future.traverse(dependsOn.getOrElse(p, Nil))(task => p.dependencyReadyFuture(task)) @@ -261,9 +270,9 @@ class PipelineMainClass(argFiles: Seq[Path], pipelineSettings: PipelineMain.Pipe if (parallelism == 1) { val criticalPath = projects.maxBy(_.regularCriticalPathMs) - reporter.echo(f"Critical path: ${criticalPath.regularCriticalPathMs}%.0f ms. Wall Clock: ${timer.durationMs}%.0f ms") + reporterEcho(f"Critical path: ${criticalPath.regularCriticalPathMs}%.0f ms. Wall Clock: ${timer.durationMs}%.0f ms") } else - reporter.echo(f" Wall Clock: ${timer.durationMs}%.0f ms") + reporterEcho(f" Wall Clock: ${timer.durationMs}%.0f ms") case Traditional => projects.foreach { p => val f1 = Future.traverse(dependsOn.getOrElse(p, Nil))(_.t.javaDone.future) @@ -286,9 +295,9 @@ class PipelineMainClass(argFiles: Seq[Path], pipelineSettings: PipelineMain.Pipe } if (parallelism == 1) { val maxFullCriticalPath: Double = projects.map(_.fullCriticalPathMs).max - reporter.echo(f"Critical path: $maxFullCriticalPath%.0f ms. Wall Clock: ${timer.durationMs}%.0f ms") + reporterEcho(f"Critical path: $maxFullCriticalPath%.0f ms. Wall Clock: ${timer.durationMs}%.0f ms") } else { - reporter.echo(f"Wall Clock: ${timer.durationMs}%.0f ms") + reporterEcho(f"Wall Clock: ${timer.durationMs}%.0f ms") } } @@ -337,7 +346,7 @@ class PipelineMainClass(argFiles: Seq[Path], pipelineSettings: PipelineMain.Pipe trace.append("]}") val traceFile = logDir.resolve(s"build-${label}.trace") Files.write(traceFile, trace.toString.getBytes()) - reporter.echo("Chrome trace written to " + traceFile.toAbsolutePath) + reporterEcho("Chrome trace written to " + traceFile.toAbsolutePath) } case class Group(files: List[String]) { @@ -420,7 +429,7 @@ class PipelineMainClass(argFiles: Seq[Path], pipelineSettings: PipelineMain.Pipe if (reporter.hasErrors) reporter.flush() else if (command.shouldStopWithInfo) - reporter.echo(command.getInfoMessage(result)) + reporterEcho(command.getInfoMessage(result)) result.reporter = createReporter(result.settings) result } catch { @@ -553,9 +562,9 @@ class PipelineMainClass(argFiles: Seq[Path], pipelineSettings: PipelineMain.Pipe Position.range(sourceFile, diagnostic.getStartPosition.toInt, diagnostic.getPosition.toInt, diagnostic.getEndPosition.toInt) } diagnostic.getKind match { - case Kind.ERROR => reporter.error(position, msg) + case Kind.ERROR => reporterError(position, msg) case Kind.WARNING | Kind.MANDATORY_WARNING => Task.this.compiler.runReporting.warning(position, msg, WarningCategory.JavaSource, site = "") - case Kind.NOTE | Kind.OTHER => reporter.echo(position, msg) + case Kind.NOTE | Kind.OTHER => reporterEcho(position, msg) } } } @@ -574,7 +583,7 @@ class PipelineMainClass(argFiles: Seq[Path], pipelineSettings: PipelineMain.Pipe javaDone.complete(Success(())) } } - def log(msg: String): Unit = reporter.echo(this.label + ": " + msg) + def log(msg: String): Unit = reporterEcho(this.label + ": " + msg) } final class Timer() { From 3393616658fbd9946a9cc0520be42907b756964f Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Thu, 28 Jan 2021 16:16:11 +1000 Subject: [PATCH 42/59] Fix regression in specialization of genericWrapArray(Array(..)) The extension to the optimization in Cleanup of Array.apply assumed that the argument array was non-primitive. This broke compilation of spire (code minimized to test/files/run/sd760a.scala) I also found a path to the same bug without specialization, by using a generic type parmater bounded by a primitive. This is in test/files/run/sd760b.scala The fix here is straight forward -- disable this optimization when the argument array is primitive. --- src/compiler/scala/tools/nsc/transform/CleanUp.scala | 2 +- .../run/array-cleanup-optimation-specialized.scala | 12 ++++++++++++ test/files/run/sd760a.scala | 12 ++++++++++++ test/files/run/sd760b.scala | 11 +++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 test/files/run/array-cleanup-optimation-specialized.scala create mode 100644 test/files/run/sd760a.scala create mode 100644 test/files/run/sd760b.scala diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 7689cc652923..017446d4708a 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -488,7 +488,7 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL { // See scala/bug#6611; we must *only* do this for literal vararg arrays. case Apply(appMeth, Apply(wrapRefArrayMeth, (arg @ StripCast(ArrayValue(elemtpt, elems))) :: Nil) :: classTagEvidence :: Nil) if (wrapRefArrayMeth.symbol == currentRun.runDefinitions.Predef_genericWrapRefArray || wrapRefArrayMeth.symbol == currentRun.runDefinitions.Predef_wrapRefArray) && appMeth.symbol == ArrayModule_genericApply && - !elemtpt.tpe.typeSymbol.isBottomClass => + !elemtpt.tpe.typeSymbol.isBottomClass && !elemtpt.tpe.typeSymbol.isPrimitiveValueClass /* can happen via specialization.*/ => classTagEvidence.attachments.get[analyzer.MacroExpansionAttachment] match { case Some(att) if att.expandee.symbol.name == nme.materializeClassTag && tree.isInstanceOf[ApplyToImplicitArgs] => super.transform(arg) diff --git a/test/files/run/array-cleanup-optimation-specialized.scala b/test/files/run/array-cleanup-optimation-specialized.scala new file mode 100644 index 000000000000..5db397752df3 --- /dev/null +++ b/test/files/run/array-cleanup-optimation-specialized.scala @@ -0,0 +1,12 @@ +import scala.reflect.ClassTag + +object Test { + def main(args: Array[String]): Unit = { + assert(apply[String]("") == classOf[Array[String]]) + assert(apply[Double](1d) == classOf[Array[Double]]) + } + + def apply[@specialized(Double) C: ClassTag](c: C): Class[_] = { + Array(c).getClass + } +} diff --git a/test/files/run/sd760a.scala b/test/files/run/sd760a.scala new file mode 100644 index 000000000000..5db397752df3 --- /dev/null +++ b/test/files/run/sd760a.scala @@ -0,0 +1,12 @@ +import scala.reflect.ClassTag + +object Test { + def main(args: Array[String]): Unit = { + assert(apply[String]("") == classOf[Array[String]]) + assert(apply[Double](1d) == classOf[Array[Double]]) + } + + def apply[@specialized(Double) C: ClassTag](c: C): Class[_] = { + Array(c).getClass + } +} diff --git a/test/files/run/sd760b.scala b/test/files/run/sd760b.scala new file mode 100644 index 000000000000..fae0e9cf8a6d --- /dev/null +++ b/test/files/run/sd760b.scala @@ -0,0 +1,11 @@ +import scala.reflect.ClassTag + +object Test { + def main(args: Array[String]): Unit = { + assert(apply[Double](1d) == classOf[Array[Double]]) + } + + def apply[D <: Double: ClassTag](d: D): Class[_] = { + Array.apply[D](d).getClass + } +} From c9692130aef49deec6db637bb5a740345d69c427 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Thu, 28 Jan 2021 16:50:05 +1000 Subject: [PATCH 43/59] Faster `Array[T](t)` for @specialialized T. Avoid boxing the elements in favour of bulk clone of the varargs array into the result array, when the runtime type of the class-tag-generated result array is the same as the varargs array. --- src/library/scala/Array.scala | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/library/scala/Array.scala b/src/library/scala/Array.scala index b41a0d9c1349..b2390a41804e 100644 --- a/src/library/scala/Array.scala +++ b/src/library/scala/Array.scala @@ -13,10 +13,11 @@ package scala import scala.collection.generic._ -import scala.collection.{ mutable, immutable } -import mutable.{ ArrayBuilder, ArraySeq } -import scala.reflect.ClassTag -import scala.runtime.ScalaRunTime.{ array_apply, array_update } +import scala.collection.{immutable, mutable} +import mutable.{ArrayBuilder, ArraySeq} +import scala.reflect.{ClassTag, classTag} +import scala.runtime.ScalaRunTime +import scala.runtime.ScalaRunTime.{array_apply, array_update} /** Contains a fallback builder for arrays when the element type * does not have a class tag. In that case a generic array is built. @@ -194,10 +195,20 @@ object Array extends FallbackArrayBuilding { // 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 - for (x <- xs.iterator) { array(i) = x; i += 1 } - array + val len = xs.length + xs match { + case wa: mutable.WrappedArray[_] if wa.elemTag == classTag[T] => + // We get here in test/files/run/sd760a.scala, `Array[T](t)` for + // a specialized type parameter `T`. While we still pay for two + // copies of the array it is better than before when we also boxed + // each element when populating the result. + ScalaRunTime.array_clone(wa.array).asInstanceOf[Array[T]] + case _ => + val array = new Array[T](len) + var i = 0 + for (x <- xs.iterator) { array(i) = x; i += 1 } + array + } } /** Creates an array of `Boolean` objects */ From 1e1a0fd6a995d7d382110534fd888996d20686cb Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 1 Feb 2021 13:18:14 +1000 Subject: [PATCH 44/59] Use a stock URLClassLoader in the scala runner for parallel capability Background: Java 7 introduced a way for classloaders to use fine grained locking to avoid some deadlocks possibilities. The same fine grained locks could conceivably improve performance of multi-threaded code that has non-trivial logic in static initializers. This tech note describes the change: https://docs.oracle.com/javase/7/docs/technotes/guides/lang/cl-mt.html For backwards compatibility, custom subclasses of ClassLoader need to opt into this scheme by calling `ClassLoader.registerParalleCapable`. This needs to be done from the class itself during it static initializer (well, at least before the first super constructor call to `ClassLoader(...)`) The Scala runners use a custom classloader subclass. This has never opted into the parallel classloading. It is extremely difficult to make ScalaClassLoader.URLClassLoader correctly register itself to ClassLoader.parallelCapable due to the absence of Scala language support for declaring Java static initializer blocks. Implementing tbis class in Java is possible but in turn requires our SBT build to no longer use the "JavaThenScala" compilation mode. However, closer inspection reveals that this custom classloader type is only used for convenience methods. This PR refactors these into extension methods and uses a plain `java.net.URLClassLoader` directly. The changes is observable with: ```scala object Test extends App { val cl = Test.getClass.getClassLoader val fld = classOf[java.lang.ClassLoader].getDeclaredField("parallelLockMap") fld.setAccessible(true) val isParallel = fld.get(cl) != null println((cl, "isParallel = " + isParallel)) } ``` ``` % (export V=2.12.12; scalac --scala-version $V -d /tmp sandbox/test.scala && scala --scala-version $V -cp /tmp Test ) (scala.reflect.internal.util.ScalaClassLoader$URLClassLoader@58c1c010,isParallel = false) % qscalac -d /tmp sandbox/test.scala && qscala -cp /tmp Test (java.net.URLClassLoader@cac736f,isParallel = true) ``` --- .../scala/tools/nsc/ObjectRunner.scala | 3 +- .../internal/util/ScalaClassLoader.scala | 58 +++++++++++++++---- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/compiler/scala/tools/nsc/ObjectRunner.scala b/src/compiler/scala/tools/nsc/ObjectRunner.scala index 4f351908f5f6..3e1e4bb92291 100644 --- a/src/compiler/scala/tools/nsc/ObjectRunner.scala +++ b/src/compiler/scala/tools/nsc/ObjectRunner.scala @@ -25,7 +25,8 @@ trait CommonRunner { * @throws InvocationTargetException */ def run(urls: Seq[URL], objectName: String, arguments: Seq[String]) { - (ScalaClassLoader fromURLs urls).run(objectName, arguments) + import scala.reflect.internal.util.RichClassLoader._ + ScalaClassLoader.fromURLsParallelCapable(urls).run(objectName, arguments) } /** Catches exceptions enumerated by run (in the case of InvocationTargetException, diff --git a/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala b/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala index 9913f158f716..53f60800d550 100644 --- a/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala +++ b/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala @@ -29,17 +29,12 @@ trait HasClassPath { def classPathURLs: Seq[URL] } -/** A wrapper around java.lang.ClassLoader to lower the annoyance - * of java reflection. - */ -trait ScalaClassLoader extends JClassLoader { +final class RichClassLoader(private val self: JClassLoader) extends AnyVal { /** Executing an action with this classloader as context classloader */ def asContext[T](action: => T): T = { - import ScalaClassLoader.setContext - val saved = Thread.currentThread.getContextClassLoader - try { setContext(this) ; action } - finally setContext(saved) + try { ScalaClassLoader.setContext(self) ; action } + finally ScalaClassLoader.setContext(saved) } /** Load and link a class with this classloader */ @@ -49,7 +44,7 @@ trait ScalaClassLoader extends JClassLoader { private def tryClass[T <: AnyRef](path: String, initialize: Boolean): Option[Class[T]] = catching(classOf[ClassNotFoundException], classOf[SecurityException]) opt - Class.forName(path, initialize, this).asInstanceOf[Class[T]] + Class.forName(path, initialize, self).asInstanceOf[Class[T]] /** Create an instance of a class with this classloader */ def create(path: String): AnyRef = @@ -60,7 +55,7 @@ trait ScalaClassLoader extends JClassLoader { def fail(msg: String) = error(msg, new IllegalArgumentException(msg)) def error(msg: String, e: Throwable) = { errorFn(msg) ; throw e } try { - val clazz = Class.forName(path, /*initialize =*/ true, /*loader =*/ this) + val clazz = Class.forName(path, /*initialize =*/ true, /*loader =*/ self) if (classTag[T].runtimeClass isAssignableFrom clazz) { val ctor = { val maybes = clazz.getConstructors filter (c => c.getParameterCount == args.size && @@ -71,7 +66,7 @@ trait ScalaClassLoader extends JClassLoader { (ctor.newInstance(args: _*)).asInstanceOf[T] } else { errorFn(s"""Loader for ${classTag[T]}: [${show(classTag[T].runtimeClass.getClassLoader)}] - |Loader for ${clazz.getName}: [${show(clazz.getClassLoader)}]""".stripMargin) + |Loader for ${clazz.getName}: [${show(clazz.getClassLoader)}]""".stripMargin) fail(s"Not a ${classTag[T]}: ${path}") } } catch { @@ -89,7 +84,7 @@ trait ScalaClassLoader extends JClassLoader { } /** An InputStream representing the given class name, or null if not found. */ - def classAsStream(className: String) = getResourceAsStream { + def classAsStream(className: String) = self.getResourceAsStream { if (className endsWith ".class") className else s"${className.replace('.', '/')}.class" // classNameToPath } @@ -108,6 +103,41 @@ trait ScalaClassLoader extends JClassLoader { } } +object RichClassLoader { + implicit def wrapClassLoader(loader: ClassLoader): RichClassLoader = new RichClassLoader(loader) +} + +/** A wrapper around java.lang.ClassLoader to lower the annoyance + * of java reflection. + */ +trait ScalaClassLoader extends JClassLoader { + private def wrap = new RichClassLoader(this) + /** Executing an action with this classloader as context classloader */ + def asContext[T](action: => T): T = wrap.asContext(action) + + /** Load and link a class with this classloader */ + def tryToLoadClass[T <: AnyRef](path: String): Option[Class[T]] = wrap.tryToLoadClass[T](path) + /** Load, link and initialize a class with this classloader */ + def tryToInitializeClass[T <: AnyRef](path: String): Option[Class[T]] = wrap.tryToInitializeClass(path) + + /** Create an instance of a class with this classloader */ + def create(path: String): AnyRef = wrap.create(path) + + /** Create an instance with ctor args, or invoke errorFn before throwing. */ + def create[T <: AnyRef : ClassTag](path: String, errorFn: String => Unit)(args: AnyRef*): T = + wrap.create[T](path, errorFn)(args: _*) + + /** The actual bytes for a class file, or an empty array if it can't be found. */ + def classBytes(className: String): Array[Byte] = wrap.classBytes(className) + + /** An InputStream representing the given class name, or null if not found. */ + def classAsStream(className: String) = wrap.classAsStream(className) + + /** Run the main method of a class to be loaded by this classloader */ + def run(objectName: String, arguments: Seq[String]): Unit = wrap.run(objectName, arguments) +} + + /** Methods for obtaining various classloaders. * appLoader: the application classloader. (Also called the java system classloader.) * extLoader: the extension classloader. @@ -152,6 +182,10 @@ object ScalaClassLoader { new URLClassLoader(urls, if (parent == null) bootClassLoader else parent) } + def fromURLsParallelCapable(urls: Seq[URL], parent: ClassLoader = null): JURLClassLoader = { + new JURLClassLoader(urls.toArray, if (parent == null) bootClassLoader else parent) + } + /** True if supplied class exists in supplied path */ def classExists(urls: Seq[URL], name: String): Boolean = (fromURLs(urls) tryToLoadClass name).isDefined From 2a60c3121ada1ec39b507aa6a6c5e36f25ea9358 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Mon, 1 Feb 2021 19:56:46 -0800 Subject: [PATCH 45/59] upgrade to asm 9.0, for JDK 16 support fixes scala/bug#12328 --- src/intellij/scala.ipr.SAMPLE | 26 +++++++++++++------------- versions.properties | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/intellij/scala.ipr.SAMPLE b/src/intellij/scala.ipr.SAMPLE index 755999c6e54f..93154b92f738 100644 --- a/src/intellij/scala.ipr.SAMPLE +++ b/src/intellij/scala.ipr.SAMPLE @@ -231,7 +231,7 @@ - + @@ -250,7 +250,7 @@ - + @@ -262,7 +262,7 @@ - + @@ -280,7 +280,7 @@ - + @@ -290,7 +290,7 @@ - + @@ -317,7 +317,7 @@ - + @@ -331,7 +331,7 @@ - + @@ -340,7 +340,7 @@ - + @@ -350,7 +350,7 @@ - + @@ -511,7 +511,7 @@ - + @@ -524,7 +524,7 @@ - + @@ -535,7 +535,7 @@ - + @@ -560,7 +560,7 @@ - + diff --git a/versions.properties b/versions.properties index 46c0be31da9f..d4151f2e6ee6 100644 --- a/versions.properties +++ b/versions.properties @@ -21,5 +21,5 @@ scala.binary.version=2.12 scala-xml.version.number=1.0.6 scala-parser-combinators.version.number=1.0.7 scala-swing.version.number=2.0.3 -scala-asm.version=7.3.1-scala-1 +scala-asm.version=9.0.0-scala-1 jline.version=2.14.6 From 845cda33e16abbddd7af54030bc1ae73d00c2e34 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 2 Feb 2021 13:51:07 +1000 Subject: [PATCH 46/59] Fix cylic error in runtime reflection (protobuf) The use of f-bounded generic in protobuf that refer to static inner classes started causing cyclic errors in runtime reflecion since scala/scala#12038. We can avoid the problem by limiting the use of the `ParameterizedType#getOwnerType` to cases when the selected inner class is non-static. --- .../scala/reflect/runtime/JavaMirrors.scala | 6 ++++-- test/files/run/t12038a.check | 3 +++ test/files/run/t12038a/J_1.java | 11 ++++++++++ test/files/run/t12038a/Test.scala | 7 +++++++ test/files/run/t12038b.check | 1 + test/files/run/t12038b/J_1.java | 21 +++++++++++++++++++ test/files/run/t12038b/Test.scala | 7 +++++++ 7 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 test/files/run/t12038a.check create mode 100644 test/files/run/t12038a/J_1.java create mode 100644 test/files/run/t12038a/Test.scala create mode 100644 test/files/run/t12038b.check create mode 100644 test/files/run/t12038b/J_1.java create mode 100644 test/files/run/t12038b/Test.scala diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 8718bdc421c5..e3045e15e0e8 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -1133,8 +1133,10 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive } case japplied: ParameterizedType => // http://stackoverflow.com/questions/5767122/parameterizedtype-getrawtype-returns-j-l-r-type-not-class - val sym = classToScala(japplied.getRawType.asInstanceOf[jClass[_]]) - val pre = if (japplied.getOwnerType ne null) typeToScala(japplied.getOwnerType) else sym.owner.thisType + val jcls = japplied.getRawType.asInstanceOf[jClass[_]] + val sym = classToScala(jcls) + val isStatic = java.lang.reflect.Modifier.isStatic(jcls.getModifiers) + val pre = if (!isStatic && (japplied.getOwnerType ne null)) typeToScala(japplied.getOwnerType) else sym.owner.thisType val args0 = japplied.getActualTypeArguments val (args, bounds) = targsToScala(pre.typeSymbol, args0.toList) newExistentialType(bounds, typeRef(pre, sym, args)) diff --git a/test/files/run/t12038a.check b/test/files/run/t12038a.check new file mode 100644 index 000000000000..13d7a9d9b34d --- /dev/null +++ b/test/files/run/t12038a.check @@ -0,0 +1,3 @@ +[BuilderType <: p1.J_1.AbstractMessageLite.Builder[BuilderType]]Object { + def (): p1.J_1.AbstractMessageLite[BuilderType] +} diff --git a/test/files/run/t12038a/J_1.java b/test/files/run/t12038a/J_1.java new file mode 100644 index 000000000000..37f545e5a6fe --- /dev/null +++ b/test/files/run/t12038a/J_1.java @@ -0,0 +1,11 @@ +package p1; + +public class J_1 { + public abstract static class AbstractMessageLite< + BuilderType extends AbstractMessageLite.Builder> { + + public abstract static class Builder>{ + + } + } +} diff --git a/test/files/run/t12038a/Test.scala b/test/files/run/t12038a/Test.scala new file mode 100644 index 000000000000..5a62349415bc --- /dev/null +++ b/test/files/run/t12038a/Test.scala @@ -0,0 +1,7 @@ +object Test { + def main(args: Array[String]): Unit = { + import reflect.runtime.universe._ + val m = scala.reflect.runtime.currentMirror + println(m.staticClass("p1.J_1.AbstractMessageLite").info.toString) // was cyclic error + } +} diff --git a/test/files/run/t12038b.check b/test/files/run/t12038b.check new file mode 100644 index 000000000000..f53073d631c9 --- /dev/null +++ b/test/files/run/t12038b.check @@ -0,0 +1 @@ +(x$1: p1.J_1.O[Object]#$I[String])Unit diff --git a/test/files/run/t12038b/J_1.java b/test/files/run/t12038b/J_1.java new file mode 100644 index 000000000000..32c240ba98bd --- /dev/null +++ b/test/files/run/t12038b/J_1.java @@ -0,0 +1,21 @@ +package p1; + +public class J_1 { + public static abstract class O { + // non static, runtime reflection should use the generic owner type + // in the type signature below. + // + // also doing for static inner classes runs into cyclic errors (see t12038a.scala) + // in the current implementation of runtime reflection. + // + // This is fine as Java rejects the type selections in `notValidJava` below with: + // + // "cannot select a static class from a parameterized type" + public abstract class I {} + + public abstract static class J {} + } + static void test(O.I oi) {} + + // static void notValidJava(O.J oj) {} +} diff --git a/test/files/run/t12038b/Test.scala b/test/files/run/t12038b/Test.scala new file mode 100644 index 000000000000..a2b2220ad4cb --- /dev/null +++ b/test/files/run/t12038b/Test.scala @@ -0,0 +1,7 @@ +object Test { + def main(args: Array[String]): Unit = { + import reflect.runtime.universe._ + val m = scala.reflect.runtime.currentMirror + println(m.staticClass("p1.J_1").companion.info.decl(TermName("test")).asMethod.info.toString) + } +} From d032ef8963678d2cd36b6794f1d3f0f5dfb2d964 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Mon, 8 Feb 2021 19:50:19 -0800 Subject: [PATCH 47/59] upgrade to asm 9.1, for JDK 17 support fixes scala/bug#12332 --- src/intellij/scala.ipr.SAMPLE | 26 +++++++++++++------------- versions.properties | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/intellij/scala.ipr.SAMPLE b/src/intellij/scala.ipr.SAMPLE index 93154b92f738..836d9eb6d8df 100644 --- a/src/intellij/scala.ipr.SAMPLE +++ b/src/intellij/scala.ipr.SAMPLE @@ -231,7 +231,7 @@ - + @@ -250,7 +250,7 @@ - + @@ -262,7 +262,7 @@ - + @@ -280,7 +280,7 @@ - + @@ -290,7 +290,7 @@ - + @@ -317,7 +317,7 @@ - + @@ -331,7 +331,7 @@ - + @@ -340,7 +340,7 @@ - + @@ -350,7 +350,7 @@ - + @@ -511,7 +511,7 @@ - + @@ -524,7 +524,7 @@ - + @@ -535,7 +535,7 @@ - + @@ -560,7 +560,7 @@ - + diff --git a/versions.properties b/versions.properties index d4151f2e6ee6..e8f059f92d92 100644 --- a/versions.properties +++ b/versions.properties @@ -21,5 +21,5 @@ scala.binary.version=2.12 scala-xml.version.number=1.0.6 scala-parser-combinators.version.number=1.0.7 scala-swing.version.number=2.0.3 -scala-asm.version=9.0.0-scala-1 +scala-asm.version=9.1.0-scala-1 jline.version=2.14.6 From 4a5d2b6dd2ff3b2c943568f66d451795be842828 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Fri, 5 Jun 2020 10:55:12 +0200 Subject: [PATCH 48/59] Don't warnUnusedNowarn in scaladoc --- src/compiler/scala/tools/nsc/Reporting.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/scala/tools/nsc/Reporting.scala b/src/compiler/scala/tools/nsc/Reporting.scala index 5ac2547e82bd..7922ab33f531 100644 --- a/src/compiler/scala/tools/nsc/Reporting.scala +++ b/src/compiler/scala/tools/nsc/Reporting.scala @@ -76,7 +76,7 @@ trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions w def warnUnusedSuppressions(): Unit = { // if we stop before typer completes (errors in parser, Ystop), report all suspended messages suspendedMessages.foreach(issueWarning) - if (settings.warnUnusedNowarn) { + if (settings.warnUnusedNowarn && !settings.isScaladoc) { // scaladoc doesn't run all phases, so not all warnings are emitted val sources = suppressions.keysIterator.toList for (source <- sources; sups <- suppressions.remove(source); sup <- sups.reverse) { if (!sup.used) From a0f9840bfc41ae3450aedb4a391aaa9e331d0335 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 15 Feb 2021 16:24:19 +1000 Subject: [PATCH 49/59] Retain positions of SingletonTypeTree Regressed in #9426. I noticed the missing position when merging that change forward to 2.13.x, in which a new test case (neg/t12322a.scala) started giving inaccurate positions. --- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 2 +- test/junit/scala/tools/nsc/typechecker/TypedTreeTest.scala | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 98796a202a1e..9843d03d12ae 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -5628,7 +5628,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (refTyped.isErrorTyped) setError(tree) else { if (!treeInfo.admitsTypeSelection(refTyped)) UnstableTreeError(tree) - else SingletonTypeTree(refTyped).setType(refTyped.tpe.resultType.deconst) + else treeCopy.SingletonTypeTree(tree, refTyped).setType(refTyped.tpe.resultType.deconst) } } diff --git a/test/junit/scala/tools/nsc/typechecker/TypedTreeTest.scala b/test/junit/scala/tools/nsc/typechecker/TypedTreeTest.scala index 2ca590c07804..212d15fbb6ec 100644 --- a/test/junit/scala/tools/nsc/typechecker/TypedTreeTest.scala +++ b/test/junit/scala/tools/nsc/typechecker/TypedTreeTest.scala @@ -1,6 +1,6 @@ package scala.tools.nsc.typechecker -import org.junit.Assert.assertEquals +import org.junit.Assert.{assertEquals, assertNotEquals} import org.junit.Test import scala.tools.testing.BytecodeTesting @@ -59,6 +59,7 @@ class TypedTreeTest extends BytecodeTesting { singletonTypeTrees.foreach { t => assertEquals(t.ref.symbol.fullName, "root.impl") + assertNotEquals(NoPosition, t.pos) } } } From 0ed35f194f356ad9c80f56bebdec129f4a0aab62 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 16 Feb 2021 10:51:15 +1000 Subject: [PATCH 50/59] Fixup async synchronized checkfile --- test/async/neg/ill-nested-await.check | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/async/neg/ill-nested-await.check b/test/async/neg/ill-nested-await.check index 4c30f63ecb40..e04df598a775 100644 --- a/test/async/neg/ill-nested-await.check +++ b/test/async/neg/ill-nested-await.check @@ -34,13 +34,13 @@ ill-nested-await.scala:71: error: await must not be used under a lazy val initia ill-nested-await.scala:77: error: await must not be used under a nested method. async { fooAsByNameLambda(await(f(""))) } ^ -ill-nested-await.scala:81: error: await must not be used under a synchronized call. +ill-nested-await.scala:82: error: await must not be used under a synchronized call. async { lock.synchronized { await(f(1)) + await(f(2)) } } ^ -ill-nested-await.scala:81: error: await must not be used under a synchronized call. +ill-nested-await.scala:82: error: await must not be used under a synchronized call. async { lock.synchronized { await(f(1)) + await(f(2)) } } ^ -ill-nested-await.scala:10: error: `await` must be enclosed in an `async` block +ill-nested-await.scala:11: error: `await` must be enclosed in an `async` block await[Any](f(null)) ^ 15 errors From f4da037f6bda5233989f76ff656cfc03778ddff3 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 16 Feb 2021 11:56:04 +1000 Subject: [PATCH 51/59] Fix non-exhaustive match in Cleanup phase (cherry picked from commit 038b26de049c7e35d52dc66e773ca114cb5434e8) --- src/compiler/scala/tools/nsc/transform/CleanUp.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 017446d4708a..da03bb29933a 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -492,7 +492,7 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL { classTagEvidence.attachments.get[analyzer.MacroExpansionAttachment] match { case Some(att) if att.expandee.symbol.name == nme.materializeClassTag && tree.isInstanceOf[ApplyToImplicitArgs] => super.transform(arg) - case None => + case _ => localTyper.typedPos(tree.pos) { gen.evalOnce(classTagEvidence, currentOwner, unit) { ev => val arr = localTyper.typedPos(tree.pos)(gen.mkMethodCall(classTagEvidence, definitions.ClassTagClass.info.decl(nme.newArray), Nil, Literal(Constant(elems.size)) :: Nil)) From b705e3b467c0225cbe82f79af2034ffdfbe282e2 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 17 Feb 2021 14:38:02 +1000 Subject: [PATCH 52/59] Fix regression in box-unbox (in -opt:l:method) Using 2.12.14-bin-8562bab or 2.13.x after this [merge](https://github.com/scala/scala/pull/9433) ```scala // scalac: -opt:l:method package p1 class AssertUtil { def waitForIt(terminated: => Boolean, progress: Int = 0, label: => String = "test"): Unit = { val limit = 5 var n = 1 var (dormancy, factor) = progress match { case 0 => (10000L, 5) case _ => (250L, 4) } () } } ``` ```scala // scalac: -opt:l:inline -opt-inline-from: package p1; class C { def f(b: java.lang.Byte) = { var box = 0 @inline def writeBox: Unit = { box = 1 } writeBox } } ``` Invalid bytecode generated, resulting in a later compiler crash. The first incorrectly orders the compensating POP instructions inserted for the `Long` and `Int` sized operands. The second reproducer only fails when the patch in merged to 2.13.x, as it relies on a particular bytecode shape that leaves a POP instruction as the final consumer. Discovered during https://github.com/scala/scala/pull/9495 Regression introduced in https://github.com/scala/scala/pull/9433. This was merged _after_ 2.12.13 was released. The enclosed test crafts the problematic bytecode for the second case directly. The first is tested directly. --- .../tools/nsc/backend/jvm/opt/BoxUnbox.scala | 3 +- .../jvm/opt/BoxUnboxAndInlineTest.scala | 106 ++++++++++++++++++ .../nsc/backend/jvm/opt/BoxUnboxTest.scala | 21 ++++ 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxAndInlineTest.scala diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala index 2eda2438d5b9..ec7a46300a65 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala @@ -266,6 +266,7 @@ abstract class BoxUnbox { case Drop(insn) => if (keepBox) toReplace(insn) = List(getPop(1)) + else toDelete += insn case extraction => val (slot, tp) = localSlots(boxKind.extractedValueIndex(extraction)) @@ -341,7 +342,7 @@ abstract class BoxUnbox { for (extraction <- allConsumers) { val replacementOps = extraction match { case Drop(_) => - boxKind.boxedTypes.map(t => getPop(t.getSize)) + boxKind.boxedTypes.reverseMap(t => getPop(t.getSize)) case _ => val valueIndex = boxKind.extractedValueIndex(extraction) if (valueIndex == 0) { diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxAndInlineTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxAndInlineTest.scala new file mode 100644 index 000000000000..3d34ff65c4ee --- /dev/null +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxAndInlineTest.scala @@ -0,0 +1,106 @@ +package scala.tools.nsc.backend.jvm.opt + +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import scala.tools.asm.Opcodes +import scala.tools.asm.Opcodes._ +import scala.tools.asm.util.CheckMethodAdapter +import scala.tools.nsc.backend.jvm.MethodNode1 +import scala.tools.partest.ASMConverters._ +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ + +/** + * Tests for boxing/unboxing optimizations. + */ +@RunWith(classOf[JUnit4]) +class BoxUnboxAndInlineTest extends BytecodeTesting { + override def compilerArgs = "-opt:l:inline -opt-inline-from:**/*" + import compiler._ + + // Was crashing in 2.13.x once https://github.com/scala/scala/pull/9433 was merged in. + // Failure was: scala.tools.asm.tree.analysis.AnalyzerException: Error at instruction 16: Cannot pop operand off an empty stack. + // Discussion: https://github.com/scala/scala/pull/9495#issuecomment-779600132 + @Test + def unboxAsmCrash(): Unit = { + val code = + """package p1; class C { + |def f(b: java.lang.Byte) = { + | var box = 0 + | + | @inline def writeBox: Unit = { + | box = 1 + | } + | + | writeBox + |} + |}""".stripMargin + val c = compileClass(code) + assertSameSummary(getMethod(c, "f"), List(RETURN)) + + } + + // This bytecode pattern results from `unboxAsmCrash` in 2.13.x and exposes a bug in + // https://github.com/scala/scala/pull/9392, which landed originally in 2.12.x. + // + // The bytecode shape after the inliner differs in 2.12.x to masks the bug, probably due to + // https://github.com/scala/scala/pull/7133, which is 2.13.x only. + // + // This test constructs the problematic bytecode shape directly. Before the patch, it + // has an extra POP instruction which would be reported as invalid bytecode by CheckMethodAdapter. + // "Error at instruction 5: Cannot pop operand off an empty stack. m()V" + // + @Test + def unboxAsmCrashDirect(): Unit = { + val code: List[Instruction] = List( + Label(1), + Op(ACONST_NULL), + Invoke(INVOKESTATIC, "scala/runtime/ObjectRef", "create", "(Ljava/lang/Object;)Lscala/runtime/ObjectRef;", false), + VarOp(ASTORE, 1), + Op(ACONST_NULL), + VarOp(ALOAD, 1), + Op(POP), + VarOp(ASTORE, 2), + VarOp(ALOAD, 1), + VarOp(ALOAD, 2), + Field(PUTFIELD, "scala/runtime/ObjectRef", "elem", "Ljava/lang/Object;"), + Op(ACONST_NULL), + VarOp(ASTORE, 2), + Op(RETURN) + ) + val method = genMethod(localVars = List( + LocalVariable("this", "Lcom/foo/Bar;", None, Label(1), Label(1), 1), + LocalVariable("x", "Lscala/runtime/ObjectRef;", None, Label(1), Label(1), 1), + LocalVariable("y", "Lscala/runtime/ObjectRef;", None, Label(1), Label(1), 1), + // introduced by the box/unbox transform, we create the slot ahead of time. CheckMethodAdapter + // relies on it to verify the bytecode. + LocalVariable("z", "Lscala/runtime/ObjectRef;", None, Label(1), Label(1), 1) + ))(code: _*) + + val r = new compiler.global.Run() + compiler.global.enteringPhase(r.jvmPhase) { + compiler.global.genBCode.postProcessor.initialize() + val changed = compiler.global.genBCode.postProcessor.localOpt.boxUnbox.boxUnboxElimination(method, "p1.Owner") + assert(changed) + method.visitMaxs(2, 4) + val labelInsnIndices = new java.util.HashMap[scala.tools.asm.Label, java.lang.Integer]() + method.instructions.resetLabels() + + val checker = new CheckMethodAdapter(Opcodes.V1_8, "m", "()V", new MethodNode1(), labelInsnIndices) + method.accept(checker) + + assertSameCode(convertMethod(method), List( + Op(ACONST_NULL), + VarOp(ASTORE, 3), + Op(ACONST_NULL), + VarOp(ASTORE, 2), + VarOp(ALOAD, 2), + VarOp(ASTORE, 3), + Op(ACONST_NULL), + VarOp(ASTORE, 2), + Op(RETURN))) + } + } +} diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala index 07d8a24a8329..3ed9b019ae9c 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala @@ -365,4 +365,25 @@ class BoxUnboxTest extends BytecodeTesting { )) } + @Test + def unboxAsmCrash(): Unit = { + val code = + """ + |package p1 + | + |class AssertUtil { + | + | def waitForIt(terminated: => Boolean, progress: Int = 0, label: => String = "test"): Unit = { + | val limit = 5 + | var n = 1 + | var (dormancy, factor) = progress match { + | case 0 => (10000L, 5) + | case _ => (250L, 4) + | } + | () + | } + |}""".stripMargin + val m = getMethod(compileClass(code), "waitForIt") + assertSameCode(m, List(VarOp(ILOAD, 2), TableSwitch(TABLESWITCH, 0, 0, Label(4), List(Label(4))), Label(4), Op(RETURN))) + } } From 0e0fb08da4d0b2040ef7611551098856750dcdea Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 27 Jan 2021 15:30:28 +0000 Subject: [PATCH 53/59] Fix mimaReportBinaryIssues, not run aggregate When you run a task in the shell, it uses the current project (normally root) and runs the tasks on the project and the project it aggregates. That's why "compile" compiles all and "test" tests all. But "testAll" is our custom thing, defined only on the root project, which refers to specific tasks to run. So while just "mimaReportBinaryIssues" does the right thing in the shell, it only checks root (which is a noop) when used in "testAll". So back to specifying both - but at least I still fixed unqualified "mimaReportBinaryIssues" from working in the shell. (cherry picked from commit 8e5951d307bfef14cb1a19c50196dd55b1ff4441) backport of #9459 --- build.sbt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 631c7b8516e8..02fad2c5148b 100644 --- a/build.sbt +++ b/build.sbt @@ -939,7 +939,8 @@ lazy val root: Project = (project in file(".")) (testOnly in IntegrationTest in testP).toTask(" -- --srcpath async").result map (_ -> "partest --srcpath async"), (Keys.test in Test in osgiTestFelix).result map (_ -> "osgiTestFelix/test"), (Keys.test in Test in osgiTestEclipse).result map (_ -> "osgiTestEclipse/test"), - (mimaReportBinaryIssues).result map (_ -> "mimaReportBinaryIssues"), + (library / mimaReportBinaryIssues).result.map(_ -> "library/mimaReportBinaryIssues"), // doesn't aggregate.. + (reflect / mimaReportBinaryIssues).result.map(_ -> "reflect/mimaReportBinaryIssues"), // ..so specify both (compile in Compile in bench).map(_ => ()).result map (_ -> "bench/compile"), Def.task(()).dependsOn( // Run these in parallel: doc in Compile in library, From dc809a564930f8174b2012396c6dcc00eb9f7e77 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 17 Feb 2021 10:08:35 +0000 Subject: [PATCH 54/59] Add missing MiMa filters for NewRedBlackTree --- project/MimaFilters.scala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/project/MimaFilters.scala b/project/MimaFilters.scala index 82413b377722..0a0a5996591b 100644 --- a/project/MimaFilters.scala +++ b/project/MimaFilters.scala @@ -22,6 +22,9 @@ object MimaFilters extends AutoPlugin { // #9314 introduced private[this] object ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.TreeSet$unitsIterator$"), + + // #9314 #9315 #9507 NewRedBlackTree is private[collection] + ProblemFilters.exclude[Problem]("scala.collection.immutable.NewRedBlackTree*"), ) override val buildSettings = Seq( From 5eb4b452180801454953db406255404eea9e25fc Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 16 Feb 2021 23:39:14 +1000 Subject: [PATCH 55/59] Fixup partitionKeys / unused import --- test/junit/scala/tools/nsc/parser/ParserTest.scala | 1 - test/scalacheck/redblacktree.scala | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/test/junit/scala/tools/nsc/parser/ParserTest.scala b/test/junit/scala/tools/nsc/parser/ParserTest.scala index 420527abcfb3..0073043f978f 100644 --- a/test/junit/scala/tools/nsc/parser/ParserTest.scala +++ b/test/junit/scala/tools/nsc/parser/ParserTest.scala @@ -1,6 +1,5 @@ package scala.tools.nsc.parser -import org.junit.Assert._ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 diff --git a/test/scalacheck/redblacktree.scala b/test/scalacheck/redblacktree.scala index ea5cab8c1dcd..3d4cfdd145a4 100644 --- a/test/scalacheck/redblacktree.scala +++ b/test/scalacheck/redblacktree.scala @@ -400,7 +400,7 @@ object TestPartitionLeft extends RedBlackTreeTest("RedBlackTree.partitionKeysLef override type ModifyParm = Int override def genParm(tree: Tree[String, Int]): Gen[ModifyParm] = choose(0, 0) override def modify(tree: Tree[String, Int], parm: ModifyParm): Tree[String, Int] = - partitionKeys[String, Int](tree, k => k.hashCode % 2 == 0)._1 + partitionEntries[String, Int](tree, (k, v) => k.hashCode % 2 == 0)._1 property("partition") = forAll(genInput) { case (tree, parm, newTree) => iterator(tree).filter(t => t._1.hashCode % 2 == 0).toList == iterator(newTree).toList @@ -413,7 +413,7 @@ object TestPartitionRight extends RedBlackTreeTest("RedBlackTree.partitionKeysRi override type ModifyParm = Int override def genParm(tree: Tree[String, Int]): Gen[ModifyParm] = choose(0, 0) override def modify(tree: Tree[String, Int], parm: ModifyParm): Tree[String, Int] = - partitionKeys[String, Int](tree, k => k.hashCode % 2 == 0)._2 + partitionEntries[String, Int](tree, (k, v) => k.hashCode % 2 == 0)._2 property("partition") = forAll(genInput) { case (tree, parm, newTree) => iterator(tree).filter(t => t._1.hashCode % 2 != 0).toList == iterator(newTree).toList From 743f4ed72dc494b389f451ec089279e7b4c3a722 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Thu, 18 Feb 2021 13:35:20 +1000 Subject: [PATCH 56/59] Fixup box/unbox merge --- src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala | 2 +- .../tools/nsc/backend/jvm/opt/BoxUnboxAndInlineTest.scala | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala index 227cbe35a543..7d790313f694 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala @@ -343,7 +343,7 @@ abstract class BoxUnbox { for (extraction <- allConsumers) { val replacementOps = extraction match { case Drop(_) => - boxKind.boxedTypes.reverseMap(t => getPop(t.getSize)) + boxKind.boxedTypes.reverseIterator.map(t => getPop(t.getSize)).toList case _ => val valueIndex = boxKind.extractedValueIndex(extraction) if (valueIndex == 0) { diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxAndInlineTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxAndInlineTest.scala index 3d34ff65c4ee..7277f3a91797 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxAndInlineTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/BoxUnboxAndInlineTest.scala @@ -8,9 +8,9 @@ import scala.tools.asm.Opcodes import scala.tools.asm.Opcodes._ import scala.tools.asm.util.CheckMethodAdapter import scala.tools.nsc.backend.jvm.MethodNode1 -import scala.tools.partest.ASMConverters._ -import scala.tools.testing.BytecodeTesting -import scala.tools.testing.BytecodeTesting._ +import scala.tools.testkit.ASMConverters._ +import scala.tools.testkit.BytecodeTesting +import scala.tools.testkit.BytecodeTesting._ /** * Tests for boxing/unboxing optimizations. From 260ae05fde9da808d44e5db4dfb2d4301fd8fbf1 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Thu, 18 Feb 2021 16:07:57 +1000 Subject: [PATCH 57/59] Fixup checkfile --- test/files/run/t12038b.check | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/files/run/t12038b.check b/test/files/run/t12038b.check index f53073d631c9..c44e84a62530 100644 --- a/test/files/run/t12038b.check +++ b/test/files/run/t12038b.check @@ -1 +1 @@ -(x$1: p1.J_1.O[Object]#$I[String])Unit +(x$1: p1.J_1.O[Object]#$I[String]): Unit From 7f16fec45e5a0f9dd04e34baf60bac8f9766432d Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Thu, 18 Feb 2021 17:15:51 +1000 Subject: [PATCH 58/59] MiMa whitelist for RedBlackTree internal changes --- project/MimaFilters.scala | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/project/MimaFilters.scala b/project/MimaFilters.scala index 722642074c1b..451319c30c9a 100644 --- a/project/MimaFilters.scala +++ b/project/MimaFilters.scala @@ -30,6 +30,13 @@ object MimaFilters extends AutoPlugin { // #9487 ProblemFilters.exclude[MissingClassProblem]("scala.reflect.ClassTag$cache$"), + + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#Tree.redWithRight"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#Tree.redWithLeftRight"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#Tree.blackWithLeftRight"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree.partitionKeys"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree.partitionKeys"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#Tree.redWithLeft"), ) override val buildSettings = Seq( From 888ef9448c1116b2c57c28df478f8fcfb8078066 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Thu, 18 Feb 2021 12:08:19 +0100 Subject: [PATCH 59/59] cleanups --- project/MimaFilters.scala | 4 ++-- .../scala/collection/immutable/RedBlackTree.scala | 15 --------------- .../junit/scala/tools/nsc/parser/ParserTest.scala | 2 +- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/project/MimaFilters.scala b/project/MimaFilters.scala index 451319c30c9a..b6e61976b735 100644 --- a/project/MimaFilters.scala +++ b/project/MimaFilters.scala @@ -34,9 +34,9 @@ object MimaFilters extends AutoPlugin { ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#Tree.redWithRight"), ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#Tree.redWithLeftRight"), ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#Tree.blackWithLeftRight"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree.partitionKeys"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree.partitionKeys"), ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree#Tree.redWithLeft"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree.partitionKeys"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.RedBlackTree.filterKeys"), ) override val buildSettings = Seq( diff --git a/src/library/scala/collection/immutable/RedBlackTree.scala b/src/library/scala/collection/immutable/RedBlackTree.scala index 02eae5c02789..2e7aa7b472ad 100644 --- a/src/library/scala/collection/immutable/RedBlackTree.scala +++ b/src/library/scala/collection/immutable/RedBlackTree.scala @@ -989,21 +989,6 @@ private[collection] object RedBlackTree { blacken(fk(t)) } - def filterKeys[A, B](t: Tree[A, B], f: A => Boolean): Tree[A, B] = if(t eq null) null else { - def fk(t: Tree[A, B]): Tree[A, B] = { - val k = t.key - val l = t.left - val r = t.right - val l2 = if(l eq null) null else fk(l) - val keep = f(k) - val r2 = if(r eq null) null else fk(r) - if(!keep) join2(l2, r2) - else if((l2 eq l) && (r2 eq r)) t - else join(l2, k, t.value, r2) - } - blacken(fk(t)) - } - private[this] val null2 = (null, null) def partitionEntries[A, B](t: Tree[A, B], p: (A, B) => Boolean): (Tree[A, B], Tree[A, B]) = if(t eq null) (null, null) else { diff --git a/test/junit/scala/tools/nsc/parser/ParserTest.scala b/test/junit/scala/tools/nsc/parser/ParserTest.scala index 0073043f978f..dd5f562fe67e 100644 --- a/test/junit/scala/tools/nsc/parser/ParserTest.scala +++ b/test/junit/scala/tools/nsc/parser/ParserTest.scala @@ -38,7 +38,7 @@ class ParserTest extends BytecodeTesting{ import compiler._, global._ val run = new Run run.compileSources(newSourceFile(code) :: Nil) - assert(!reporter.hasErrors) + assertFalse(reporter.hasErrors) val unit = run.units.toList.head def codeOf(pos: Position) = new String(pos.source.content.slice(pos.start, pos.end)) val List(x, y) = unit.body.collect { case vd : ValDef => vd }.takeRight(2)