8000 Rearrange the init sequence of PrimRefs and PrimTypeWithRefs. by sjrd · Pull Request #5139 · scala-js/scala-js · GitHub
[go: up one dir, main page]

Skip to content

Rearrange the init sequence of PrimRefs and PrimTypeWithRefs. #5139

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
Mar 15, 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
121 changes: 47 additions & 74 deletions ir/shared/src/main/scala/org/scalajs/ir/Types.scala
E15C
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@

package org.scalajs.ir

import scala.annotation.tailrec

import Names._
import Trees._

Expand Down Expand Up @@ -62,20 +60,14 @@ object Types {
}
}

sealed abstract class PrimTypeWithRef extends PrimType {
def primRef: PrimRef = this match {
case VoidType => VoidRef
case BooleanType => BooleanRef
case CharType => CharRef
case ByteType => ByteRef
case ShortType => ShortRef
case IntType => IntRef
case LongType => LongRef
case FloatType => FloatRef
case DoubleType => DoubleRef
case NullType => NullRef
case NothingType => NothingRef
}
/* Each PrimTypeWithRef creates its corresponding `PrimRef`. Therefore, it
* takes the parameters that need to be passed to the `PrimRef` constructor.
* This little dance ensures proper initialization safety between
* `PrimTypeWithRef`s and `PrimRef`s.
*/
sealed abstract class PrimTypeWithRef(primRefCharCode: Char, primRefDisplayName: String)
extends PrimType {
val primRef: PrimRef = new PrimRef(this, primRefCharCode, primRefDisplayName)
}

/** Any type.
Expand Down Expand Up @@ -106,50 +98,50 @@ object Types {
* Expressions from which one can never come back are typed as `Nothing`.
* For example, `throw` and `return`.
*/
case object NothingType extends PrimTypeWithRef
case object NothingType extends PrimTypeWithRef('E', "nothing")

/** The type of `undefined`. */
case object UndefType extends PrimType

/** Boolean type.
* It does not accept `null` nor `undefined`.
*/
case object BooleanType extends PrimTypeWithRef
case object BooleanType extends PrimTypeWithRef('Z', "boolean")

/** `Char` type, a 16-bit UTF-16 code unit.
* It does not accept `null` nor `undefined`.
*/
case object CharType extends PrimTypeWithRef
case object CharType extends PrimTypeWithRef('C', "char")

/** 8-bit signed integer type.
* It does not accept `null` nor `undefined`.
*/
case object ByteType extends PrimTypeWithRef
case object ByteType extends PrimTypeWithRef('B', "byte")

/** 16-bit signed integer type.
* It does not accept `null` nor `undefined`.
*/
case object ShortType extends PrimTypeWithRef
case object ShortType extends PrimTypeWithRef('S', "short")

/** 32-bit signed integer type.
* It does not accept `null` nor `undefined`.
*/
case object IntType extends PrimTypeWithRef
case object IntType extends PrimTypeWithRef('I', "int")

/** 64-bit signed integer type.
* It does not accept `null` nor `undefined`.
*/
case object LongType extends PrimTypeWithRef
case object LongType extends PrimTypeWithRef('J', "long")

/** Float type (32-bit).
* It does not accept `null` nor `undefined`.
*/
case object FloatType extends PrimTypeWithRef
case object FloatType extends PrimTypeWithRef('F', "float")

/** Double type (64-bit).
* It does not accept `null` nor `undefined`.
*/
case object DoubleType extends PrimTypeWithRef
case object DoubleType extends PrimTypeWithRef('D', "double")

/** String type.
* It does not accept `null` nor `undefined`.
Expand All @@ -160,7 +152,7 @@ object Types {
* It does not accept `undefined`.
* The null type is a subtype of all class types and array types.
*/
case object NullType extends PrimTypeWithRef
case object NullType extends PrimTypeWithRef('N', "null")

/** Class (or interface) type. */
final case class ClassType(className: ClassName, nullable: Boolean) extends Type {
Expand Down Expand Up @@ -210,7 +202,7 @@ object Types {
}

/** Void type, the top of type of our type system. */
case object VoidType extends PrimTypeWithRef
case object VoidType extends PrimTypeWithRef('V', "void")

@deprecated("Use VoidType instead", since = "1.18.0")
lazy val NoType: VoidType.type = VoidType
Expand Down Expand Up @@ -265,8 +257,12 @@ object Types {

sealed abstract class NonArrayTypeRef extends TypeRef

// scalastyle:off equals.hash.code
// PrimRef uses reference equality, but has a stable hashCode() method

/** Primitive type reference. */
final case class PrimRef private[ir] (tpe: PrimTypeWithRef)
final class PrimRef private[Types] (val tpe: PrimTypeWithRef,
charCodeInit: Char, displayNameInit: String) // "Init" variants so we can have good Scaladoc on the val's
extends NonArrayTypeRef {

/** The display name of this primitive type.
Expand All @@ -278,19 +274,7 @@ object Types {
* For `NullType` and `NothingType`, the names are `"null"` and
* `"nothing"`, respectively.
*/
val displayName: String = tpe match {
case VoidType => "void"
case BooleanType => "boolean"
case CharType => "char"
case ByteType => "byte"
case ShortType => "short"
case IntType => "int"
case LongType => "long"
case FloatType => "float"
case DoubleType => "double"
case NullType => "null"
case NothingType => "nothing"
}
val displayName: String = displayNameInit

/** The char code of this primitive type.
*
Expand All @@ -302,41 +286,30 @@ object Types {
* For `NullType` and `NothingType`, the char codes are `'N'` and `'E'`,
* respectively.
*/
val charCode: Char = tpe match {
case VoidType => 'V'
case BooleanType => 'Z'
case CharType => 'C'
case ByteType => 'B'
case ShortType => 'S'
case IntType => 'I'
case LongType => 'J'
case FloatType => 'F'
case DoubleType => 'D'
case NullType => 'N'
case NothingType => 'E'
}
val charCode: Char = charCodeInit

// Stable hash code, corresponding to reference equality
override def hashCode(): Int = charCode.##
}

/* @unchecked for the initialization checker of Scala 3
* When we get here, `VoidType` is not yet considered fully initialized because
* its method `primRef` can access `VoidRef`. Since the constructor of
* `PrimRef` pattern-matches on its `tpe`, which is `VoidType`, this is flagged
* by the init checker, although our usage is safe given that we do not call
* `primRef`. The same reasoning applies to the other primitive types.
* In the future, we may want to rearrange the initialization sequence of
* this file to avoid this issue.
*/
final val VoidRef = PrimRef(VoidType: @unchecked)
final val BooleanRef = PrimRef(BooleanType: @unchecked)
final val CharRef = PrimRef(CharType: @unchecked)
final val ByteRef = PrimRef(ByteType: @unchecked)
final val ShortRef = PrimRef(ShortType: @unchecked)
final val IntRef = PrimRef(IntType: @unchecked)
final val LongRef = PrimRef(LongType: @unchecked)
final val FloatRef = PrimRef(FloatType: @unchecked)
final val DoubleRef = PrimRef(DoubleType: @unchecked)
final val NullRef = PrimRef(NullType: @unchecked)
final val NothingRef = PrimRef(NothingType: @unchecked)
// scalastyle:on equals.hash.code

object PrimRef {
def unapply(typeRef: PrimRef): Some[PrimTypeWithRef] =
Some(typeRef.tpe)
}

final val VoidRef = VoidType.primRef
final val BooleanRef = BooleanType.primRef
final val CharRef = CharType.primRef
final val ByteRef = ByteType.primRef
final val ShortRef = ShortType.primRef
final val IntRef = IntType.primRef
final val LongRef = LongType.primRef
final val FloatRef = FloatType.primRef
final val DoubleRef = DoubleType.primRef
final val NullRef = NullType.primRef
final val NothingRef = NothingType.primRef

/** Class (or interface) type. */
final case class ClassRef(className: ClassName) extends NonArrayTypeRef {
Expand Down
21 changes: 21 additions & 0 deletions project/BinaryIncompatibilities.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,27 @@ object BinaryIncompatibilities {
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types.BoxedClassToPrimType"),
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types.PrimTypeToBoxedClass"),

// !!! Breaking, PrimRef is not a case class anymore
ProblemFilters.exclude[MissingTypesProblem]("org.scalajs.ir.Types$PrimRef"),
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.canEqual"),
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.productArity"),
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.productElement"),
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.productElementName"),
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.productElementNames"),
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.productIterator"),
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.productPrefix"),
ProblemFilters.exclude[IncompatibleResultTypeProblem]("org.scalajs.ir.Types#PrimRef.unapply"),

// !!! Breaking I guess ... we used to leak public things out of a `case class` with a private[ir] constructor
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.this"),
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.apply"),
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.copy"),
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.copy$default$1"),
ProblemFilters.exclude[MissingTypesProblem]("org.scalajs.ir.Types$PrimRef$"),

// constructor of a sealed abstract class, not an issue
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimTypeWithRef.this"),

// private, not an issue
ProblemFilters.exclude[MissingClassProblem]("org.scalajs.ir.Serializers$Deserializer$BodyHack5Transformer$"),
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Serializers#Hacks.use*"),
Expand Down
0