Skip to content

Commit 33aa948

Browse files
committed
Scala.js: Implement support for linkTimeIf.
This commit is a forward port of the compiler changes in scala-js/scala-js@5e842d8
1 parent 19b3b1e commit 33aa948

File tree

4 files changed

+109
-3
lines changed

4 files changed

+109
-3
lines changed

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

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4103,6 +4103,16 @@ class JSCodeGen()(using genCtx: Context) {
41034103
js.UnaryOp(js.UnaryOp.UnwrapFromThrowable,
41044104
js.UnaryOp(js.UnaryOp.CheckNotNull, genArgs1))
41054105

4106+
case LINKTIME_IF =>
4107+
// LinkingInfo.linkTimeIf(cond, thenp, elsep)
4108+
val cond = genLinkTimeExpr(args(0))
4109+
val thenp = genExpr(args(1))
4110+
val elsep = genExpr(args(2))
4111+
val tpe =
4112+
if (isStat) jstpe.VoidType
4113+
else toIRType(tree.tpe)
4114+
js.LinkTimeIf(cond, thenp, elsep)(tpe)
4115+
41064116
case UNION_FROM | UNION_FROM_TYPE_CONSTRUCTOR =>
41074117
/* js.|.from and js.|.fromTypeConstructor
41084118
* We should not have to deal with those. They have a perfectly valid
@@ -4128,6 +4138,91 @@ class JSCodeGen()(using genCtx: Context) {
41284138
}
41294139
}
41304140

4141+
private def genLinkTimeExpr(tree: Tree): js.Tree = {
4142+
import dotty.tools.backend.ScalaPrimitivesOps.*
4143+
4144+
import primitives.*
4145+
4146+
implicit val pos = tree.span
4147+
4148+
def invalid(): js.Tree = {
4149+
report.error(
4150+
"Illegal expression in the condition of a linkTimeIf. " +
4151+
"Valid expressions are: boolean and int primitives; " +
4152+
"references to link-time properties; " +
4153+
"primitive operations on booleans; " +
4154+
"and comparisons on ints.",
4155+
tree.sourcePos)
4156+
js.BooleanLiteral(false)
4157+
}
4158+
4159+
tree match {
4160+
case Literal(c) =>
4161+
import Constants.*
4162+
c.tag match {
4163+
case BooleanTag => js.BooleanLiteral(c.booleanValue)
4164+
case IntTag => js.IntLiteral(c.intValue)
4165+
case _ => invalid()
4166+
}
4167+
4168+
case Apply(fun, args) =>
4169+
fun.symbol.getAnnotation(jsdefn.LinkTimePropertyAnnot) match {
4170+
case Some(annotation) =>
4171+
val propName = annotation.argumentConstantString(0).get
4172+
js.LinkTimeProperty(propName)(toIRType(tree.tpe))
4173+
4174+
case None if isPrimitive(fun.symbol) =>
4175+
val code = getPrimitive(fun.symbol)
4176+
val receiver = (fun: @unchecked) match {
4177+
case fun: Select => fun.qualifier
4178+
case fun: Ident => desugarIdent(fun).get.qualifier
4179+
}
4180+
4181+
def genLhs: js.Tree = genLinkTimeExpr(receiver)
4182+
def genRhs: js.Tree = genLinkTimeExpr(args.head)
4183+
4184+
def unaryOp(op: js.UnaryOp.Code): js.Tree =
4185+
js.UnaryOp(op, genLhs)
4186+
def binaryOp(op: js.BinaryOp.Code): js.Tree =
4187+
js.BinaryOp(op, genLhs, genRhs)
4188+
4189+
toIRType(receiver.tpe) match {
4190+
case jstpe.BooleanType =>
4191+
(code: @switch) match {
4192+
case ZNOT => unaryOp(js.UnaryOp.Boolean_!)
4193+
case EQ => binaryOp(js.BinaryOp.Boolean_==)
4194+
case NE | XOR => binaryOp(js.BinaryOp.Boolean_!=)
4195+
case OR => binaryOp(js.BinaryOp.Boolean_|)
4196+
case AND => binaryOp(js.BinaryOp.Boolean_&)
4197+
case ZOR => js.LinkTimeIf(genLhs, js.BooleanLiteral(true), genRhs)(jstpe.BooleanType)
4198+
case ZAND => js.LinkTimeIf(genLhs, genRhs, js.BooleanLiteral(false))(jstpe.BooleanType)
4199+
case _ => invalid()
4200+
}
4201+
4202+
case jstpe.IntType =>
4203+
(code: @switch) match {
4204+
case EQ => binaryOp(js.BinaryOp.Int_==)
4205+
case NE => binaryOp(js.BinaryOp.Int_!=)
4206+
case LT => binaryOp(js.BinaryOp.Int_<)
4207+
case LE => binaryOp(js.BinaryOp.Int_<=)
4208+
case GT => binaryOp(js.BinaryOp.Int_>)
4209+
case GE => binaryOp(js.BinaryOp.Int_>=)
4210+
case _ => invalid()
4211+
}
4212+
4213+
case _ =>
4214+
invalid()
4215+
}
4216+
4217+
case None => // if !isPrimitive
4218+
invalid()
4219+
}
4220+
4221+
case _ =>
4222+
invalid()
4223+
}
4224+
}
4225+
41314226
/** Gen the SJSIR for a reflective call.
41324227
*
41334228
* Reflective calls are calls to a structural type field or method that

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,14 @@ final class JSDefinitions()(using Context) {
215215
@threadUnsafe lazy val WrappedArrayType: TypeRef = requiredClassRef("scala.scalajs.js.WrappedArray")
216216
def WrappedArrayClass(using Context) = WrappedArrayType.symbol.asClass
217217

218+
@threadUnsafe lazy val LinkingInfoModuleRef = requiredModuleRef("scala.scalajs.LinkingInfo")
219+
def LinkingInfoModule(using Context) = LinkingInfoModuleRef.symbol
220+
@threadUnsafe lazy val LinkingInfo_linkTimeIfR = LinkingInfoModule.requiredMethodRef("linkTimeIf")
221+
def LinkingInfo_linkTimeIf(using Context) = LinkingInfo_linkTimeIfR.symbol
222+
223+
@threadUnsafe lazy val LinkTimePropertyAnnotType: TypeRef = requiredClassRef("scala.scalajs.annotation.linkTimeProperty")
224+
def LinkTimePropertyAnnot(using Context) = LinkTimePropertyAnnotType.symbol.asClass
225+
218226
@threadUnsafe lazy val ScalaRunTime_isArrayR = defn.ScalaRuntimeModule.requiredMethodRef("isArray", List(???, ???))
219227
def ScalaRunTime_isArray(using Context): Symbol = ScalaRunTime_isArrayR.symbol
220228

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ object JSPrimitives {
4747
inline val UNWRAP_FROM_THROWABLE = WRAP_AS_THROWABLE + 1 // js.special.unwrapFromThrowable
4848
inline val DEBUGGER = UNWRAP_FROM_THROWABLE + 1 // js.special.debugger
4949

50-
inline val THROW = DEBUGGER + 1 // <special-ops>.throw
51-
inline val NEW_ARRAY = THROW + 1 // scala.runtime.Arrays.newArray
50+
inline val LINKTIME_IF = DEBUGGER + 1 // LinkingInfo.linkTimeIf
51+
52+
inline val THROW = LINKTIME_IF + 1 // <special-ops>.throw
53+
inline val NEW_ARRAY = THROW + 1 // scala.runtime.Arrays.newArray
5254

5355
inline val UNION_FROM = NEW_ARRAY + 1 // js.|.from
5456
inline val UNION_FROM_TYPE_CONSTRUCTOR = UNION_FROM + 1 // js.|.fromTypeConstructor
@@ -135,6 +137,8 @@ class JSPrimitives(ictx: Context) extends DottyPrimitives(ictx) {
135137
addPrimitive(jsdefn.Special_unwrapFromThrowable, UNWRAP_FROM_THROWABLE)
136138
addPrimitive(jsdefn.Special_debugger, DEBUGGER)
137139

140+
addPrimitive(jsdefn.LinkingInfo_linkTimeIf, LINKTIME_IF)
141+
138142
addPrimitive(defn.throwMethod, THROW)
139143
addPrimitive(defn.newArrayMethod, NEW_ARRAY)
140144

project/Build.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2820,7 +2820,6 @@ object Build {
28202820
++ (dir / "js/src/test/scala" ** (("*.scala": FileFilter)
28212821
-- "StackTraceTest.scala" // would require `npm install source-map-support`
28222822
-- "UnionTypeTest.scala" // requires the Scala 2 macro defined in Typechecking*.scala
2823-
-- "LinkTimeIfTest.scala" // TODO implement support for linkTimeIf
28242823
)).get
28252824

28262825
++ (dir / "js/src/test/require-2.12" ** "*.scala").get

0 commit comments

Comments
 (0)