@@ -14,6 +14,40 @@ import Decorators._
1414import Definitions .MaxImplementedFunctionArity
1515import scala .annotation .tailrec
1616
17+ /** The language in which the definition being erased was written. */
18+ enum SourceLanguage :
19+ case Java , Scala2 , Scala3
20+ def isJava : Boolean = this eq Java
21+ def isScala2 : Boolean = this eq Scala2
22+ def isScala3 : Boolean = this eq Scala3
23+ object SourceLanguage :
24+ /** The language in which `sym` was defined. */
25+ def apply (sym : Symbol )(using Context ): SourceLanguage =
26+ if sym.is(JavaDefined ) then
27+ SourceLanguage .Java
28+ // Scala 2 methods don't have Inline set, except for the ones injected with `patchStdlibClass`
29+ // which are really Scala 3 methods.
30+ else if sym.isClass && sym.is(Scala2x ) || (sym.maybeOwner.is(Scala2x ) && ! sym.is(Inline )) then
31+ SourceLanguage .Scala2
32+ else
33+ SourceLanguage .Scala3
34+
35+ /** Number of bits needed to represent this enum. */
36+ def bits : Int =
37+ val len = values.length
38+ val log2 = 31 - Integer .numberOfLeadingZeros(len)
39+ if len == 1 << log2 then
40+ log2
41+ else
42+ log2 + 1
43+
44+ /** A common language to use when matching definitions written in different
45+ * languages.
46+ */
47+ def commonLanguage (x : SourceLanguage , y : SourceLanguage ): SourceLanguage =
48+ if x.ordinal > y.ordinal then x else y
49+ end SourceLanguage
50+
1751/** Erased types are:
1852 *
1953 * ErasedValueType
@@ -107,28 +141,29 @@ object TypeErasure {
107141 }
108142 }
109143
110- private def erasureIdx (isJava : Boolean , semiEraseVCs : Boolean , isConstructor : Boolean , wildcardOK : Boolean ) =
111- (if (isJava) 1 else 0 ) +
112- (if (semiEraseVCs) 2 else 0 ) +
113- (if (isConstructor) 4 else 0 ) +
114- (if (wildcardOK) 8 else 0 )
144+ private def erasureIdx (sourceLanguage : SourceLanguage , semiEraseVCs : Boolean , isConstructor : Boolean , wildcardOK : Boolean ) =
145+ extension (b : Boolean ) def toInt = if b then 1 else 0
146+ wildcardOK.toInt
147+ + (isConstructor.toInt << 1 )
148+ + (semiEraseVCs.toInt << 2 )
149+ + (sourceLanguage.ordinal << 3 )
115150
116- private val erasures = new Array [TypeErasure ](16 )
151+ private val erasures = new Array [TypeErasure ](1 << ( SourceLanguage .bits + 3 ) )
117152
118- for {
119- isJava <- List ( false , true )
153+ for
154+ sourceLanguage <- SourceLanguage .values
120155 semiEraseVCs <- List (false , true )
121156 isConstructor <- List (false , true )
122157 wildcardOK <- List (false , true )
123- }
124- erasures(erasureIdx(isJava , semiEraseVCs, isConstructor, wildcardOK)) =
125- new TypeErasure (isJava , semiEraseVCs, isConstructor, wildcardOK)
158+ do
159+ erasures(erasureIdx(sourceLanguage , semiEraseVCs, isConstructor, wildcardOK)) =
160+ new TypeErasure (sourceLanguage , semiEraseVCs, isConstructor, wildcardOK)
126161
127162 /** Produces an erasure function. See the documentation of the class [[TypeErasure ]]
128163 * for a description of each parameter.
129164 */
130- private def erasureFn (isJava : Boolean , semiEraseVCs : Boolean , isConstructor : Boolean , wildcardOK : Boolean ): TypeErasure =
131- erasures(erasureIdx(isJava , semiEraseVCs, isConstructor, wildcardOK))
165+ private def erasureFn (sourceLanguage : SourceLanguage , semiEraseVCs : Boolean , isConstructor : Boolean , wildcardOK : Boolean ): TypeErasure =
166+ erasures(erasureIdx(sourceLanguage , semiEraseVCs, isConstructor, wildcardOK))
132167
133168 /** The current context with a phase no later than erasure */
134169 def preErasureCtx (using Context ) =
@@ -139,25 +174,25 @@ object TypeErasure {
139174 * @param tp The type to erase.
140175 */
141176 def erasure (tp : Type )(using Context ): Type =
142- erasureFn(isJava = false , semiEraseVCs = false , isConstructor = false , wildcardOK = false )(tp)(using preErasureCtx)
177+ erasureFn(sourceLanguage = SourceLanguage . Scala3 , semiEraseVCs = false , isConstructor = false , wildcardOK = false )(tp)(using preErasureCtx)
143178
144179 /** The value class erasure of a Scala type, where value classes are semi-erased to
145180 * ErasedValueType (they will be fully erased in [[ElimErasedValueType ]]).
146181 *
147182 * @param tp The type to erase.
148183 */
149184 def valueErasure (tp : Type )(using Context ): Type =
150- erasureFn(isJava = false , semiEraseVCs = true , isConstructor = false , wildcardOK = false )(tp)(using preErasureCtx)
185+ erasureFn(sourceLanguage = SourceLanguage . Scala3 , semiEraseVCs = true , isConstructor = false , wildcardOK = false )(tp)(using preErasureCtx)
151186
152187 /** Like value class erasure, but value classes erase to their underlying type erasure */
153188 def fullErasure (tp : Type )(using Context ): Type =
154189 valueErasure(tp) match
155190 case ErasedValueType (_, underlying) => erasure(underlying)
156191 case etp => etp
157192
158- def sigName (tp : Type , isJava : Boolean )(using Context ): TypeName = {
159- val normTp = tp.translateFromRepeated(toArray = isJava)
160- val erase = erasureFn(isJava , semiEraseVCs = true , isConstructor = false , wildcardOK = true )
193+ def sigName (tp : Type , sourceLanguage : SourceLanguage )(using Context ): TypeName = {
194+ val normTp = tp.translateFromRepeated(toArray = sourceLanguage. isJava)
195+ val erase = erasureFn(sourceLanguage , semiEraseVCs = true , isConstructor = false , wildcardOK = true )
161196 erase.sigName(normTp)(using preErasureCtx)
162197 }
163198
@@ -181,15 +216,13 @@ object TypeErasure {
181216 * - For $asInstanceOf : [T]T
182217 * - For $isInstanceOf : [T]Boolean
183218 * - For all abstract types : = ?
184- * - For Java-defined symbols: : the erasure of their type with isJava = true,
185- * semiEraseVCs = false. Semi-erasure never happens in Java.
186- * - For all other symbols : the semi-erasure of their types, with
187- * isJava, isConstructor set according to symbol.
219+ *
220+ * `sourceLanguage`, `isConstructor` and `semiEraseVCs` are set based on the symbol.
188221 */
189222 def transformInfo (sym : Symbol , tp : Type )(using Context ): Type = {
190- val isJava = sym is JavaDefined
191- val semiEraseVCs = ! isJava
192- val erase = erasureFn(isJava , semiEraseVCs, sym.isConstructor, wildcardOK = false )
223+ val sourceLanguage = SourceLanguage ( sym)
224+ val semiEraseVCs = ! sourceLanguage. isJava // Java sees our value classes as regular classes.
225+ val erase = erasureFn(sourceLanguage , semiEraseVCs, sym.isConstructor, wildcardOK = false )
193226
194227 def eraseParamBounds (tp : PolyType ): Type =
195228 tp.derivedLambdaType(
@@ -391,18 +424,20 @@ object TypeErasure {
391424 case _ => false
392425 }
393426}
427+
394428import TypeErasure ._
395429
396430/**
397- * @param isJava Arguments should be treated the way Java does it
398- * @param semiEraseVCs If true, value classes are semi-erased to ErasedValueType
399- * (they will be fully erased in [[ElimErasedValueType ]]).
400- * If false, they are erased like normal classes.
401- * @param isConstructor Argument forms part of the type of a constructor
402- * @param wildcardOK Wildcards are acceptable (true when using the erasure
403- * for computing a signature name).
431+ * @param sourceLanguage Adapt our erasure rules to mimic what the given language
432+ * would do.
433+ * @param semiEraseVCs If true, value classes are semi-erased to ErasedValueType
434+ * (they will be fully erased in [[ElimErasedValueType ]]).
435+ * If false, they are erased like normal classes.
436+ * @param isConstructor Argument forms part of the type of a constructor
437+ * @param wildcardOK Wildcards are acceptable (true when using the erasure
438+ * for computing a signature name).
404439 */
405- class TypeErasure (isJava : Boolean , semiEraseVCs : Boolean , isConstructor : Boolean , wildcardOK : Boolean ) {
440+ class TypeErasure (sourceLanguage : SourceLanguage , semiEraseVCs : Boolean , isConstructor : Boolean , wildcardOK : Boolean ) {
406441
407442 /** The erasure |T| of a type T. This is:
408443 *
@@ -450,7 +485,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
450485 val tycon = tp.tycon
451486 if (tycon.isRef(defn.ArrayClass )) eraseArray(tp)
452487 else if (tycon.isRef(defn.PairClass )) erasePair(tp)
453- else if (tp.isRepeatedParam) apply(tp.translateFromRepeated(toArray = isJava))
488+ else if (tp.isRepeatedParam) apply(tp.translateFromRepeated(toArray = sourceLanguage. isJava))
454489 else if (semiEraseVCs && isDerivedValueClass(tycon.classSymbol)) eraseDerivedValueClass(tp)
455490 else apply(tp.translucentSuperType)
456491 case _ : TermRef | _ : ThisType =>
@@ -468,12 +503,12 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
468503 case tp : TypeProxy =>
469504 this (tp.underlying)
470505 case AndType (tp1, tp2) =>
471- erasedGlb(this (tp1), this (tp2), isJava)
506+ erasedGlb(this (tp1), this (tp2), sourceLanguage. isJava)
472507 case OrType (tp1, tp2) =>
473508 TypeComparer .orType(this (tp1), this (tp2), isErased = true )
474509 case tp : MethodType =>
475510 def paramErasure (tpToErase : Type ) =
476- erasureFn(isJava , semiEraseVCs, isConstructor, wildcardOK)(tpToErase)
511+ erasureFn(sourceLanguage , semiEraseVCs, isConstructor, wildcardOK)(tpToErase)
477512 val (names, formals0) = if (tp.isErasedMethod) (Nil , Nil ) else (tp.paramNames, tp.paramInfos)
478513 val formals = formals0.mapConserve(paramErasure)
479514 eraseResult(tp.resultType) match {
@@ -516,8 +551,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
516551 private def eraseArray (tp : Type )(using Context ) = {
517552 val defn .ArrayOf (elemtp) = tp
518553 if (classify(elemtp).derivesFrom(defn.NullClass )) JavaArrayType (defn.ObjectType )
519- else if (isUnboundedGeneric(elemtp) && ! isJava) defn.ObjectType
520- else JavaArrayType (erasureFn(isJava , semiEraseVCs = false , isConstructor, wildcardOK)(elemtp))
554+ else if (isUnboundedGeneric(elemtp) && ! sourceLanguage. isJava) defn.ObjectType
555+ else JavaArrayType (erasureFn(sourceLanguage , semiEraseVCs = false , isConstructor, wildcardOK)(elemtp))
521556 }
522557
523558 private def erasePair (tp : Type )(using Context ): Type = {
@@ -544,7 +579,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
544579 // See doc comment for ElimByName for speculation how we could improve this.
545580 else
546581 MethodType (Nil , Nil ,
547- eraseResult(sym.info.finalResultType.translateFromRepeated(toArray = isJava)))
582+ eraseResult(sym.info.finalResultType.translateFromRepeated(toArray = sourceLanguage. isJava)))
548583 case tp1 : PolyType =>
549584 eraseResult(tp1.resultType) match
550585 case rt : MethodType => rt
@@ -596,7 +631,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
596631 // correctly (see SIP-15 and [[Erasure.Boxing.adaptToType]]), so the result type of a
597632 // constructor method should not be semi-erased.
598633 if semiEraseVCs && isConstructor && ! tp.isInstanceOf [MethodOrPoly ] then
599- erasureFn(isJava , semiEraseVCs = false , isConstructor, wildcardOK).eraseResult(tp)
634+ erasureFn(sourceLanguage , semiEraseVCs = false , isConstructor, wildcardOK).eraseResult(tp)
600635 else tp match
601636 case tp : TypeRef =>
602637 val sym = tp.symbol
0 commit comments