Skip to content

Upgrade to Scala.js 1.11.0 then 1.12.0. #16411

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

Merged
merged 2 commits into from
Nov 28, 2022
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
201 changes: 133 additions & 68 deletions compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,14 @@ class JSCodeGen()(using genCtx: Context) {
/** Implicitly materializes the current local name generator. */
implicit def implicitLocalNames: LocalNameGenerator = localNames.get

private def currentClassType = encodeClassType(currentClassSym)
def currentThisType: jstpe.Type = {
encodeClassType(currentClassSym) match {
case tpe @ jstpe.ClassType(cls) =>
jstpe.BoxedClassToPrimType.getOrElse(cls, tpe)
case tpe =>
tpe
}
}

/** Returns a new fresh local identifier. */
private def freshLocalIdent()(implicit pos: Position): js.LocalIdent =
Expand Down Expand Up @@ -1023,7 +1030,7 @@ class JSCodeGen()(using genCtx: Context) {
// Constructor of a non-native JS class ------------------------------------

def genJSClassCapturesAndConstructor(constructorTrees: List[DefDef])(
implicit pos: SourcePosition): (List[js.ParamDef], js.JSMethodDef) = {
implicit pos: SourcePosition): (List[js.ParamDef], js.JSConstructorDef) = {
/* We need to merge all Scala constructors into a single one because the
* IR, like JavaScript, only allows a single one.
*
Expand Down Expand Up @@ -1095,20 +1102,21 @@ class JSCodeGen()(using genCtx: Context) {
(exports.result(), jsClassCaptures.result())
}

// The name 'constructor' is used for error reporting here
val (formalArgs, restParam, overloadDispatchBody) =
jsExportsGen.genOverloadDispatch(JSName.Literal("constructor"), exports, jstpe.IntType)

val overloadVar = js.VarDef(freshLocalIdent("overload"), NoOriginalName,
jstpe.IntType, mutable = false, overloadDispatchBody)

val ctorStats = genJSClassCtorStats(overloadVar.ref, ctorTree)

val constructorBody = js.Block(
paramVarDefs ::: List(overloadVar, ctorStats, js.Undefined()))
val constructorBody = wrapJSCtorBody(
paramVarDefs :+ overloadVar,
genJSClassCtorBody(overloadVar.ref, ctorTree),
js.Undefined() :: Nil
)

val constructorDef = js.JSMethodDef(
js.MemberFlags.empty,
js.StringLiteral("constructor"),
val constructorDef = js.JSConstructorDef(
js.MemberFlags.empty.withNamespace(js.MemberNamespace.Constructor),
formalArgs, restParam, constructorBody)(OptimizerHints.empty, None)

(jsClassCaptures, constructorDef)
Expand Down Expand Up @@ -1150,7 +1158,8 @@ class JSCodeGen()(using genCtx: Context) {
assert(jsSuperCall.isDefined,
s"Did not find Super call in primary JS construtor at ${dd.sourcePos}")

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

private def genSecondaryJSClassCtor(dd: DefDef): SplitSecondaryJSCtor = {
Expand Down Expand Up @@ -1251,9 +1260,9 @@ class JSCodeGen()(using genCtx: Context) {
(jsExport, jsClassCaptures)
}

/** generates a sequence of JS constructor statements based on a constructor tree. */
private def genJSClassCtorStats(overloadVar: js.VarRef,
ctorTree: ConstructorTree[PrimaryJSCtor])(implicit pos: Position): js.Tree = {
/** Generates a JS constructor body based on a constructor tree. */
private def genJSClassCtorBody(overloadVar: js.VarRef,
ctorTree: ConstructorTree[PrimaryJSCtor])(implicit pos: Position): js.JSConstructorBody = {

/* generates a statement that conditionally executes body iff the chosen
* overload is any of the descendants of `tree` (including itself).
Expand Down Expand Up @@ -1348,21 +1357,27 @@ class JSCodeGen()(using genCtx: Context) {
val primaryCtor = ctorTree.ctor
val secondaryCtorTrees = ctorTree.subCtors

js.Block(
secondaryCtorTrees.map(preStats(_, primaryCtor.paramsAndInfo)) ++
primaryCtor.body ++
wrapJSCtorBody(
secondaryCtorTrees.map(preStats(_, primaryCtor.paramsAndInfo)),
primaryCtor.body,
secondaryCtorTrees.map(postStats(_))
)
}

private def wrapJSCtorBody(before: List[js.Tree], body: js.JSConstructorBody,
after: List[js.Tree]): js.JSConstructorBody = {
js.JSConstructorBody(before ::: body.beforeSuper, body.superCall,
body.afterSuper ::: after)(body.pos)
}

private sealed trait JSCtor {
val sym: Symbol
val paramsAndInfo: List[(Symbol, JSParamInfo)]
}

private class PrimaryJSCtor(val sym: Symbol,
val paramsAndInfo: List[(Symbol, JSParamInfo)],
val body: List[js.Tree]) extends JSCtor
val body: js.JSConstructorBody) extends JSCtor

private class SplitSecondaryJSCtor(val sym: Symbol,
val paramsAndInfo: List[(Symbol, JSParamInfo)],
Expand Down Expand Up @@ -1945,9 +1960,9 @@ class JSCodeGen()(using genCtx: Context) {
}*/

thisLocalVarIdent.fold[js.Tree] {
js.This()(currentClassType)
js.This()(currentThisType)
} { thisLocalIdent =>
js.VarRef(thisLocalIdent)(currentClassType)
js.VarRef(thisLocalIdent)(currentThisType)
}
}

Expand Down Expand Up @@ -2014,9 +2029,7 @@ class JSCodeGen()(using genCtx: Context) {

val (exceptValDef, exceptVar) = if (mightCatchJavaScriptException) {
val valDef = js.VarDef(freshLocalIdent("e"), NoOriginalName,
encodeClassType(defn.ThrowableClass), mutable = false, {
genModuleApplyMethod(jsdefn.Runtime_wrapJavaScriptException, origExceptVar :: Nil)
})
encodeClassType(defn.ThrowableClass), mutable = false, js.WrapAsThrowable(origExceptVar))
(valDef, valDef.ref)
} else {
(js.Skip(), origExceptVar)
Expand Down Expand Up @@ -2307,7 +2320,7 @@ class JSCodeGen()(using genCtx: Context) {
val privateFieldDefs = mutable.ListBuffer.empty[js.FieldDef]
val classDefMembers = mutable.ListBuffer.empty[js.MemberDef]
val instanceMembers = mutable.ListBuffer.empty[js.MemberDef]
var constructor: Option[js.JSMethodDef] = None
var constructor: Option[js.JSConstructorDef] = None

originalClassDef.memberDefs.foreach {
case fdef: js.FieldDef =>
Expand All @@ -2321,17 +2334,13 @@ class JSCodeGen()(using genCtx: Context) {
"Non-static, unexported method in non-native JS class")
classDefMembers += mdef

case mdef: js.JSMethodDef =>
mdef.name match {
case js.StringLiteral("constructor") =>
assert(!mdef.flags.namespace.isStatic, "Exported static method")
assert(constructor.isEmpty, "two ctors in class")
constructor = Some(mdef)
case cdef: js.JSConstructorDef =>
assert(constructor.isEmpty, "two ctors in class")
constructor = Some(cdef)

case _ =>
assert(!mdef.flags.namespace.isStatic, "Exported static method")
instanceMembers += mdef
}
case mdef: js.JSMethodDef =>
assert(!mdef.flags.namespace.isStatic, "Exported static method")
instanceMembers += mdef

case property: js.JSPropertyDef =>
instanceMembers += property
Expand Down Expand Up @@ -2361,7 +2370,7 @@ class JSCodeGen()(using genCtx: Context) {
val jsClassCaptures = originalClassDef.jsClassCaptures.getOrElse {
throw new AssertionError(s"no class captures for anonymous JS class at $pos")
}
val js.JSMethodDef(_, _, ctorParams, ctorRestParam, ctorBody) = constructor.getOrElse {
val js.JSConstructorDef(_, ctorParams, ctorRestParam, ctorBody) = constructor.getOrElse {
throw new AssertionError("No ctor found")
}
assert(ctorParams.isEmpty && ctorRestParam.isEmpty,
Expand Down Expand Up @@ -2396,6 +2405,9 @@ class JSCodeGen()(using genCtx: Context) {
case mdef: js.MethodDef =>
throw new AssertionError("unexpected MethodDef")

case cdef: js.JSConstructorDef =>
throw new AssertionError("unexpected JSConstructorDef")

case mdef: js.JSMethodDef =>
implicit val pos = mdef.pos
val impl = memberLambda(mdef.args, mdef.restParam, mdef.body)
Expand Down Expand Up @@ -2468,36 +2480,43 @@ class JSCodeGen()(using genCtx: Context) {
}

// Transform the constructor body.
val inlinedCtorStats = new ir.Transformers.Transformer {
override def transform(tree: js.Tree, isStat: Boolean): js.Tree = tree match {
// The super constructor call. Transform this into a simple new call.
case js.JSSuperConstructorCall(args) =>
implicit val pos = tree.pos

val newTree = {
val ident = originalClassDef.superClass.getOrElse(throw new FatalError("No superclass"))
if (args.isEmpty && ident.name == JSObjectClassName)
js.JSObjectConstr(Nil)
else
js.JSNew(jsSuperClassRef, args)
}

js.Block(
js.VarDef(selfName, thisOriginalName, jstpe.AnyType, mutable = false, newTree) ::
memberDefinitions)
val inlinedCtorStats: List[js.Tree] = {
val beforeSuper = ctorBody.beforeSuper

case js.This() =>
selfRef(tree.pos)
val superCall = {
implicit val pos = ctorBody.superCall.pos
val js.JSSuperConstructorCall(args) = ctorBody.superCall

// Don't traverse closure boundaries
case closure: js.Closure =>
val newCaptureValues = closure.captureValues.map(transformExpr)
closure.copy(captureValues = newCaptureValues)(closure.pos)
val newTree = {
val ident = originalClassDef.superClass.getOrElse(throw new FatalError("No superclass"))
if (args.isEmpty && ident.name == JSObjectClassName)
js.JSObjectConstr(Nil)
else
js.JSNew(jsSuperClassRef, args)
}

case tree =>
super.transform(tree, isStat)
val selfVarDef = js.VarDef(selfName, thisOriginalName, jstpe.AnyType, mutable = false, newTree)
selfVarDef :: memberDefinitions
}
}.transform(ctorBody, isStat = true)

// After the super call, substitute `selfRef` for `This()`
val afterSuper = new ir.Transformers.Transformer {
override def transform(tree: js.Tree, isStat: Boolean): js.Tree = tree match {
case js.This() =>
selfRef(tree.pos)

// Don't traverse closure boundaries
case closure: js.Closure =>
val newCaptureValues = closure.captureValues.map(transformExpr)
closure.copy(captureValues = newCaptureValues)(closure.pos)

case tree =>
super.transform(tree, isStat)
}
}.transformStats(ctorBody.afterSuper)

beforeSuper ::: superCall ::: afterSuper
}

val closure = js.Closure(arrow = true, jsClassCaptures, Nil, None,
js.Block(inlinedCtorStats, selfRef), jsSuperClassValue :: args)
Expand Down Expand Up @@ -2989,14 +3008,12 @@ class JSCodeGen()(using genCtx: Context) {
implicit val pos: SourcePosition = tree.sourcePos
val exception = args.head
val genException = genExpr(exception)
js.Throw {
if (exception.tpe.typeSymbol.derivesFrom(jsdefn.JavaScriptExceptionClass)) {
genModuleApplyMethod(
jsdefn.Runtime_unwrapJavaScriptException,
List(genException))
} else {
genException
}
genException match {
case js.New(cls, _, _) if cls != JavaScriptExceptionClassName =>
// Common case where ex is neither null nor a js.JavaScriptException
js.Throw(genException)
case _ =>
js.Throw(js.UnwrapFromThrowable(genException))
}
}

Expand Down Expand Up @@ -3982,6 +3999,53 @@ class JSCodeGen()(using genCtx: Context) {
js.JSFunctionApply(fVarDef.ref, List(keyVarRef))
}))

case JS_THROW =>
// js.special.throw(arg)
js.Throw(genArgs1)

case JS_TRY_CATCH =>
/* js.special.tryCatch(arg1, arg2)
*
* We must generate:
*
* val body = arg1
* val handler = arg2
* try {
* body()
* } catch (e) {
* handler(e)
* }
*
* with temporary vals, because `arg2` must be evaluated before
* `body` executes. Moreover, exceptions thrown while evaluating
* the function values `arg1` and `arg2` must not be caught.
*/
val (arg1, arg2) = genArgs2
val bodyVarDef = js.VarDef(freshLocalIdent("body"), NoOriginalName,
jstpe.AnyType, mutable = false, arg1)
val handlerVarDef = js.VarDef(freshLocalIdent("handler"), NoOriginalName,
jstpe.AnyType, mutable = false, arg2)
val exceptionVarIdent = freshLocalIdent("e")
val exceptionVarRef = js.VarRef(exceptionVarIdent)(jstpe.AnyType)
js.Block(
bodyVarDef,
handlerVarDef,
js.TryCatch(
js.JSFunctionApply(bodyVarDef.ref, Nil),
exceptionVarIdent,
NoOriginalName,
js.JSFunctionApply(handlerVarDef.ref, List(exceptionVarRef))
)(jstpe.AnyType)
)

case WRAP_AS_THROWABLE =>
// js.special.wrapAsThrowable(arg)
js.WrapAsThrowable(genArgs1)

case UNWRAP_FROM_THROWABLE =>
// js.special.unwrapFromThrowable(arg)
js.UnwrapFromThrowable(genArgs1)

case UNION_FROM | UNION_FROM_TYPE_CONSTRUCTOR =>
/* js.|.from and js.|.fromTypeConstructor
* We should not have to deal with those. They have a perfectly valid
Expand Down Expand Up @@ -4764,6 +4828,7 @@ object JSCodeGen {

private val NullPointerExceptionClass = ClassName("java.lang.NullPointerException")
private val JSObjectClassName = ClassName("scala.scalajs.js.Object")
private val JavaScriptExceptionClassName = ClassName("scala.scalajs.js.JavaScriptException")

private val ObjectClassRef = jstpe.ClassRef(ir.Names.ObjectClass)

Expand Down
12 changes: 8 additions & 4 deletions compiler/src/dotty/tools/backend/sjs/JSDefinitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,6 @@ final class JSDefinitions()(using Context) {

@threadUnsafe lazy val RuntimePackageVal = requiredPackage("scala.scalajs.runtime")
@threadUnsafe lazy val RuntimePackageClass = RuntimePackageVal.moduleClass.asClass
@threadUnsafe lazy val RuntimePackage_wrapJavaScriptExceptionR = RuntimePackageClass.requiredMethodRef("wrapJavaScriptException")
def Runtime_wrapJavaScriptException(using Context) = RuntimePackage_wrapJavaScriptExceptionR.symbol
@threadUnsafe lazy val Runtime_unwrapJavaScriptExceptionR = RuntimePackageClass.requiredMethodRef("unwrapJavaScriptException")
def Runtime_unwrapJavaScriptException(using Context) = Runtime_unwrapJavaScriptExceptionR.symbol
@threadUnsafe lazy val Runtime_toScalaVarArgsR = RuntimePackageClass.requiredMethodRef("toScalaVarArgs")
def Runtime_toScalaVarArgs(using Context) = Runtime_toScalaVarArgsR.symbol
@threadUnsafe lazy val Runtime_toJSVarArgsR = RuntimePackageClass.requiredMethodRef("toJSVarArgs")
Expand Down Expand Up @@ -206,6 +202,14 @@ final class JSDefinitions()(using Context) {
def Special_instanceof(using Context) = Special_instanceofR.symbol
@threadUnsafe lazy val Special_strictEqualsR = SpecialPackageClass.requiredMethodRef("strictEquals")
def Special_strictEquals(using Context) = Special_strictEqualsR.symbol
@threadUnsafe lazy val Special_throwR = SpecialPackageClass.requiredMethodRef("throw")
def Special_throw(using Context) = Special_throwR.symbol
@threadUnsafe lazy val Special_tryCatchR = SpecialPackageClass.requiredMethodRef("tryCatch")
def Special_tryCatch(using Context) = Special_tryCatchR.symbol
@threadUnsafe lazy val Special_wrapAsThrowableR = SpecialPackageClass.requiredMethodRef("wrapAsThrowable")
def Special_wrapAsThrowable(using Context) = Special_wrapAsThrowableR.symbol
@threadUnsafe lazy val Special_unwrapFromThrowableR = SpecialPackageClass.requiredMethodRef("unwrapFromThrowable")
def Special_unwrapFromThrowable(using Context) = Special_unwrapFromThrowableR.symbol

@threadUnsafe lazy val WrappedArrayType: TypeRef = requiredClassRef("scala.scalajs.js.WrappedArray")
def WrappedArrayClass(using Context) = WrappedArrayType.symbol.asClass
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/backend/sjs/JSExportsGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,7 @@ final class JSExportsGen(jsCodeGen: JSCodeGen)(using Context) {
js.LoadJSConstructor(encodeClassName(superClassSym))
}

val receiver = js.This()(jstpe.AnyType)
val receiver = js.This()(currentThisType)
val nameTree = genExpr(sym.jsName)

if (sym.isJSGetter) {
Expand Down Expand Up @@ -754,7 +754,7 @@ final class JSExportsGen(jsCodeGen: JSCodeGen)(using Context) {
genApplyMethodMaybeStatically(receiver, modAccessor, Nil)
}
} else {
js.This()(encodeClassType(targetSym))
js.This()(currentThisType)
}
}

Expand Down Expand Up @@ -811,7 +811,7 @@ final class JSExportsGen(jsCodeGen: JSCodeGen)(using Context) {

def receiver =
if (static) genLoadModule(sym.owner)
else js.This()(encodeClassType(currentClass))
else js.This()(currentThisType)

def boxIfNeeded(call: js.Tree): js.Tree =
box(call, atPhase(elimErasedValueTypePhase)(sym.info.resultType))
Expand Down
Loading