Skip to content

Commit

Permalink
Support Scala 2.13.0-M4 in all the non-tools artifacts.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
julienrf authored and sjrd committed May 14, 2018
1 parent 17aba05 commit 0012d82
Show file tree
Hide file tree
Showing 53 changed files with 2,043 additions and 932 deletions.
4 changes: 2 additions & 2 deletions ci/checksizes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ REVERSI_OPT_GZ_SIZE=$(stat '-c%s' "$REVERSI_OPT.gz")

case $FULLVER in
2.10.2)
REVERSI_PREOPT_EXPECTEDSIZE=532000
REVERSI_PREOPT_EXPECTEDSIZE=533000
REVERSI_OPT_EXPECTEDSIZE=122000
REVERSI_PREOPT_GZ_EXPECTEDSIZE=71000
REVERSI_OPT_GZ_EXPECTEDSIZE=31000
Expand All @@ -55,7 +55,7 @@ case $FULLVER in
REVERSI_OPT_GZ_EXPECTEDSIZE=33000
;;
2.13.0-M3)
REVERSI_PREOPT_EXPECTEDSIZE=628000
REVERSI_PREOPT_EXPECTEDSIZE=629000
REVERSI_OPT_EXPECTEDSIZE=147000
REVERSI_PREOPT_GZ_EXPECTEDSIZE=77000
REVERSI_OPT_GZ_EXPECTEDSIZE=33000
Expand Down
59 changes: 41 additions & 18 deletions compiler/src/main/scala/org/scalajs/core/compiler/GenJSCode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1395,7 +1395,7 @@ abstract class GenJSCode extends plugins.PluginComponent

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

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

val methodDefWithoutUselessVars = {
val unmutatedMutableLocalVars =
(mutableLocalVars -- mutatedLocalVars).toList
(mutableLocalVars.diff(mutatedLocalVars)).toList
val mutatedImmutableLocalVals =
(mutatedLocalVars -- mutableLocalVars).toList
(mutatedLocalVars.diff(mutableLocalVars)).toList
if (unmutatedMutableLocalVars.isEmpty &&
mutatedImmutableLocalVals.isEmpty) {
// OK, we're good (common case)
Expand Down Expand Up @@ -4643,10 +4643,12 @@ abstract class GenJSCode extends plugins.PluginComponent
}

/** Gen actual actual arguments to Scala method call.
*
* Returns a list of the transformed arguments.
*
* This tries to optimize repeated arguments (varargs) by turning them
* into js.WrappedArray instead of Scala wrapped arrays.
* into JS arrays wrapped in the appropriate Seq, rather than Scala
* arrays.
*/
private def genActualArgs(sym: Symbol, args: List[Tree])(
implicit pos: Position): List[js.Tree] = {
Expand All @@ -4671,8 +4673,7 @@ abstract class GenJSCode extends plugins.PluginComponent
tryGenRepeatedParamAsJSArray(arg, handleNil = false).fold {
genExpr(arg)
} { genArgs =>
genNew(WrappedArrayClass, WrappedArray_ctor,
List(js.JSArrayConstr(genArgs)))
genJSArrayToVarArgs(js.JSArrayConstr(genArgs))
}
} else {
genExpr(arg)
Expand Down Expand Up @@ -4829,18 +4830,25 @@ abstract class GenJSCode extends plugins.PluginComponent
}

object WrapArray {
lazy val isWrapArray: Set[Symbol] = Seq(
nme.wrapRefArray,
nme.wrapByteArray,
nme.wrapShortArray,
nme.wrapCharArray,
nme.wrapIntArray,
nme.wrapLongArray,
nme.wrapFloatArray,
nme.wrapDoubleArray,
nme.wrapBooleanArray,
nme.wrapUnitArray,
nme.genericWrapArray).map(getMemberMethod(PredefModule, _)).toSet
private val isWrapArray: Set[Symbol] = {
val wrapArrayModule =
if (hasNewCollections) ScalaRunTimeModule
else PredefModule

Seq(
nme.wrapRefArray,
nme.wrapByteArray,
nme.wrapShortArray,
nme.wrapCharArray,
nme.wrapIntArray,
nme.wrapLongArray,
nme.wrapFloatArray,
nme.wrapDoubleArray,
nme.wrapBooleanArray,
nme.wrapUnitArray,
nme.genericWrapArray
).map(getMemberMethod(wrapArrayModule, _)).toSet
}

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

/** Wraps a `js.Array` to use as varargs. */
def genJSArrayToVarArgs(arrayRef: js.Tree)(
implicit pos: Position): js.Tree = {
genApplyMethod(genLoadModule(RuntimePackageModule),
Runtime_toScalaVarArgs, List(arrayRef))
}

// Synthesizers for raw JS functions ---------------------------------------

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

private lazy val hasNewCollections = {
val v = scala.util.Properties.versionNumberString
!v.startsWith("2.10.") &&
!v.startsWith("2.11.") &&
!v.startsWith("2.12.") &&
v != "2.13.0-M3"
}

/** Tests whether the given type represents a raw JavaScript type,
* i.e., whether it extends scala.scalajs.js.Any.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ trait GenJSExports extends SubComponent { self: GenJSCode =>

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

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

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,16 +126,14 @@ trait JSDefinitions { self: JSGlobalAddons =>
lazy val Runtime_unwrapJavaScriptException = getMemberMethod(RuntimePackageModule, newTermName("unwrapJavaScriptException"))
lazy val Runtime_jsObjectSuperGet = getMemberMethod(RuntimePackageModule, newTermName("jsObjectSuperGet"))
lazy val Runtime_jsObjectSuperSet = getMemberMethod(RuntimePackageModule, newTermName("jsObjectSuperSet"))
lazy val Runtime_toScalaVarArgs = getMemberMethod(RuntimePackageModule, newTermName("toScalaVarArgs"))
lazy val Runtime_genTraversableOnce2jsArray = getMemberMethod(RuntimePackageModule, newTermName("genTraversableOnce2jsArray"))
lazy val Runtime_jsTupleArray2jsObject = getMemberMethod(RuntimePackageModule, newTermName("jsTupleArray2jsObject"))
lazy val Runtime_constructorOf = getMemberMethod(RuntimePackageModule, newTermName("constructorOf"))
lazy val Runtime_newConstructorTag = getMemberMethod(RuntimePackageModule, newTermName("newConstructorTag"))
lazy val Runtime_propertiesOf = getMemberMethod(RuntimePackageModule, newTermName("propertiesOf"))
lazy val Runtime_linkingInfo = getMemberMethod(RuntimePackageModule, newTermName("linkingInfo"))

lazy val WrappedArrayClass = getRequiredClass("scala.scalajs.js.WrappedArray")
lazy val WrappedArray_ctor = WrappedArrayClass.primaryConstructor

// This is a def, since similar symbols (arrayUpdateMethod, etc.) are in runDefinitions
// (rather than definitions) and we weren't sure if it is safe to make this a lazy val
def ScalaRunTime_isArray: Symbol = getMemberMethod(ScalaRunTimeModule, newTermName("isArray")).suchThat(_.tpe.params.size == 2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -641,8 +641,8 @@ trait PrepJSExports { this: PrepJSInterop =>
def ph = Ident(Predef_???)

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

Expand Down Expand Up @@ -687,8 +687,8 @@ trait PrepJSExports { this: PrepJSInterop =>
}

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,18 @@ class JSExportTest extends DirectTest with TestHelpers {
@Test
def noOverrideNamedExport: Unit = {

val indent = {
val version = scala.util.Properties.versionNumberString
if (version.startsWith("2.10.") ||
version.startsWith("2.11.") ||
version.startsWith("2.12.") ||
version == "2.13.0-M3") {
" "
} else {
" "
}
}

"""
class A {
@JSExportNamed
Expand All @@ -840,7 +852,7 @@ class JSExportTest extends DirectTest with TestHelpers {
| @JSExportNamed
| ^
|newSource1.scala:9: error: overriding method $$js$$exported$$meth$$foo in class A of type (namedArgs: Any)Any;
| method $$js$$exported$$meth$$foo cannot override final member
|${indent}method $$js$$exported$$meth$$foo cannot override final member
| @JSExportNamed
| ^
|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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.junit.Test
import org.scalajs.core.ir.{Trees => js, Types => jstpe}

class OptimizationTest extends JSASTTest {
import OptimizationTest._

@Test
def unwrapScalaFunWrapper: Unit = {
Expand Down Expand Up @@ -55,8 +56,7 @@ class OptimizationTest extends JSASTTest {
}
""".
hasNot("any of the wrapArray methods") {
case js.Apply(_, js.Ident(name, _), _)
if name.startsWith("wrap") && name.endsWith("__scm_WrappedArray") =>
case WrapArrayCall() =>
}
}

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

/* #2265 and #2741:
Expand Down Expand Up @@ -108,21 +107,30 @@ class OptimizationTest extends JSASTTest {
}
""".
hasNot("any of the wrapArray methods") {
case js.Apply(_, js.Ident(name, _), _)
if name.startsWith("wrap") && name.endsWith("__scm_WrappedArray") =>
case WrapArrayCall() =>
}

// Make sure our wrapper matcher has the right name
"""
import scala.scalajs.js
class A {
val a: Seq[Int] = new Array[Int](5)
/* Make sure our wrapper matcher has the right name.
* With the new collections, only actual varargs will produce a call to the
* methods we optimize, and we would always be able to optimize them in
* that case. So we need to explicitly call the method that the codegen
* would use.
*/
val sanityCheckCode = if (hasOldCollections) {
"""
class A {
val a: Seq[Int] = new Array[Int](5)
}
"""
} else {
"""
class A {
runtime.ScalaRunTime.wrapIntArray(new Array[Int](5))
}
"""
}
""".
has("one of the wrapArray methods") {
case js.Apply(_, js.Ident(name, _), _)
if name.startsWith("wrap") && name.endsWith("__scm_WrappedArray") =>
sanityCheckCode.has("one of the wrapArray methods") {
case WrapArrayCall() =>
}
}

Expand Down Expand Up @@ -258,3 +266,27 @@ class OptimizationTest extends JSASTTest {
}

}

object OptimizationTest {

private val hasOldCollections = {
val version = scala.util.Properties.versionNumberString

version.startsWith("2.10.") ||
version.startsWith("2.11.") ||
version.startsWith("2.12.") ||
version == "2.13.0-M3"
}

private object WrapArrayCall {
private val Suffix =
if (hasOldCollections) "__scm_WrappedArray"
else "__sci_ImmutableArray"

def unapply(tree: js.Apply): Boolean = {
val methodName = tree.method.name
methodName.startsWith("wrap") && methodName.endsWith(Suffix)
}
}

}
2 changes: 1 addition & 1 deletion javalib/src/main/scala/java/util/ArrayList.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class ArrayList[E] private (private[ArrayList] val inner: js.Array[E])
override def addAll(index: Int, c: Collection[_ <: E]): Boolean = {
c match {
case other: ArrayList[_] =>
inner.splice(index, 0, other.inner: _*)
inner.splice(index, 0, other.inner.toSeq: _*)
other.size > 0
case _ => super.addAll(index, c)
}
Expand Down
2 changes: 1 addition & 1 deletion javalib/src/main/scala/java/util/Collections.scala
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ object Collections {
}

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

def newSetFromMap[E](map: Map[E, java.lang.Boolean]): Set[E] = {
if (!map.isEmpty)
Expand Down
47 changes: 47 additions & 0 deletions javalib/src/main/scala/java/util/Compat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package java.util

import scala.collection.mutable

/** Make some Scala 2.13 APIs available in older Scala versions. */
private[util] object Compat {

/** Adds methods from 2.13 to `SortedSet`.
*
* The `to` operation has been renamed to `rangeTo` in 2.13, to not
* conflict with the `to` operation in `Iterable`.
*/
implicit class SortedSetCompat[A](val __private_self: mutable.SortedSet[A])
extends AnyVal {

@inline private def self: mutable.SortedSet[A] = __private_self

/* Note: the double implicit conversion trick does not work here because
* there *is* a `to` method in 2.13 (but it takes a `Factory` as parameter)
* so the second implicit conversion is never triggered.
*/
def rangeTo(to: A): mutable.SortedSet[A] = {
// Implementation copied from 2.12's implementation
val i = self.rangeFrom(to).iterator
if (i.isEmpty) {
self
} else {
val next = i.next()
if (self.ordering.compare(next, to) == 0) {
if (i.isEmpty) self
else self.rangeUntil(i.next())
} else {
self.rangeUntil(next)
}
}
}

/* Note: the double implicit conversion trick does not work here either
* because the `from` and `until` methods still exist on 2.13 but they
* are deprecated.
*/
def rangeFrom(a: A): mutable.SortedSet[A] = self.rangeImpl(Some(a), None)
def rangeUntil(a: A): mutable.SortedSet[A] = self.rangeImpl(None, Some(a))

}

}
Loading

0 comments on commit 0012d82

Please sign in to comment.