Skip to content

Reorganize LinkTimeProperties. #5163

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 1 commit into from
May 7, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import org.scalajs.ir.WellKnownNames._

import org.scalajs.linker._
import org.scalajs.linker.checker.CheckingPhase
import org.scalajs.linker.frontend.{IRLoader, LambdaSynthesizer, SyntheticClassKind}
import org.scalajs.linker.frontend.{IRLoader, LambdaSynthesizer, LinkTimeProperties, SyntheticClassKind}
import org.scalajs.linker.interface._
import org.scalajs.linker.interface.unstable.ModuleInitializerImpl
import org.scalajs.linker.standard._
Expand All @@ -47,6 +47,8 @@ import Infos.{NamespacedMethodName, ReachabilityInfo, ReachabilityInfoInClass}
final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
checkIRFor: Option[CheckingPhase], failOnError: Boolean, irLoader: IRLoader) {

private val linkTimeProperties = LinkTimeProperties.fromCoreSpec(config.coreSpec)

private val infoLoader: InfoLoader =
new InfoLoader(irLoader, checkIRFor)

Expand All @@ -55,7 +57,7 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,

infoLoader.update(logger)

val run = new AnalyzerRun(config, initial, infoLoader)(
val run = new AnalyzerRun(config, initial, infoLoader, linkTimeProperties)(
adjustExecutionContextForParallelism(ec, config.parallel))

run
Expand Down Expand Up @@ -99,7 +101,10 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
}

private class AnalyzerRun(config: CommonPhaseConfig, initial: Boolean,
infoLoader: InfoLoader)(implicit ec: ExecutionContext) extends Analysis {
infoLoader: InfoLoader, linkTimeProperties: LinkTimeProperties)(
implicit ec: ExecutionContext)
extends Analysis {

import AnalyzerRun._

private val allowAddingSyntheticMethods = initial
Expand Down Expand Up @@ -1539,7 +1544,7 @@ private class AnalyzerRun(config: CommonPhaseConfig, initial: Boolean,

if (data.referencedLinkTimeProperties.nonEmpty) {
for ((name, tpe) <- data.referencedLinkTimeProperties) {
if (!config.coreSpec.linkTimeProperties.validate(name, tpe)) {
if (!linkTimeProperties.get(name).exists(_.tpe == tpe)) {
_errors ::= InvalidLinkTimeProperty(name, tpe, from)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ import org.scalajs.ir.{Position, Version}
final class Desugarer(config: CommonPhaseConfig, checkIR: Boolean) {
import Desugarer._

private val desugarTransformer = new DesugarTransformer(config.coreSpec)
private val linkTimeProperties = LinkTimeProperties.fromCoreSpec(config.coreSpec)

private val desugarTransformer = new DesugarTransformer(linkTimeProperties)

def desugar(unit: LinkingUnit, logger: Logger): LinkingUnit = {
val result = logger.time("Desugarer: Desugar") {
Expand Down Expand Up @@ -118,7 +120,7 @@ final class Desugarer(config: CommonPhaseConfig, checkIR: Boolean) {

private[linker] object Desugarer {

private final class DesugarTransformer(coreSpec: CoreSpec)
private final class DesugarTransformer(linkTimeProperties: LinkTimeProperties)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

extends ClassTransformer {

/* Cache the names generated for lambda classes because computing their
Expand All @@ -135,8 +137,17 @@ private[linker] object Desugarer {

override def transform(tree: Tree): Tree = {
tree match {
case prop: LinkTimeProperty =>
coreSpec.linkTimeProperties.transformLinkTimeProperty(prop)
case LinkTimeProperty(name) =>
implicit val pos = tree.pos
val value = linkTimeProperties.get(name).getOrElse {
throw new IllegalArgumentException(
s"link time property not found: '$name' of type ${tree.tpe}")
}
value match {
case LinkTimeProperties.LinkTimeBoolean(value) => BooleanLiteral(value)
case LinkTimeProperties.LinkTimeInt(value) => IntLiteral(value)
case LinkTimeProperties.LinkTimeString(value) => StringLiteral(value)
}

case NewLambda(descriptor, fun) =>
implicit val pos = tree.pos
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@
* additional information regarding copyright ownership.
*/

package org.scalajs.linker.standard
package org.scalajs.linker.frontend

import org.scalajs.ir.{Types => jstpe, Trees => js}
import org.scalajs.ir.Trees.LinkTimeProperty._
import org.scalajs.ir.Types._
import org.scalajs.ir.ScalaJSVersions
import org.scalajs.ir.Position.NoPosition
import org.scalajs.linker.interface.{Semantics, ESFeatures}

private[linker] final class LinkTimeProperties (
import org.scalajs.linker.interface.{ESVersion => _, _}
import org.scalajs.linker.standard.CoreSpec

final class LinkTimeProperties private (
semantics: Semantics,
esFeatures: ESFeatures,
targetIsWebAssembly: Boolean
Expand All @@ -38,31 +39,24 @@ private[linker] final class LinkTimeProperties (
LinkTimeString(ScalaJSVersions.current)
)

def validate(name: String, tpe: jstpe.Type): Boolean = {
linkTimeProperties.get(name).exists {
case _: LinkTimeBoolean => tpe == jstpe.BooleanType
case _: LinkTimeInt => tpe == jstpe.IntType
case _: LinkTimeString => tpe == jstpe.StringType
}
}
def get(name: String): Option[LinkTimeValue] =
linkTimeProperties.get(name)
}

object LinkTimeProperties {
sealed abstract class LinkTimeValue(val tpe: Type)

def transformLinkTimeProperty(prop: js.LinkTimeProperty): js.Literal = {
val value = linkTimeProperties.getOrElse(prop.name,
throw new IllegalArgumentException(s"link time property not found: '${prop.name}' of type ${prop.tpe}"))
value match {
case LinkTimeBoolean(value) =>
js.BooleanLiteral(value)(prop.pos)
case LinkTimeInt(value) =>
js.IntLiteral(value)(prop.pos)
case LinkTimeString(value) =>
js.StringLiteral(value)(prop.pos)
}
final case class LinkTimeInt(value: Int) extends LinkTimeValue(IntType)

final case class LinkTimeBoolean(value: Boolean) extends LinkTimeValue(BooleanType)

final case class LinkTimeString(value: String) extends LinkTimeValue(StringType) {
// Being extra careful
require(value != null, "LinkTimeString requires a non-null value.")
}
}

private[linker] object LinkTimeProperties {
sealed abstract class LinkTimeValue
final case class LinkTimeInt(value: Int) extends LinkTimeValue
final case class LinkTimeBoolean(value: Boolean) extends LinkTimeValue
final case class LinkTimeString(value: String) extends LinkTimeValue
def fromCoreSpec(coreSpec: CoreSpec): LinkTimeProperties = {
new LinkTimeProperties(coreSpec.semantics, coreSpec.esFeatures,
coreSpec.targetIsWebAssembly)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,6 @@ final class CoreSpec private (
targetIsWebAssembly
)
}

private[linker] lazy val linkTimeProperties = new LinkTimeProperties(
semantics, esFeatures, targetIsWebAssembly)
}

private[linker] object CoreSpec {
Expand Down
3 changes: 3 additions & 0 deletions project/BinaryIncompatibilities.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ object BinaryIncompatibilities {
)

val Linker = Seq(
// private[linker], not an issue
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.linker.standard.CoreSpec.linkTimeProperties"),
ProblemFilters.exclude[MissingClassProblem]("org.scalajs.linker.standard.LinkTimeProperties*"),
)

val LinkerInterface = Seq(
Expand Down