Skip to content

Commit 827df03

Browse files
authored
Upgrade to Scala.js 1.16.0. (#20294)
The commit messages mention the upstream commits that were forward ported. Tests come for free in the "Upgrade to Scala.js 1.x.0." commits.
2 parents 1a103c0 + 8ebef0f commit 827df03

File tree

7 files changed

+71
-34
lines changed

7 files changed

+71
-34
lines changed

compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala

Lines changed: 55 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -927,7 +927,7 @@ class JSCodeGen()(using genCtx: Context) {
927927
val className = encodeClassName(classSym)
928928
val body = js.Block(
929929
js.LoadModule(className),
930-
js.SelectStatic(className, fieldIdent)(irTpe))
930+
js.SelectStatic(fieldIdent)(irTpe))
931931
staticGetterDefs += js.MethodDef(
932932
js.MemberFlags.empty.withNamespace(js.MemberNamespace.PublicStatic),
933933
encodeStaticMemberSym(f), originalName, Nil, irTpe,
@@ -1146,42 +1146,72 @@ class JSCodeGen()(using genCtx: Context) {
11461146

11471147
private def genPrimaryJSClassCtor(dd: DefDef): PrimaryJSCtor = {
11481148
val sym = dd.symbol
1149-
val Block(stats, _) = dd.rhs: @unchecked
11501149
assert(sym.isPrimaryConstructor, s"called with non-primary ctor: $sym")
11511150

1151+
var preSuperStats = List.newBuilder[js.Tree]
11521152
var jsSuperCall: Option[js.JSSuperConstructorCall] = None
1153-
val jsStats = List.newBuilder[js.Tree]
1153+
val postSuperStats = List.newBuilder[js.Tree]
11541154

1155-
/* Move all statements after the super constructor call since JS
1156-
* cannot access `this` before the super constructor call.
1155+
/* Move param accessor initializers after the super constructor call since
1156+
* JS cannot access `this` before the super constructor call.
11571157
*
11581158
* dotc inserts statements before the super constructor call for param
11591159
* accessor initializers (including val's and var's declared in the
1160-
* params). We move those after the super constructor call, and are
1161-
* therefore executed later than for a Scala class.
1160+
* params). Those statements are assignments whose rhs'es are always simple
1161+
* Idents (the constructor params).
1162+
*
1163+
* There can also be local `val`s before the super constructor call for
1164+
* default arguments to the super constructor. These must remain before.
1165+
*
1166+
* Our strategy is therefore to move only the field assignments after the
1167+
* super constructor call. They are therefore executed later than for a
1168+
* Scala class (as specified for non-native JS classes semantics).
1169+
* However, side effects and evaluation order of all the other
1170+
* computations remains unchanged.
11621171
*/
11631172
withPerMethodBodyState(sym) {
1164-
stats.foreach {
1165-
case tree @ Apply(fun @ Select(Super(This(_), _), _), args)
1166-
if fun.symbol.isClassConstructor =>
1167-
assert(jsSuperCall.isEmpty, s"Found 2 JS Super calls at ${dd.sourcePos}")
1168-
implicit val pos: Position = tree.span
1169-
jsSuperCall = Some(js.JSSuperConstructorCall(genActualJSArgs(fun.symbol, args)))
1173+
def isThisField(tree: Tree): Boolean = tree match {
1174+
case Select(ths: This, _) => ths.symbol == currentClassSym.get
1175+
case tree: Ident => desugarIdent(tree).exists(isThisField(_))
1176+
case _ => false
1177+
}
11701178

1171-
case stat =>
1172-
val jsStat = genStat(stat)
1173-
assert(jsSuperCall.isDefined || !jsStat.isInstanceOf[js.VarDef],
1174-
"Trying to move a local VarDef after the super constructor call of a non-native JS class at " +
1175-
dd.sourcePos)
1176-
jsStats += jsStat
1179+
def rec(tree: Tree): Unit = {
1180+
tree match {
1181+
case Block(stats, expr) =>
1182+
stats.foreach(rec(_))
1183+
rec(expr)
1184+
1185+
case tree @ Apply(fun @ Select(Super(This(_), _), _), args)
1186+
if fun.symbol.isClassConstructor =>
1187+
assert(jsSuperCall.isEmpty, s"Found 2 JS Super calls at ${dd.sourcePos}")
1188+
implicit val pos: Position = tree.span
1189+
jsSuperCall = Some(js.JSSuperConstructorCall(genActualJSArgs(fun.symbol, args)))
1190+
1191+
case tree if jsSuperCall.isDefined =>
1192+
// Once we're past the super constructor call, everything goes after.
1193+
postSuperStats += genStat(tree)
1194+
1195+
case Assign(lhs, Ident(_)) if isThisField(lhs) =>
1196+
/* If that shape appears before the jsSuperCall, it is a param
1197+
* accessor initializer. We move it.
1198+
*/
1199+
postSuperStats += genStat(tree)
1200+
1201+
case stat =>
1202+
// Other statements are left before.
1203+
preSuperStats += genStat(stat)
1204+
}
11771205
}
1206+
1207+
rec(dd.rhs)
11781208
}
11791209

11801210
assert(jsSuperCall.isDefined,
11811211
s"Did not find Super call in primary JS construtor at ${dd.sourcePos}")
11821212

11831213
new PrimaryJSCtor(sym, genParamsAndInfo(sym, dd.paramss),
1184-
js.JSConstructorBody(Nil, jsSuperCall.get, jsStats.result())(dd.span))
1214+
js.JSConstructorBody(preSuperStats.result(), jsSuperCall.get, postSuperStats.result())(dd.span))
11851215
}
11861216

11871217
private def genSecondaryJSClassCtor(dd: DefDef): SplitSecondaryJSCtor = {
@@ -2213,10 +2243,7 @@ class JSCodeGen()(using genCtx: Context) {
22132243
if (isStaticModule(currentClassSym) && !isModuleInitialized.get.value &&
22142244
currentMethodSym.get.isClassConstructor) {
22152245
isModuleInitialized.get.value = true
2216-
val className = encodeClassName(currentClassSym)
2217-
val thisType = jstpe.ClassType(className)
2218-
val initModule = js.StoreModule(className, js.This()(thisType))
2219-
js.Block(superCall, initModule)
2246+
js.Block(superCall, js.StoreModule())
22202247
} else {
22212248
superCall
22222249
}
@@ -4433,13 +4460,12 @@ class JSCodeGen()(using genCtx: Context) {
44334460
js.JSSelect(qual, genPrivateFieldsSymbol()),
44344461
encodeFieldSymAsStringLiteral(sym))
44354462
} else {
4436-
js.JSPrivateSelect(qual, encodeClassName(sym.owner),
4437-
encodeFieldSym(sym))
4463+
js.JSPrivateSelect(qual, encodeFieldSym(sym))
44384464
}
44394465

44404466
(f, true)
44414467
} else if (sym.hasAnnotation(jsdefn.JSExportTopLevelAnnot)) {
4442-
val f = js.SelectStatic(encodeClassName(sym.owner), encodeFieldSym(sym))(jstpe.AnyType)
4468+
val f = js.SelectStatic(encodeFieldSym(sym))(jstpe.AnyType)
44434469
(f, true)
44444470
} else if (sym.hasAnnotation(jsdefn.JSExportStaticAnnot)) {
44454471
val jsName = sym.getAnnotation(jsdefn.JSExportStaticAnnot).get.argumentConstantString(0).getOrElse {
@@ -4465,9 +4491,9 @@ class JSCodeGen()(using genCtx: Context) {
44654491

44664492
val f =
44674493
if sym.is(JavaStatic) then
4468-
js.SelectStatic(className, fieldIdent)(irType)
4494+
js.SelectStatic(fieldIdent)(irType)
44694495
else
4470-
js.Select(qual, className, fieldIdent)(irType)
4496+
js.Select(qual, fieldIdent)(irType)
44714497

44724498
(f, boxed)
44734499
}

compiler/src/dotty/tools/backend/sjs/JSEncoding.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import dotty.tools.dotc.transform.sjs.JSSymUtils.*
1717

1818
import org.scalajs.ir
1919
import org.scalajs.ir.{Trees => js, Types => jstpe}
20-
import org.scalajs.ir.Names.{LocalName, LabelName, FieldName, SimpleMethodName, MethodName, ClassName}
20+
import org.scalajs.ir.Names.{LocalName, LabelName, SimpleFieldName, FieldName, SimpleMethodName, MethodName, ClassName}
2121
import org.scalajs.ir.OriginalName
2222
import org.scalajs.ir.OriginalName.NoOriginalName
2323
import org.scalajs.ir.UTF8String
@@ -173,7 +173,7 @@ object JSEncoding {
173173
}
174174

175175
def encodeFieldSym(sym: Symbol)(implicit ctx: Context, pos: ir.Position): js.FieldIdent =
176-
js.FieldIdent(FieldName(encodeFieldSymAsString(sym)))
176+
js.FieldIdent(FieldName(encodeClassName(sym.owner), SimpleFieldName(encodeFieldSymAsString(sym))))
177177

178178
def encodeFieldSymAsStringLiteral(sym: Symbol)(implicit ctx: Context, pos: ir.Position): js.StringLiteral =
179179
js.StringLiteral(encodeFieldSymAsString(sym))

compiler/src/dotty/tools/dotc/transform/sjs/ExplicitJSClasses.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,11 @@ class ExplicitJSClasses extends MiniPhase with InfoTransformer { thisPhase =>
637637
private def maybeWrapSuperCallWithContextualJSClassValue(tree: Tree)(using Context): Tree = {
638638
methPart(tree) match {
639639
case Select(sup: Super, _) if isInnerOrLocalJSClass(sup.symbol.asClass.superClass) =>
640-
wrapWithContextualJSClassValue(sup.symbol.asClass.superClass.typeRef)(tree)
640+
val superClass = sup.symbol.asClass.superClass
641+
val jsClassTypeInSuperClass = superClass.typeRef
642+
// scala-js#4801 Rebase the super class type on the current class' this type
643+
val jsClassTypeAsSeenFromThis = jsClassTypeInSuperClass.asSeenFrom(currentClass.thisType, superClass)
644+
wrapWithContextualJSClassValue(jsClassTypeAsSeenFromThis)(tree)
641645
case _ =>
642646
tree
643647
}

compiler/test/dotty/Properties.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ object Properties {
103103
/** scalajs-javalib jar */
104104
def scalaJSJavalib: String = sys.props("dotty.tests.classes.scalaJSJavalib")
105105

106+
/** scalajs-scalalib jar */
107+
def scalaJSScalalib: String = sys.props("dotty.tests.classes.scalaJSScalalib")
108+
106109
/** scalajs-library jar */
107110
def scalaJSLibrary: String = sys.props("dotty.tests.classes.scalaJSLibrary")
108111
}

compiler/test/dotty/tools/vulpix/TestConfiguration.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ object TestConfiguration {
5252

5353
lazy val scalaJSClasspath = mkClasspath(List(
5454
Properties.scalaJSJavalib,
55+
Properties.scalaJSScalalib,
5556
Properties.scalaJSLibrary,
5657
Properties.dottyLibraryJS
5758
))

project/Build.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1507,7 +1507,8 @@ object Build {
15071507
"isNoModule" -> (moduleKind == ModuleKind.NoModule),
15081508
"isESModule" -> (moduleKind == ModuleKind.ESModule),
15091509
"isCommonJSModule" -> (moduleKind == ModuleKind.CommonJSModule),
1510-
"isFullOpt" -> (stage == FullOptStage),
1510+
"usesClosureCompiler" -> linkerConfig.closureCompiler,
1511+
"hasMinifiedNames" -> (linkerConfig.closureCompiler || linkerConfig.minify),
15111512
"compliantAsInstanceOfs" -> (sems.asInstanceOfs == CheckedBehavior.Compliant),
15121513
"compliantArrayIndexOutOfBounds" -> (sems.arrayIndexOutOfBounds == CheckedBehavior.Compliant),
15131514
"compliantArrayStores" -> (sems.arrayStores == CheckedBehavior.Compliant),
@@ -1580,6 +1581,7 @@ object Build {
15801581
-- "ReflectiveCallTest.scala" // uses many forms of structural calls that are not allowed in Scala 3 anymore
15811582
-- "UTF16Test.scala" // refutable pattern match
15821583
-- "CharsetTest.scala" // bogus @tailrec that Scala 2 ignores but Scala 3 flags as an error
1584+
-- "ClassDiffersOnlyInCaseTest.scala" // looks like the Scala 3 compiler itself does not deal with that
15831585
)).get
15841586

15851587
++ (dir / "shared/src/test/require-sam" ** "*.scala").get
@@ -1648,6 +1650,7 @@ object Build {
16481650
Seq(
16491651
"-Ddotty.tests.classes.dottyLibraryJS=" + dottyLibraryJSJar,
16501652
"-Ddotty.tests.classes.scalaJSJavalib=" + findArtifactPath(externalJSDeps, "scalajs-javalib"),
1653+
"-Ddotty.tests.classes.scalaJSScalalib=" + findArtifactPath(externalJSDeps, "scalajs-scalalib_2.13"),
16511654
"-Ddotty.tests.classes.scalaJSLibrary=" + findArtifactPath(externalJSDeps, "scalajs-library_2.13"),
16521655
)
16531656
},

project/plugins.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
libraryDependencySchemes +=
77
"org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always
88

9-
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.13.0")
9+
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0")
1010

1111
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.21")
1212

0 commit comments

Comments
 (0)