@@ -6,6 +6,7 @@ import Symbols._, Types._, Contexts._, Flags._, Names._, StdNames._, Phases._
66import Flags .JavaDefined
77import Uniques .unique
88import TypeOps .makePackageObjPrefixExplicit
9+ import backend .sjs .JSDefinitions
910import transform .ExplicitOuter ._
1011import transform .ValueClasses ._
1112import transform .TypeUtils ._
@@ -142,29 +143,31 @@ object TypeErasure {
142143 }
143144 }
144145
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 ) =
146147 extension (b : Boolean ) def toInt = if b then 1 else 0
147148 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 )
151153
152- private val erasures = new Array [TypeErasure ](1 << (SourceLanguage .bits + 3 ))
154+ private val erasures = new Array [TypeErasure ](1 << (SourceLanguage .bits + 4 ))
153155
154156 for
155157 sourceLanguage <- SourceLanguage .values
156158 semiEraseVCs <- List (false , true )
157159 isConstructor <- List (false , true )
160+ isSymbol <- List (false , true )
158161 wildcardOK <- List (false , true )
159162 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)
162165
163166 /** Produces an erasure function. See the documentation of the class [[TypeErasure ]]
164167 * for a description of each parameter.
165168 */
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))
168171
169172 /** The current context with a phase no later than erasure */
170173 def preErasureCtx (using Context ) =
@@ -175,19 +178,19 @@ object TypeErasure {
175178 * @param tp The type to erase.
176179 */
177180 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)
179182
180183 /** The value class erasure of a Scala type, where value classes are semi-erased to
181184 * ErasedValueType (they will be fully erased in [[ElimErasedValueType ]]).
182185 *
183186 * @param tp The type to erase.
184187 */
185188 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)
187190
188191 /** The erasure that Scala 2 would use for this type. */
189192 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)
191194
192195 /** Like value class erasure, but value classes erase to their underlying type erasure */
193196 def fullErasure (tp : Type )(using Context ): Type =
@@ -197,7 +200,7 @@ object TypeErasure {
197200
198201 def sigName (tp : Type , sourceLanguage : SourceLanguage )(using Context ): TypeName = {
199202 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 )
201204 erase.sigName(normTp)(using preErasureCtx)
202205 }
203206
@@ -227,7 +230,7 @@ object TypeErasure {
227230 def transformInfo (sym : Symbol , tp : Type )(using Context ): Type = {
228231 val sourceLanguage = SourceLanguage (sym)
229232 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 )
231234
232235 def eraseParamBounds (tp : PolyType ): Type =
233236 tp.derivedLambdaType(
@@ -446,10 +449,11 @@ import TypeErasure._
446449 * (they will be fully erased in [[ElimErasedValueType ]]).
447450 * If false, they are erased like normal classes.
448451 * @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.
449453 * @param wildcardOK Wildcards are acceptable (true when using the erasure
450454 * for computing a signature name).
451455 */
452- class TypeErasure (sourceLanguage : SourceLanguage , semiEraseVCs : Boolean , isConstructor : Boolean , wildcardOK : Boolean ) {
456+ class TypeErasure (sourceLanguage : SourceLanguage , semiEraseVCs : Boolean , isConstructor : Boolean , isSymbol : Boolean , wildcardOK : Boolean ) {
453457
454458 /** The erasure |T| of a type T. This is:
455459 *
@@ -520,10 +524,22 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
520524 else
521525 erasedGlb(this (tp1), this (tp2), isJava = sourceLanguage.isJava)
522526 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 )
524540 case tp : MethodType =>
525541 def paramErasure (tpToErase : Type ) =
526- erasureFn(sourceLanguage, semiEraseVCs, isConstructor, wildcardOK)(tpToErase)
542+ erasureFn(sourceLanguage, semiEraseVCs, isConstructor, isSymbol, wildcardOK)(tpToErase)
527543 val (names, formals0) = if (tp.isErasedMethod) (Nil , Nil ) else (tp.paramNames, tp.paramInfos)
528544 val formals = formals0.mapConserve(paramErasure)
529545 eraseResult(tp.resultType) match {
@@ -567,7 +583,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
567583 val defn .ArrayOf (elemtp) = tp
568584 if (classify(elemtp).derivesFrom(defn.NullClass )) JavaArrayType (defn.ObjectType )
569585 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))
571587 }
572588
573589 private def erasePair (tp : Type )(using Context ): Type = {
@@ -608,7 +624,9 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
608624 val genericUnderlying = unbox.info.resultType
609625 val underlying = tp.select(unbox).widen.resultType
610626
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)
612630
613631 // Ideally, we would just use `erasedUnderlying` as the erasure of `tp`, but to
614632 // be binary-compatible with Scala 2 we need two special cases for polymorphic
@@ -646,7 +664,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
646664 // correctly (see SIP-15 and [[Erasure.Boxing.adaptToType]]), so the result type of a
647665 // constructor method should not be semi-erased.
648666 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)
650668 else tp match
651669 case tp : TypeRef =>
652670 val sym = tp.symbol
0 commit comments