@@ -6,6 +6,7 @@ import Symbols._, Types._, Contexts._, Flags._, Names._, StdNames._, Phases._
6
6
import Flags .JavaDefined
7
7
import Uniques .unique
8
8
import TypeOps .makePackageObjPrefixExplicit
9
+ import backend .sjs .JSDefinitions
9
10
import transform .ExplicitOuter ._
10
11
import transform .ValueClasses ._
11
12
import transform .TypeUtils ._
@@ -142,29 +143,31 @@ object TypeErasure {
142
143
}
143
144
}
144
145
145
- private def erasureIdx (sourceLanguage : SourceLanguage , semiEraseVCs : Boolean , isConstructor : Boolean , wildcardOK : Boolean ) =
146
+ private def erasureIdx (sourceLanguage : SourceLanguage , semiEraseVCs : Boolean , isConstructor : Boolean , isSymbol : Boolean , wildcardOK : Boolean ) =
146
147
extension (b : Boolean ) def toInt = if b then 1 else 0
147
148
wildcardOK.toInt
148
- + (isConstructor.toInt << 1 )
149
- + (semiEraseVCs.toInt << 2 )
150
- + (sourceLanguage.ordinal << 3 )
149
+ + (isSymbol.toInt << 1 )
150
+ + (isConstructor.toInt << 2 )
151
+ + (semiEraseVCs.toInt << 3 )
152
+ + (sourceLanguage.ordinal << 4 )
151
153
152
- private val erasures = new Array [TypeErasure ](1 << (SourceLanguage .bits + 3 ))
154
+ private val erasures = new Array [TypeErasure ](1 << (SourceLanguage .bits + 4 ))
153
155
154
156
for
155
157
sourceLanguage <- SourceLanguage .values
156
158
semiEraseVCs <- List (false , true )
157
159
isConstructor <- List (false , true )
160
+ isSymbol <- List (false , true )
158
161
wildcardOK <- List (false , true )
159
162
do
160
- erasures(erasureIdx(sourceLanguage, semiEraseVCs, isConstructor, wildcardOK)) =
161
- new TypeErasure (sourceLanguage, semiEraseVCs, isConstructor, wildcardOK)
163
+ erasures(erasureIdx(sourceLanguage, semiEraseVCs, isConstructor, isSymbol, wildcardOK)) =
164
+ new TypeErasure (sourceLanguage, semiEraseVCs, isConstructor, isSymbol, wildcardOK)
162
165
163
166
/** Produces an erasure function. See the documentation of the class [[TypeErasure ]]
164
167
* for a description of each parameter.
165
168
*/
166
- private def erasureFn (sourceLanguage : SourceLanguage , semiEraseVCs : Boolean , isConstructor : Boolean , wildcardOK : Boolean ): TypeErasure =
167
- erasures(erasureIdx(sourceLanguage, semiEraseVCs, isConstructor, wildcardOK))
169
+ private def erasureFn (sourceLanguage : SourceLanguage , semiEraseVCs : Boolean , isConstructor : Boolean , isSymbol : Boolean , wildcardOK : Boolean ): TypeErasure =
170
+ erasures(erasureIdx(sourceLanguage, semiEraseVCs, isConstructor, isSymbol, wildcardOK))
168
171
169
172
/** The current context with a phase no later than erasure */
170
173
def preErasureCtx (using Context ) =
@@ -175,19 +178,19 @@ object TypeErasure {
175
178
* @param tp The type to erase.
176
179
*/
177
180
def erasure (tp : Type )(using Context ): Type =
178
- erasureFn(sourceLanguage = SourceLanguage .Scala3 , semiEraseVCs = false , isConstructor = false , wildcardOK = false )(tp)(using preErasureCtx)
181
+ erasureFn(sourceLanguage = SourceLanguage .Scala3 , semiEraseVCs = false , isConstructor = false , isSymbol = false , wildcardOK = false )(tp)(using preErasureCtx)
179
182
180
183
/** The value class erasure of a Scala type, where value classes are semi-erased to
181
184
* ErasedValueType (they will be fully erased in [[ElimErasedValueType ]]).
182
185
*
183
186
* @param tp The type to erase.
184
187
*/
185
188
def valueErasure (tp : Type )(using Context ): Type =
186
- erasureFn(sourceLanguage = SourceLanguage .Scala3 , semiEraseVCs = true , isConstructor = false , wildcardOK = false )(tp)(using preErasureCtx)
189
+ erasureFn(sourceLanguage = SourceLanguage .Scala3 , semiEraseVCs = true , isConstructor = false , isSymbol = false , wildcardOK = false )(tp)(using preErasureCtx)
187
190
188
191
/** The erasure that Scala 2 would use for this type. */
189
192
def scala2Erasure (tp : Type )(using Context ): Type =
190
- erasureFn(sourceLanguage = SourceLanguage .Scala2 , semiEraseVCs = true , isConstructor = false , wildcardOK = false )(tp)(using preErasureCtx)
193
+ erasureFn(sourceLanguage = SourceLanguage .Scala2 , semiEraseVCs = true , isConstructor = false , isSymbol = false , wildcardOK = false )(tp)(using preErasureCtx)
191
194
192
195
/** Like value class erasure, but value classes erase to their underlying type erasure */
193
196
def fullErasure (tp : Type )(using Context ): Type =
@@ -197,7 +200,7 @@ object TypeErasure {
197
200
198
201
def sigName (tp : Type , sourceLanguage : SourceLanguage )(using Context ): TypeName = {
199
202
val normTp = tp.translateFromRepeated(toArray = sourceLanguage.isJava)
200
- val erase = erasureFn(sourceLanguage, semiEraseVCs = ! sourceLanguage.isJava, isConstructor = false , wildcardOK = true )
203
+ val erase = erasureFn(sourceLanguage, semiEraseVCs = ! sourceLanguage.isJava, isConstructor = false , isSymbol = false , wildcardOK = true )
201
204
erase.sigName(normTp)(using preErasureCtx)
202
205
}
203
206
@@ -227,7 +230,7 @@ object TypeErasure {
227
230
def transformInfo (sym : Symbol , tp : Type )(using Context ): Type = {
228
231
val sourceLanguage = SourceLanguage (sym)
229
232
val semiEraseVCs = ! sourceLanguage.isJava // Java sees our value classes as regular classes.
230
- val erase = erasureFn(sourceLanguage, semiEraseVCs, sym.isConstructor, wildcardOK = false )
233
+ val erase = erasureFn(sourceLanguage, semiEraseVCs, sym.isConstructor, isSymbol = true , wildcardOK = false )
231
234
232
235
def eraseParamBounds (tp : PolyType ): Type =
233
236
tp.derivedLambdaType(
@@ -446,10 +449,11 @@ import TypeErasure._
446
449
* (they will be fully erased in [[ElimErasedValueType ]]).
447
450
* If false, they are erased like normal classes.
448
451
* @param isConstructor Argument forms part of the type of a constructor
452
+ * @param isSymbol If true, the type being erased is the info of a symbol.
449
453
* @param wildcardOK Wildcards are acceptable (true when using the erasure
450
454
* for computing a signature name).
451
455
*/
452
- class TypeErasure (sourceLanguage : SourceLanguage , semiEraseVCs : Boolean , isConstructor : Boolean , wildcardOK : Boolean ) {
456
+ class TypeErasure (sourceLanguage : SourceLanguage , semiEraseVCs : Boolean , isConstructor : Boolean , isSymbol : Boolean , wildcardOK : Boolean ) {
453
457
454
458
/** The erasure |T| of a type T. This is:
455
459
*
@@ -520,10 +524,22 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
520
524
else
521
525
erasedGlb(this (tp1), this (tp2), isJava = sourceLanguage.isJava)
522
526
case OrType (tp1, tp2) =>
523
- TypeComparer .orType(this (tp1), this (tp2), isErased = true )
527
+ if isSymbol && sourceLanguage.isScala2 && ctx.settings.scalajs.value then
528
+ // In Scala2Unpickler we unpickle Scala.js pseudo-unions as if they were
529
+ // real unions, but we must still erase them as Scala 2 would to emit
530
+ // the correct signatures in SJSIR.
531
+ // We only do this when `isSymbol` is true since in other situations we
532
+ // cannot distinguish a Scala.js pseudo-union from a Scala 3 union that
533
+ // has been substituted into a Scala 2 type (e.g., via `asSeenFrom`),
534
+ // erasing these unions as if they were pseudo-unions could have an
535
+ // impact on overriding relationships so it's best to leave them
536
+ // alone (and this doesn't impact the SJSIR we generate).
537
+ JSDefinitions .jsdefn.PseudoUnionType
538
+ else
539
+ TypeComparer .orType(this (tp1), this (tp2), isErased = true )
524
540
case tp : MethodType =>
525
541
def paramErasure (tpToErase : Type ) =
526
- erasureFn(sourceLanguage, semiEraseVCs, isConstructor, wildcardOK)(tpToErase)
542
+ erasureFn(sourceLanguage, semiEraseVCs, isConstructor, isSymbol, wildcardOK)(tpToErase)
527
543
val (names, formals0) = if (tp.isErasedMethod) (Nil , Nil ) else (tp.paramNames, tp.paramInfos)
528
544
val formals = formals0.mapConserve(paramErasure)
529
545
eraseResult(tp.resultType) match {
@@ -567,7 +583,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
567
583
val defn .ArrayOf (elemtp) = tp
568
584
if (classify(elemtp).derivesFrom(defn.NullClass )) JavaArrayType (defn.ObjectType )
569
585
else if (isUnboundedGeneric(elemtp) && ! sourceLanguage.isJava) defn.ObjectType
570
- else JavaArrayType (erasureFn(sourceLanguage, semiEraseVCs = false , isConstructor, wildcardOK)(elemtp))
586
+ else JavaArrayType (erasureFn(sourceLanguage, semiEraseVCs = false , isConstructor, isSymbol, wildcardOK)(elemtp))
571
587
}
572
588
573
589
private def erasePair (tp : Type )(using Context ): Type = {
@@ -608,7 +624,9 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
608
624
val genericUnderlying = unbox.info.resultType
609
625
val underlying = tp.select(unbox).widen.resultType
610
626
611
- val erasedUnderlying = erasure(underlying)
627
+ // The underlying part of an ErasedValueType cannot be an ErasedValueType itself
628
+ val erase = erasureFn(sourceLanguage, semiEraseVCs = false , isConstructor, isSymbol, wildcardOK)
629
+ val erasedUnderlying = erase(underlying)
612
630
613
631
// Ideally, we would just use `erasedUnderlying` as the erasure of `tp`, but to
614
632
// be binary-compatible with Scala 2 we need two special cases for polymorphic
@@ -646,7 +664,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
646
664
// correctly (see SIP-15 and [[Erasure.Boxing.adaptToType]]), so the result type of a
647
665
// constructor method should not be semi-erased.
648
666
if semiEraseVCs && isConstructor && ! tp.isInstanceOf [MethodOrPoly ] then
649
- erasureFn(sourceLanguage, semiEraseVCs = false , isConstructor, wildcardOK).eraseResult(tp)
667
+ erasureFn(sourceLanguage, semiEraseVCs = false , isConstructor, isSymbol, wildcardOK).eraseResult(tp)
650
668
else tp match
651
669
case tp : TypeRef =>
652
670
val sym = tp.symbol
0 commit comments