@@ -8,6 +8,7 @@ import Uniques.unique
88import dotc .transform .ExplicitOuter ._
99import dotc .transform .ValueClasses ._
1010import transform .TypeUtils ._
11+ import Decorators ._
1112import Definitions .MaxImplementedFunctionArity
1213import scala .annotation .tailrec
1314
@@ -32,8 +33,8 @@ import scala.annotation.tailrec
3233 */
3334object TypeErasure {
3435
35- private def erasureDependsOnArgs (tp : Type )(implicit ctx : Context ) =
36- tp.isRef( defn.ArrayClass ) || tp.isRef( defn.PairClass )
36+ private def erasureDependsOnArgs (sym : Symbol )(implicit ctx : Context ) =
37+ sym == defn.ArrayClass || sym == defn.PairClass
3738
3839 /** A predicate that tests whether a type is a legal erased type. Only asInstanceOf and
3940 * isInstanceOf may have types that do not satisfy the predicate.
@@ -46,7 +47,7 @@ object TypeErasure {
4647 case tp : TypeRef =>
4748 val sym = tp.symbol
4849 sym.isClass &&
49- ! erasureDependsOnArgs(tp ) &&
50+ ! erasureDependsOnArgs(sym ) &&
5051 ! defn.erasedToObject.contains(sym) &&
5152 ! defn.isSyntheticFunctionClass(sym)
5253 case _ : TermRef =>
@@ -192,37 +193,48 @@ object TypeErasure {
192193 }
193194 }
194195
196+ /** Underlying type that does not contain aliases or abstract types
197+ * at top-level, treating opaque aliases as transparent.
198+ */
199+ def classify (tp : Type )(implicit ctx : Context ): Type =
200+ if (tp.typeSymbol.isClass) tp
201+ else tp match {
202+ case tp : TypeProxy => classify(tp.translucentSuperType)
203+ case tp : AndOrType => tp.derivedAndOrType(classify(tp.tp1), classify(tp.tp2))
204+ case _ => tp
205+ }
206+
195207 /** Is `tp` an abstract type or polymorphic type parameter that has `Any`, `AnyVal`,
196208 * or a universal trait as upper bound and that is not Java defined? Arrays of such types are
197209 * erased to `Object` instead of `Object[]`.
198210 */
199211 def isUnboundedGeneric (tp : Type )(implicit ctx : Context ): Boolean = tp.dealias match {
200- case tp : TypeRef =>
212+ case tp : TypeRef if ! tp.symbol.isOpaqueHelper =>
201213 ! tp.symbol.isClass &&
202- ! tp .derivesFrom(defn.ObjectClass ) &&
214+ ! classify(tp) .derivesFrom(defn.ObjectClass ) &&
203215 ! tp.symbol.is(JavaDefined )
204216 case tp : TypeParamRef =>
205- ! tp .derivesFrom(defn.ObjectClass ) &&
217+ ! classify(tp) .derivesFrom(defn.ObjectClass ) &&
206218 ! tp.binder.resultType.isJavaMethod
207219 case tp : TypeAlias => isUnboundedGeneric(tp.alias)
208- case tp : TypeBounds => ! tp.hi.derivesFrom(defn.ObjectClass )
209- case tp : TypeProxy => isUnboundedGeneric(tp.underlying )
220+ case tp : TypeBounds => ! classify( tp.hi) .derivesFrom(defn.ObjectClass )
221+ case tp : TypeProxy => isUnboundedGeneric(tp.translucentSuperType )
210222 case tp : AndType => isUnboundedGeneric(tp.tp1) && isUnboundedGeneric(tp.tp2)
211223 case tp : OrType => isUnboundedGeneric(tp.tp1) || isUnboundedGeneric(tp.tp2)
212224 case _ => false
213225 }
214226
215227 /** Is `tp` an abstract type or polymorphic type parameter, or another unbounded generic type? */
216228 def isGeneric (tp : Type )(implicit ctx : Context ): Boolean = tp.dealias match {
217- case tp : TypeRef => ! tp.symbol.isClass
229+ case tp : TypeRef if ! tp.symbol.isOpaqueHelper => ! tp.symbol.isClass
218230 case tp : TypeParamRef => true
219- case tp : TypeProxy => isGeneric(tp.underlying )
231+ case tp : TypeProxy => isGeneric(tp.translucentSuperType )
220232 case tp : AndType => isGeneric(tp.tp1) || isGeneric(tp.tp2)
221233 case tp : OrType => isGeneric(tp.tp1) || isGeneric(tp.tp2)
222234 case _ => false
223235 }
224236
225- /** The erased least upper bound is computed as follows
237+ /** The erased least upper bound of two erased types is computed as follows
226238 * - if both argument are arrays of objects, an array of the erased lub of the element types
227239 * - if both arguments are arrays of same primitives, an array of this primitive
228240 * - if one argument is array of primitives and the other is array of objects, Object
@@ -286,7 +298,8 @@ object TypeErasure {
286298 }
287299 }
288300
289- /** The erased greatest lower bound picks one of the two argument types. It prefers, in this order:
301+ /** The erased greatest lower bound of two erased type picks one of the two argument types.
302+ * It prefers, in this order:
290303 * - arrays over non-arrays
291304 * - subtypes over supertypes, unless isJava is set
292305 * - real classes over traits
@@ -317,15 +330,15 @@ object TypeErasure {
317330 * possible instantiations?
318331 */
319332 def hasStableErasure (tp : Type )(implicit ctx : Context ): Boolean = tp match {
320- case tp : TypeRef =>
333+ case tp : TypeRef if ! tp.symbol.isOpaqueHelper =>
321334 tp.info match {
322335 case TypeAlias (alias) => hasStableErasure(alias)
323336 case _ : ClassInfo => true
324337 case _ => false
325338 }
326339 case tp : TypeParamRef => false
327340 case tp : TypeBounds => false
328- case tp : TypeProxy => hasStableErasure(tp.superType )
341+ case tp : TypeProxy => hasStableErasure(tp.translucentSuperType )
329342 case tp : AndType => hasStableErasure(tp.tp1) && hasStableErasure(tp.tp2)
330343 case tp : OrType => hasStableErasure(tp.tp1) && hasStableErasure(tp.tp2)
331344 case _ => false
@@ -381,16 +394,17 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
381394 tp
382395 case tp : TypeRef =>
383396 val sym = tp.symbol
384- if (! sym.isClass) this (tp.info )
397+ if (! sym.isClass) this (tp.translucentSuperType )
385398 else if (semiEraseVCs && isDerivedValueClass(sym)) eraseDerivedValueClassRef(tp)
386399 else if (sym == defn.ArrayClass ) apply(tp.appliedTo(TypeBounds .empty)) // i966 shows that we can hit a raw Array type.
387400 else if (defn.isSyntheticFunctionClass(sym)) defn.erasedFunctionType(sym)
388401 else eraseNormalClassRef(tp)
389402 case tp : AppliedType =>
390- if (tp.tycon.isRef(defn.ArrayClass )) eraseArray(tp)
391- else if (tp.tycon.isRef(defn.PairClass )) erasePair(tp)
403+ val tycon = tp.tycon
404+ if (tycon.isRef(defn.ArrayClass )) eraseArray(tp)
405+ else if (tycon.isRef(defn.PairClass )) erasePair(tp)
392406 else if (tp.isRepeatedParam) apply(tp.underlyingIfRepeated(isJava))
393- else apply(tp.superType )
407+ else apply(tp.translucentSuperType )
394408 case _ : TermRef | _ : ThisType =>
395409 this (tp.widen)
396410 case SuperType (thistpe, supertpe) =>
@@ -419,7 +433,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
419433 case tp @ ClassInfo (pre, cls, parents, decls, _) =>
420434 if (cls is Package ) tp
421435 else {
422- def eraseParent (tp : Type ) = tp.dealias match {
436+ def eraseParent (tp : Type ) = tp.dealias match { // note: can't be opaque, since it's a class parent
423437 case tp : AppliedType if tp.tycon.isRef(defn.PairClass ) => defn.ObjectType
424438 case _ => apply(tp)
425439 }
@@ -446,11 +460,9 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
446460
447461 private def eraseArray (tp : Type )(implicit ctx : Context ) = {
448462 val defn .ArrayOf (elemtp) = tp
449- def arrayErasure (tpToErase : Type ) =
450- erasureFn(isJava, semiEraseVCs = false , isConstructor, wildcardOK)(tpToErase)
451- if (elemtp derivesFrom defn.NullClass ) JavaArrayType (defn.ObjectType )
463+ if (classify(elemtp).derivesFrom(defn.NullClass )) JavaArrayType (defn.ObjectType )
452464 else if (isUnboundedGeneric(elemtp) && ! isJava) defn.ObjectType
453- else JavaArrayType (arrayErasure (elemtp))
465+ else JavaArrayType (erasureFn(isJava, semiEraseVCs = false , isConstructor, wildcardOK) (elemtp))
454466 }
455467
456468 private def erasePair (tp : Type )(implicit ctx : Context ): Type = {
@@ -502,8 +514,10 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
502514 // constructor method should not be semi-erased.
503515 else if (isConstructor && isDerivedValueClass(sym)) eraseNormalClassRef(tp)
504516 else this (tp)
505- case AppliedType (tycon, _) if tycon.typeSymbol.isClass && ! erasureDependsOnArgs(tycon) =>
506- eraseResult(tycon)
517+ case tp : AppliedType =>
518+ val sym = tp.tycon.typeSymbol
519+ if (sym.isClass && ! erasureDependsOnArgs(sym)) eraseResult(tp.tycon)
520+ else this (tp)
507521 case _ =>
508522 this (tp)
509523 }
@@ -530,8 +544,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
530544 }
531545 val sym = tp.symbol
532546 if (! sym.isClass) {
533- val info = tp.info
534- if (! info.exists) assert(false , " undefined: $tp with symbol $sym" )
547+ val info = tp.translucentSuperType
548+ if (! info.exists) assert(false , i " undefined: $tp with symbol $sym" )
535549 return sigName(info)
536550 }
537551 if (isDerivedValueClass(sym)) {
@@ -543,10 +557,11 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
543557 else
544558 normalizeClass(sym.asClass).fullName.asTypeName
545559 case tp : AppliedType =>
546- sigName(
547- if (erasureDependsOnArgs(tp.tycon)) this (tp)
548- else if (tp.tycon.typeSymbol.isClass) tp.underlying
549- else tp.superType)
560+ val sym = tp.tycon.typeSymbol
561+ sigName( // todo: what about repeatedParam?
562+ if (erasureDependsOnArgs(sym)) this (tp)
563+ else if (sym.isClass) tp.underlying
564+ else tp.translucentSuperType)
550565 case ErasedValueType (_, underlying) =>
551566 sigName(underlying)
552567 case JavaArrayType (elem) =>
@@ -574,6 +589,4 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
574589 println(s " no sig for $tp because of ${ex.printStackTrace()}" )
575590 throw ex
576591 }
577-
578-
579592}
0 commit comments