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

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

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 < 8000 span class="pl-k">=> 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 A93C
*/
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