Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade to Scala.js 1.16.0. #20294

Merged
merged 5 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 55 additions & 29 deletions compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -927,7 +927,7 @@ class JSCodeGen()(using genCtx: Context) {
val className = encodeClassName(classSym)
val body = js.Block(
js.LoadModule(className),
js.SelectStatic(className, fieldIdent)(irTpe))
js.SelectStatic(fieldIdent)(irTpe))
staticGetterDefs += js.MethodDef(
js.MemberFlags.empty.withNamespace(js.MemberNamespace.PublicStatic),
encodeStaticMemberSym(f), originalName, Nil, irTpe,
Expand Down Expand Up @@ -1146,42 +1146,72 @@ class JSCodeGen()(using genCtx: Context) {

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

var preSuperStats = List.newBuilder[js.Tree]
var jsSuperCall: Option[js.JSSuperConstructorCall] = None
val jsStats = List.newBuilder[js.Tree]
val postSuperStats = List.newBuilder[js.Tree]

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

case stat =>
val jsStat = genStat(stat)
assert(jsSuperCall.isDefined || !jsStat.isInstanceOf[js.VarDef],
"Trying to move a local VarDef after the super constructor call of a non-native JS class at " +
dd.sourcePos)
jsStats += jsStat
def rec(tree: Tree): Unit = {
tree match {
case Block(stats, expr) =>
stats.foreach(rec(_))
rec(expr)

case tree @ Apply(fun @ Select(Super(This(_), _), _), args)
if fun.symbol.isClassConstructor =>
assert(jsSuperCall.isEmpty, s"Found 2 JS Super calls at ${dd.sourcePos}")
implicit val pos: Position = tree.span
jsSuperCall = Some(js.JSSuperConstructorCall(genActualJSArgs(fun.symbol, args)))

case tree if jsSuperCall.isDefined =>
// Once we're past the super constructor call, everything goes after.
postSuperStats += genStat(tree)

case Assign(lhs, Ident(_)) if isThisField(lhs) =>
/* If that shape appears before the jsSuperCall, it is a param
* accessor initializer. We move it.
*/
postSuperStats += genStat(tree)

case stat =>
// Other statements are left before.
preSuperStats += genStat(stat)
}
}

rec(dd.rhs)
}

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

new PrimaryJSCtor(sym, genParamsAndInfo(sym, dd.paramss),
js.JSConstructorBody(Nil, jsSuperCall.get, jsStats.result())(dd.span))
js.JSConstructorBody(preSuperStats.result(), jsSuperCall.get, postSuperStats.result())(dd.span))
}

private def genSecondaryJSClassCtor(dd: DefDef): SplitSecondaryJSCtor = {
Expand Down Expand Up @@ -2213,10 +2243,7 @@ class JSCodeGen()(using genCtx: Context) {
if (isStaticModule(currentClassSym) && !isModuleInitialized.get.value &&
currentMethodSym.get.isClassConstructor) {
isModuleInitialized.get.value = true
val className = encodeClassName(currentClassSym)
val thisType = jstpe.ClassType(className)
val initModule = js.StoreModule(className, js.This()(thisType))
js.Block(superCall, initModule)
js.Block(superCall, js.StoreModule())
} else {
superCall
}
Expand Down Expand Up @@ -4433,13 +4460,12 @@ class JSCodeGen()(using genCtx: Context) {
js.JSSelect(qual, genPrivateFieldsSymbol()),
encodeFieldSymAsStringLiteral(sym))
} else {
js.JSPrivateSelect(qual, encodeClassName(sym.owner),
encodeFieldSym(sym))
js.JSPrivateSelect(qual, encodeFieldSym(sym))
}

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

val f =
if sym.is(JavaStatic) then
js.SelectStatic(className, fieldIdent)(irType)
js.SelectStatic(fieldIdent)(irType)
else
js.Select(qual, className, fieldIdent)(irType)
js.Select(qual, fieldIdent)(irType)

(f, boxed)
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/backend/sjs/JSEncoding.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import dotty.tools.dotc.transform.sjs.JSSymUtils.*

import org.scalajs.ir
import org.scalajs.ir.{Trees => js, Types => jstpe}
import org.scalajs.ir.Names.{LocalName, LabelName, FieldName, SimpleMethodName, MethodName, ClassName}
import org.scalajs.ir.Names.{LocalName, LabelName, SimpleFieldName, FieldName, SimpleMethodName, MethodName, ClassName}
import org.scalajs.ir.OriginalName
import org.scalajs.ir.OriginalName.NoOriginalName
import org.scalajs.ir.UTF8String
Expand Down Expand Up @@ -173,7 +173,7 @@ object JSEncoding {
}

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

def encodeFieldSymAsStringLiteral(sym: Symbol)(implicit ctx: Context, pos: ir.Position): js.StringLiteral =
js.StringLiteral(encodeFieldSymAsString(sym))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,11 @@ class ExplicitJSClasses extends MiniPhase with InfoTransformer { thisPhase =>
private def maybeWrapSuperCallWithContextualJSClassValue(tree: Tree)(using Context): Tree = {
methPart(tree) match {
case Select(sup: Super, _) if isInnerOrLocalJSClass(sup.symbol.asClass.superClass) =>
wrapWithContextualJSClassValue(sup.symbol.asClass.superClass.typeRef)(tree)
val superClass = sup.symbol.asClass.superClass
val jsClassTypeInSuperClass = superClass.typeRef
// scala-js#4801 Rebase the super class type on the current class' this type
val jsClassTypeAsSeenFromThis = jsClassTypeInSuperClass.asSeenFrom(currentClass.thisType, superClass)
wrapWithContextualJSClassValue(jsClassTypeAsSeenFromThis)(tree)
case _ =>
tree
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/test/dotty/Properties.scala
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ object Properties {
/** scalajs-javalib jar */
def scalaJSJavalib: String = sys.props("dotty.tests.classes.scalaJSJavalib")

/** scalajs-scalalib jar */
def scalaJSScalalib: String = sys.props("dotty.tests.classes.scalaJSScalalib")

/** scalajs-library jar */
def scalaJSLibrary: String = sys.props("dotty.tests.classes.scalaJSLibrary")
}
1 change: 1 addition & 0 deletions compiler/test/dotty/tools/vulpix/TestConfiguration.scala
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ object TestConfiguration {

lazy val scalaJSClasspath = mkClasspath(List(
Properties.scalaJSJavalib,
Properties.scalaJSScalalib,
Properties.scalaJSLibrary,
Properties.dottyLibraryJS
))
Expand Down
5 changes: 4 additions & 1 deletion project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1508,7 +1508,8 @@ object Build {
"isNoModule" -> (moduleKind == ModuleKind.NoModule),
"isESModule" -> (moduleKind == ModuleKind.ESModule),
"isCommonJSModule" -> (moduleKind == ModuleKind.CommonJSModule),
"isFullOpt" -> (stage == FullOptStage),
"usesClosureCompiler" -> linkerConfig.closureCompiler,
"hasMinifiedNames" -> (linkerConfig.closureCompiler || linkerConfig.minify),
"compliantAsInstanceOfs" -> (sems.asInstanceOfs == CheckedBehavior.Compliant),
"compliantArrayIndexOutOfBounds" -> (sems.arrayIndexOutOfBounds == CheckedBehavior.Compliant),
"compliantArrayStores" -> (sems.arrayStores == CheckedBehavior.Compliant),
Expand Down Expand Up @@ -1581,6 +1582,7 @@ object Build {
-- "ReflectiveCallTest.scala" // uses many forms of structural calls that are not allowed in Scala 3 anymore
-- "UTF16Test.scala" // refutable pattern match
-- "CharsetTest.scala" // bogus @tailrec that Scala 2 ignores but Scala 3 flags as an error
-- "ClassDiffersOnlyInCaseTest.scala" // looks like the Scala 3 compiler itself does not deal with that
)).get

++ (dir / "shared/src/test/require-sam" ** "*.scala").get
Expand Down Expand Up @@ -1649,6 +1651,7 @@ object Build {
Seq(
"-Ddotty.tests.classes.dottyLibraryJS=" + dottyLibraryJSJar,
"-Ddotty.tests.classes.scalaJSJavalib=" + findArtifactPath(externalJSDeps, "scalajs-javalib"),
"-Ddotty.tests.classes.scalaJSScalalib=" + findArtifactPath(externalJSDeps, "scalajs-scalalib_2.13"),
"-Ddotty.tests.classes.scalaJSLibrary=" + findArtifactPath(externalJSDeps, "scalajs-library_2.13"),
)
},
Expand Down
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
libraryDependencySchemes +=
"org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always

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

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

Expand Down
Loading