8000 Rearrange the init sequence of `PrimRef`s and `PrimTypeWithRef`s. · scala-js/scala-js@b1eabac · GitHub
[go: up one dir, main page]

Skip to content

Commit b1eabac

Browse files
committed
Rearrange the init sequence of PrimRefs and PrimTypeWithRefs.
So that it is more obvious that it is not circular. `PrimRef` is not a case class anymore.
1 parent 2ed0b39 commit b1eabac

File tree

2 files changed

+68
-74
lines changed

2 files changed

+68
-74
lines changed

ir/shared/src/main/scala/org/scalajs/ir/Types.scala

Lines changed: 47 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212

1313
package org.scalajs.ir
1414

15-
import scala.annotation.tailrec
16-
1715
import Names._
1816
import Trees._
1917

@@ -62,20 +60,14 @@ object Types {
6260
}
6361
}
6462

65-
sealed abstract class PrimTypeWithRef extends PrimType {
66-
def primRef: PrimRef = this match {
67-
case VoidType => VoidRef
68-
case BooleanType => BooleanRef
69-
case CharType => CharRef
70-
case ByteType => ByteRef
71-
case ShortType => ShortRef
72-
case IntType => IntRef
73-
case LongType => LongRef
74-
case FloatType => FloatRef
75-
case DoubleType => DoubleRef
76-
case NullType => NullRef
77-
case NothingType => NothingRef
78-
}
63+
/* Each PrimTypeWithRef creates its corresponding `PrimRef`. Therefore, it
64+
* takes the parameters that need to be passed to the `PrimRef` constructor.
65+
* This little dance ensures proper initialization safety between
66+
* `PrimTypeWithRef`s and `PrimRef`s.
67+
*/
68+
sealed abstract class PrimTypeWithRef(primRefCharCode: Char, primRefDisplayName: String)
69+
extends PrimType {
70+
val primRef: PrimRef = new PrimRef(this, primRefCharCode, primRefDisplayName)
7971
}
8072

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

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

114106
/** Boolean type.
115107
* It does not accept `null` nor `undefined`.
116108
*/
117-
case object BooleanType extends PrimTypeWithRef
109+
case object BooleanType extends PrimTypeWithRef('Z', "boolean")
118110

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

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

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

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

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

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

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

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

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

212204
/** Void type, the top of type of our type system. */
213-
case object VoidType extends PrimTypeWithRef
205+
case object VoidType extends PrimTypeWithRef('V', "void")
214206

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

266258
sealed abstract class NonArrayTypeRef extends TypeRef
267259

260+
// scalastyle:off equals.hash.code
261+
// PrimRef uses reference equality, but has a stable hashCode() method
262+
268263
/** Primitive type reference. */
269-
final case class PrimRef private[ir] (tpe: PrimTypeWithRef)
264+
final class PrimRef private[Types] (val tpe: PrimTypeWithRef,
265+
charCodeInit: Char, displayNameInit: String) // "Init" variants so we can have good Scaladoc on the val's
270266
extends NonArrayTypeRef {
271267

272268
/** The display name of this primitive type.
@@ -278,19 +274,7 @@ object Types {
278274
* For `NullType` and `NothingType`, the names are `"null"` and
279275
* `"nothing"`, respectively.
280276
*/
281-
val displayName: String = tpe match {
282-
case VoidType => "void"
283-
case BooleanType => "boolean"
284-
case CharType => "char"
285-
case ByteType => "byte"
286-
case ShortType => "short"
287-
case IntType => "int"
288-
case LongType => "long"
289-
case FloatType => "float"
290-
case DoubleType => "double"
291-
case NullType => "null"
292-
case NothingType => "nothing"
293-
}
277+
val displayName: String = displayNameInit
294278

295279
/** The char code of this primitive type.
296280
*
@@ -302,41 +286,30 @@ object Types {
302286
* For `NullType` and `NothingType`, the char codes are `'N'` and `'E'`,
303287
* respectively.
304288
*/
305-
val charCode: Char = tpe match {
306-
case VoidType => 'V'
307-
case BooleanType => 'Z'
308-
case CharType => 'C'
309-
case ByteType => 'B'
310-
case ShortType => 'S'
311-
case IntType => 'I'
312-
case LongType => 'J'
313-
case FloatType => 'F'
314-
case DoubleType => 'D'
315-
case NullType => 'N'
316-
case NothingType => 'E'
317-
}
289+
val charCode: Char = charCodeInit
290+
291+
// Stable hash code, corresponding to reference equality
292+
override def hashCode(): Int = charCode.##
318293
}
319294

320-
/* @unchecked for the initialization checker of Scala 3
321-
* When we get here, `VoidType` is not yet considered fully initialized because
322-
* its method `primRef` can access `VoidRef`. Since the constructor of
323-
* `PrimRef` pattern-matches on its `tpe`, which is `VoidType`, this is flagged
324-
* by the init checker, although our usage is safe given that we do not call
325-
* `primRef`. The same reasoning applies to the other primitive types.
326-
* In the future, we may want to rearrange the initialization sequence of
327-
* this file to avoid this issue.
328-
*/
329-
final val VoidRef = PrimRef(VoidType: @unchecked)
330-
final val BooleanRef = PrimRef(BooleanType: @unchecked)
331-
final val CharRef = PrimRef(CharType: @unchecked)
332-
final val ByteRef = PrimRef(ByteType: @unchecked)
333-
final val ShortRef = PrimRef(ShortType: @unchecked)
334-
final val IntRef = PrimRef(IntType: @unchecked)
335-
final val LongRef = PrimRef(LongType: @unchecked)
336-
final val FloatRef = PrimRef(FloatType: @unchecked)
337-
final val DoubleRef = PrimRef(DoubleType: @unchecked)
338-
final val NullRef = PrimRef(NullType: @unchecked)
339-
final val NothingRef = PrimRef(NothingType: @unchecked)
295+
// scalastyle:on equals.hash.code
296+
297+
object PrimRef {
298+
def unapply(typeRef: PrimRef): Some[PrimTypeWithRef] =
299+
Some(typeRef.tpe)
300+
}
301+
302+
final val VoidRef = VoidType.primRef
303+
final val BooleanRef = BooleanType.primRef
304+
final val CharRef = CharType.primRef
305+
final val ByteRef = ByteType.primRef
306+
final val ShortRef = ShortType.primRef
307+
final val IntRef = IntType.primRef
308+
final val LongRef = LongType.primRef
309+
final val FloatRef = FloatType.primRef
310+
final val DoubleRef = DoubleType.primRef
311+
final val NullRef = NullType.primRef
312+
final val NothingRef = NothingType.primRef
340313

341314
/** Class (or interface) type. */
342315
final case class ClassRef(className: ClassName) extends NonArrayTypeRef {

project/BinaryIncompatibilities.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,27 @@ object BinaryIncompatibilities {
1616
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types.BoxedClassToPrimType"),
1717
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types.PrimTypeToBoxedClass"),
1818

19+
// !!! Breaking, PrimRef is not a case class anymore
20+
ProblemFilters.exclude[MissingTypesProblem]("org.scalajs.ir.Types$PrimRef"),
21+
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.canEqual"),
22+
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.productArity"),
23+
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.productElement"),
24+
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.productElementName"),
25+
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.productElementNames"),
26+
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.productIterator"),
27+
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.productPrefix"),
28+
ProblemFilters.exclude[IncompatibleResultTypeProblem]("org.scalajs.ir.Types#PrimRef.unapply"),
29+
30+
// !!! Breaking I guess ... we used to leak public things out of a `case class` with a private[ir] constructor
31+
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.this"),
32+
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.apply"),
33+
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.copy"),
34+
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimRef.copy$default$1"),
35+
ProblemFilters.exclude[MissingTypesProblem]("org.scalajs.ir.Types$PrimRef$"),
36+
37+
// constructor of a sealed abstract class, not an issue
38+
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Types#PrimTypeWithRef.this"),
39+
1940
// private, not an issue
2041
ProblemFilters.exclude[MissingClassProblem]("org.scalajs.ir.Serializers$Deserializer$BodyHack5Transformer$"),
2142
ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Serializers#Hacks.use*"),

0 commit comments

Comments
 (0)
0