Skip to content

Commit 0012d82

Browse files
julienrfsjrd
authored andcommitted
Support Scala 2.13.0-M4 in all the non-tools artifacts.
This commit puts the codebase in a state where we can build the compiler plugins, libraries and test suite with Scala 2.13.0-M4 and its new collections. The tools API and related artifacts are not yet updated. This is the minimal set of changes necessary to be able to build and back-publish for 2.13.0-M4 when it comes out. We will not be able to publish tools artifact for that version, but that is not critical.
1 parent 17aba05 commit 0012d82

File tree

53 files changed

+2043
-932
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+2043
-932
lines changed

ci/checksizes.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ REVERSI_OPT_GZ_SIZE=$(stat '-c%s' "$REVERSI_OPT.gz")
3737

3838
case $FULLVER in
3939
2.10.2)
40-
REVERSI_PREOPT_EXPECTEDSIZE=532000
40+
REVERSI_PREOPT_EXPECTEDSIZE=533000
4141
REVERSI_OPT_EXPECTEDSIZE=122000
4242
REVERSI_PREOPT_GZ_EXPECTEDSIZE=71000
4343
REVERSI_OPT_GZ_EXPECTEDSIZE=31000
@@ -55,7 +55,7 @@ case $FULLVER in
5555
REVERSI_OPT_GZ_EXPECTEDSIZE=33000
5656
;;
5757
2.13.0-M3)
58-
REVERSI_PREOPT_EXPECTEDSIZE=628000
58+
REVERSI_PREOPT_EXPECTEDSIZE=629000
5959
REVERSI_OPT_EXPECTEDSIZE=147000
6060
REVERSI_PREOPT_GZ_EXPECTEDSIZE=77000
6161
REVERSI_OPT_GZ_EXPECTEDSIZE=33000

compiler/src/main/scala/org/scalajs/core/compiler/GenJSCode.scala

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,7 +1395,7 @@ abstract class GenJSCode extends plugins.PluginComponent
13951395

13961396
val ctorToChildren = secondaryCtors.map { ctor =>
13971397
findCtorForwarderCall(ctor.body.get) -> ctor
1398-
}.groupBy(_._1).mapValues(_.map(_._2)).withDefaultValue(Nil)
1398+
}.groupBy(_._1).mapValues(_.map(_._2)).toMap.withDefaultValue(Nil)
13991399

14001400
var overrideNum = -1
14011401
def mkConstructorTree(method: js.MethodDef): ConstructorTree = {
@@ -1546,9 +1546,9 @@ abstract class GenJSCode extends plugins.PluginComponent
15461546

15471547
val methodDefWithoutUselessVars = {
15481548
val unmutatedMutableLocalVars =
1549-
(mutableLocalVars -- mutatedLocalVars).toList
1549+
(mutableLocalVars.diff(mutatedLocalVars)).toList
15501550
val mutatedImmutableLocalVals =
1551-
(mutatedLocalVars -- mutableLocalVars).toList
1551+
(mutatedLocalVars.diff(mutableLocalVars)).toList
15521552
if (unmutatedMutableLocalVars.isEmpty &&
15531553
mutatedImmutableLocalVals.isEmpty) {
15541554
// OK, we're good (common case)
@@ -4643,10 +4643,12 @@ abstract class GenJSCode extends plugins.PluginComponent
46434643
}
46444644

46454645
/** Gen actual actual arguments to Scala method call.
4646+
*
46464647
* Returns a list of the transformed arguments.
46474648
*
46484649
* This tries to optimize repeated arguments (varargs) by turning them
4649-
* into js.WrappedArray instead of Scala wrapped arrays.
4650+
* into JS arrays wrapped in the appropriate Seq, rather than Scala
4651+
* arrays.
46504652
*/
46514653
private def genActualArgs(sym: Symbol, args: List[Tree])(
46524654
implicit pos: Position): List[js.Tree] = {
@@ -4671,8 +4673,7 @@ abstract class GenJSCode extends plugins.PluginComponent
46714673
tryGenRepeatedParamAsJSArray(arg, handleNil = false).fold {
46724674
genExpr(arg)
46734675
} { genArgs =>
4674-
genNew(WrappedArrayClass, WrappedArray_ctor,
4675-
List(js.JSArrayConstr(genArgs)))
4676+
genJSArrayToVarArgs(js.JSArrayConstr(genArgs))
46764677
}
46774678
} else {
46784679
genExpr(arg)
@@ -4829,18 +4830,25 @@ abstract class GenJSCode extends plugins.PluginComponent
48294830
}
48304831

48314832
object WrapArray {
4832-
lazy val isWrapArray: Set[Symbol] = Seq(
4833-
nme.wrapRefArray,
4834-
nme.wrapByteArray,
4835-
nme.wrapShortArray,
4836-
nme.wrapCharArray,
4837-
nme.wrapIntArray,
4838-
nme.wrapLongArray,
4839-
nme.wrapFloatArray,
4840-
nme.wrapDoubleArray,
4841-
nme.wrapBooleanArray,
4842-
nme.wrapUnitArray,
4843-
nme.genericWrapArray).map(getMemberMethod(PredefModule, _)).toSet
4833+
private val isWrapArray: Set[Symbol] = {
4834+
val wrapArrayModule =
4835+
if (hasNewCollections) ScalaRunTimeModule
4836+
else PredefModule
4837+
4838+
Seq(
4839+
nme.wrapRefArray,
4840+
nme.wrapByteArray,
4841+
nme.wrapShortArray,
4842+
nme.wrapCharArray,
4843+
nme.wrapIntArray,
4844+
nme.wrapLongArray,
4845+
nme.wrapFloatArray,
4846+
nme.wrapDoubleArray,
4847+
nme.wrapBooleanArray,
4848+
nme.wrapUnitArray,
4849+
nme.genericWrapArray
4850+
).map(getMemberMethod(wrapArrayModule, _)).toSet
4851+
}
48444852

48454853
def unapply(tree: Apply): Option[Tree] = tree match {
48464854
case Apply(wrapArray_?, List(wrapped))
@@ -4851,6 +4859,13 @@ abstract class GenJSCode extends plugins.PluginComponent
48514859
}
48524860
}
48534861

4862+
/** Wraps a `js.Array` to use as varargs. */
4863+
def genJSArrayToVarArgs(arrayRef: js.Tree)(
4864+
implicit pos: Position): js.Tree = {
4865+
genApplyMethod(genLoadModule(RuntimePackageModule),
4866+
Runtime_toScalaVarArgs, List(arrayRef))
4867+
}
4868+
48544869
// Synthesizers for raw JS functions ---------------------------------------
48554870

48564871
/** Try and generate JS code for an anonymous function class.
@@ -5534,6 +5549,14 @@ abstract class GenJSCode extends plugins.PluginComponent
55345549
settings.Xexperimental.value
55355550
}
55365551

5552+
private lazy val hasNewCollections = {
5553+
val v = scala.util.Properties.versionNumberString
5554+
!v.startsWith("2.10.") &&
5555+
!v.startsWith("2.11.") &&
5556+
!v.startsWith("2.12.") &&
5557+
v != "2.13.0-M3"
5558+
}
5559+
55375560
/** Tests whether the given type represents a raw JavaScript type,
55385561
* i.e., whether it extends scala.scalajs.js.Any.
55395562
*/

compiler/src/main/scala/org/scalajs/core/compiler/GenJSExports.scala

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ trait GenJSExports extends SubComponent { self: GenJSCode =>
461461

462462
// Create a map: argCount -> methods (methods may appear multiple times)
463463
val methodByArgCount =
464-
methodArgCounts.groupBy(_._1).mapValues(_.map(_._2).toSet)
464+
methodArgCounts.groupBy(_._1).mapValues(_.map(_._2).toSet).toMap
465465

466466
// Minimum number of arguments that must be given
467467
val minArgc = methodByArgCount.keys.min
@@ -754,9 +754,7 @@ trait GenJSExports extends SubComponent { self: GenJSCode =>
754754

755755
// optional repeated parameter list
756756
val jsVarArgPrep = repeatedTpe map { tpe =>
757-
// new WrappedArray(varargs)
758-
val rhs = genNew(WrappedArrayClass, WrappedArray_ctor, List(
759-
genVarargRef(normalArgc, minArgc)))
757+
val rhs = genJSArrayToVarArgs(genVarargRef(normalArgc, minArgc))
760758
js.VarDef(js.Ident("prep" + normalArgc), rhs.tpe, mutable = false, rhs)
761759
}
762760

compiler/src/main/scala/org/scalajs/core/compiler/JSDefinitions.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,16 +126,14 @@ trait JSDefinitions { self: JSGlobalAddons =>
126126
lazy val Runtime_unwrapJavaScriptException = getMemberMethod(RuntimePackageModule, newTermName("unwrapJavaScriptException"))
127127
lazy val Runtime_jsObjectSuperGet = getMemberMethod(RuntimePackageModule, newTermName("jsObjectSuperGet"))
128128
lazy val Runtime_jsObjectSuperSet = getMemberMethod(RuntimePackageModule, newTermName("jsObjectSuperSet"))
129+
lazy val Runtime_toScalaVarArgs = getMemberMethod(RuntimePackageModule, newTermName("toScalaVarArgs"))
129130
lazy val Runtime_genTraversableOnce2jsArray = getMemberMethod(RuntimePackageModule, newTermName("genTraversableOnce2jsArray"))
130131
lazy val Runtime_jsTupleArray2jsObject = getMemberMethod(RuntimePackageModule, newTermName("jsTupleArray2jsObject"))
131132
lazy val Runtime_constructorOf = getMemberMethod(RuntimePackageModule, newTermName("constructorOf"))
132133
lazy val Runtime_newConstructorTag = getMemberMethod(RuntimePackageModule, newTermName("newConstructorTag"))
133134
lazy val Runtime_propertiesOf = getMemberMethod(RuntimePackageModule, newTermName("propertiesOf"))
134135
lazy val Runtime_linkingInfo = getMemberMethod(RuntimePackageModule, newTermName("linkingInfo"))
135136

136-
lazy val WrappedArrayClass = getRequiredClass("scala.scalajs.js.WrappedArray")
137-
lazy val WrappedArray_ctor = WrappedArrayClass.primaryConstructor
138-
139137
// This is a def, since similar symbols (arrayUpdateMethod, etc.) are in runDefinitions
140138
// (rather than definitions) and we weren't sure if it is safe to make this a lazy val
141139
def ScalaRunTime_isArray: Symbol = getMemberMethod(ScalaRunTimeModule, newTermName("isArray")).suchThat(_.tpe.params.size == 2)

compiler/src/main/scala/org/scalajs/core/compiler/PrepJSExports.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -641,8 +641,8 @@ trait PrepJSExports { this: PrepJSInterop =>
641641
def ph = Ident(Predef_???)
642642

643643
// Create a call to the forwarded method with ??? as args
644-
val sel: Tree = Select(This(clsSym), defSym)
645-
val call = (sel /: defSym.paramss) {
644+
val sel = Select(This(clsSym), defSym)
645+
val call = defSym.paramss.foldLeft[Tree](sel) {
646646
(fun, params) => Apply(fun, List.fill(params.size)(ph))
647647
}
648648

@@ -687,8 +687,8 @@ trait PrepJSExports { this: PrepJSInterop =>
687687
}
688688

689689
// Construct proxied function call
690-
val sel: Tree = Select(This(clsSym), trgSym)
691-
val rhs = (sel /: proxySym.paramss) {
690+
val sel = Select(This(clsSym), trgSym)
691+
val rhs = proxySym.paramss.foldLeft[Tree](sel) {
692692
(fun,params) => Apply(fun, params map spliceParam)
693693
}
694694

compiler/src/test/scala/org/scalajs/core/compiler/test/JSExportTest.scala

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,18 @@ class JSExportTest extends DirectTest with TestHelpers {
821821
@Test
822822
def noOverrideNamedExport: Unit = {
823823

824+
val indent = {
825+
val version = scala.util.Properties.versionNumberString
826+
if (version.startsWith("2.10.") ||
827+
version.startsWith("2.11.") ||
828+
version.startsWith("2.12.") ||
829+
version == "2.13.0-M3") {
830+
" "
831+
} else {
832+
" "
833+
}
834+
}
835+
824836
"""
825837
class A {
826838
@JSExportNamed
@@ -840,7 +852,7 @@ class JSExportTest extends DirectTest with TestHelpers {
840852
| @JSExportNamed
841853
| ^
842854
|newSource1.scala:9: error: overriding method $$js$$exported$$meth$$foo in class A of type (namedArgs: Any)Any;
843-
| method $$js$$exported$$meth$$foo cannot override final member
855+
|${indent}method $$js$$exported$$meth$$foo cannot override final member
844856
| @JSExportNamed
845857
| ^
846858
|newSource1.scala:10: warning: class JSExportNamed in package annotation is deprecated${since("0.6.11")}: Use @JSExport with an explicit option bag instead. See the Scaladoc for more details.

compiler/src/test/scala/org/scalajs/core/compiler/test/OptimizationTest.scala

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import org.junit.Test
77
import org.scalajs.core.ir.{Trees => js, Types => jstpe}
88

99
class OptimizationTest extends JSASTTest {
10+
import OptimizationTest._
1011

1112
@Test
1213
def unwrapScalaFunWrapper: Unit = {
@@ -55,8 +56,7 @@ class OptimizationTest extends JSASTTest {
5556
}
5657
""".
5758
hasNot("any of the wrapArray methods") {
58-
case js.Apply(_, js.Ident(name, _), _)
59-
if name.startsWith("wrap") && name.endsWith("__scm_WrappedArray") =>
59+
case WrapArrayCall() =>
6060
}
6161
}
6262

@@ -79,8 +79,7 @@ class OptimizationTest extends JSASTTest {
7979
}
8080
""".
8181
hasNot("any of the wrapArray methods") {
82-
case js.Apply(_, js.Ident(name, _), _)
83-
if name.startsWith("wrap") && name.endsWith("__scm_WrappedArray") =>
82+
case WrapArrayCall() =>
8483
}
8584

8685
/* #2265 and #2741:
@@ -108,21 +107,30 @@ class OptimizationTest extends JSASTTest {
108107
}
109108
""".
110109
hasNot("any of the wrapArray methods") {
111-
case js.Apply(_, js.Ident(name, _), _)
112-
if name.startsWith("wrap") && name.endsWith("__scm_WrappedArray") =>
110+
case WrapArrayCall() =>
113111
}
114112

115-
// Make sure our wrapper matcher has the right name
116-
"""
117-
import scala.scalajs.js
118-
119-
class A {
120-
val a: Seq[Int] = new Array[Int](5)
113+
/* Make sure our wrapper matcher has the right name.
114+
* With the new collections, only actual varargs will produce a call to the
115+
* methods we optimize, and we would always be able to optimize them in
116+
* that case. So we need to explicitly call the method that the codegen
117+
* would use.
118+
*/
119+
val sanityCheckCode = if (hasOldCollections) {
120+
"""
121+
class A {
122+
val a: Seq[Int] = new Array[Int](5)
123+
}
124+
"""
125+
} else {
126+
"""
127+
class A {
128+
runtime.ScalaRunTime.wrapIntArray(new Array[Int](5))
129+
}
130+
"""
121131
}
122-
""".
123-
has("one of the wrapArray methods") {
124-
case js.Apply(_, js.Ident(name, _), _)
125-
if name.startsWith("wrap") && name.endsWith("__scm_WrappedArray") =>
132+
sanityCheckCode.has("one of the wrapArray methods") {
133+
case WrapArrayCall() =>
126134
}
127135
}
128136

@@ -258,3 +266,27 @@ class OptimizationTest extends JSASTTest {
258266
}
259267

260268
}
269+
270+
object OptimizationTest {
271+
272+
private val hasOldCollections = {
273+
val version = scala.util.Properties.versionNumberString
274+
275+
version.startsWith("2.10.") ||
276+
version.startsWith("2.11.") ||
277+
version.startsWith("2.12.") ||
278+
version == "2.13.0-M3"
279+
}
280+
281+
private object WrapArrayCall {
282+
private val Suffix =
283+
if (hasOldCollections) "__scm_WrappedArray"
284+
else "__sci_ImmutableArray"
285+
286+
def unapply(tree: js.Apply): Boolean = {
287+
val methodName = tree.method.name
288+
methodName.startsWith("wrap") && methodName.endsWith(Suffix)
289+
}
290+
}
291+
292+
}

javalib/src/main/scala/java/util/ArrayList.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class ArrayList[E] private (private[ArrayList] val inner: js.Array[E])
6666
override def addAll(index: Int, c: Collection[_ <: E]): Boolean = {
6767
c match {
6868
case other: ArrayList[_] =>
69-
inner.splice(index, 0, other.inner: _*)
69+
inner.splice(index, 0, other.inner.toSeq: _*)
7070
other.size > 0
7171
case _ => super.addAll(index, c)
7272
}

javalib/src/main/scala/java/util/Collections.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ object Collections {
537537
}
538538

539539
def addAll[T](c: Collection[_ >: T], elements: Array[AnyRef]): Boolean =
540-
c.addAll((elements.asInstanceOf[Array[T]]: Seq[T]).asJava)
540+
c.addAll(elements.asInstanceOf[Array[T]].toSeq.asJava)
541541

542542
def newSetFromMap[E](map: Map[E, java.lang.Boolean]): Set[E] = {
543543
if (!map.isEmpty)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package java.util
2+
3+
import scala.collection.mutable
4+
5+
/** Make some Scala 2.13 APIs available in older Scala versions. */
6+
private[util] object Compat {
7+
8+
/** Adds methods from 2.13 to `SortedSet`.
9+
*
10+
* The `to` operation has been renamed to `rangeTo` in 2.13, to not
11+
* conflict with the `to` operation in `Iterable`.
12+
*/
13+
implicit class SortedSetCompat[A](val __private_self: mutable.SortedSet[A])
14+
extends AnyVal {
15+
16+
@inline private def self: mutable.SortedSet[A] = __private_self
17+
18+
/* Note: the double implicit conversion trick does not work here because
19+
* there *is* a `to` method in 2.13 (but it takes a `Factory` as parameter)
20+
* so the second implicit conversion is never triggered.
21+
*/
22+
def rangeTo(to: A): mutable.SortedSet[A] = {
23+
// Implementation copied from 2.12's implementation
24+
val i = self.rangeFrom(to).iterator
25+
if (i.isEmpty) {
26+
self
27+
} else {
28+
val next = i.next()
29+
if (self.ordering.compare(next, to) == 0) {
30+
if (i.isEmpty) self
31+
else self.rangeUntil(i.next())
32+
} else {
33+
self.rangeUntil(next)
34+
}
35+
}
36+
}
37+
38+
/* Note: the double implicit conversion trick does not work here either
39+
* because the `from` and `until` methods still exist on 2.13 but they
40+
* are deprecated.
41+
*/
42+
def rangeFrom(a: A): mutable.SortedSet[A] = self.rangeImpl(Some(a), None)
43+
def rangeUntil(a: A): mutable.SortedSet[A] = self.rangeImpl(None, Some(a))
44+
45+
}
46+
47+
}

0 commit comments

Comments
 (0)