Skip to content

Commit c6c5bd1

Browse files
committed
Fix typo
1 parent 53d1fca commit c6c5bd1

File tree

2 files changed

+69
-33
lines changed

2 files changed

+69
-33
lines changed

compiler/src/dotty/tools/dotc/core/TypeErasure.scala

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Uniques.unique
88
import dotc.transform.ExplicitOuter._
99
import dotc.transform.ValueClasses._
1010
import transform.TypeUtils._
11+
import Decorators._
1112
import Definitions.MaxImplementedFunctionArity
1213
import scala.annotation.tailrec
1314

@@ -32,8 +33,8 @@ import scala.annotation.tailrec
3233
*/
3334
object 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.is(Opaque) =>
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.is(Opaque) => !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.is(Opaque) =>
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
}

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,6 +1526,9 @@ object Types {
15261526
case TypeBounds(_, hi) => hi
15271527
case st => st
15281528
}
1529+
1530+
/** Same as superType, except that opaque types are treated as transparent aliases */
1531+
def translucentSuperType(implicit ctx: Context): Type = superType
15291532
}
15301533

15311534
// Every type has to inherit one of the following four abstract type classes.,
@@ -2181,6 +2184,14 @@ object Types {
21812184
override protected def designator_=(d: Designator): Unit = myDesignator = d
21822185

21832186
override def underlying(implicit ctx: Context): Type = info
2187+
2188+
override def translucentSuperType(implicit ctx: Context) = info match {
2189+
case TypeAlias(aliased) => aliased
2190+
case TypeBounds(_, hi) =>
2191+
if (symbol.is(Opaque)) symbol.opaqueAlias.asSeenFrom(prefix, symbol.owner)
2192+
else hi
2193+
case _ => underlying
2194+
}
21842195
}
21852196

21862197
final class CachedTermRef(prefix: Type, designator: Designator, hc: Int) extends TermRef(prefix, designator) {
@@ -2534,6 +2545,11 @@ object Types {
25342545
def isAnd: Boolean
25352546
def tp1: Type
25362547
def tp2: Type
2548+
2549+
def derivedAndOrType(tp1: Type, tp2: Type)(implicit ctx: Context) =
2550+
if ((tp1 eq this.tp1) && (tp2 eq this.tp2)) this
2551+
else if (isAnd) AndType.make(tp1, tp2, checkValid = true)
2552+
else OrType.make(tp1, tp2)
25372553
}
25382554

25392555
abstract case class AndType(tp1: Type, tp2: Type) extends AndOrType {
@@ -3297,6 +3313,13 @@ object Types {
32973313
cachedSuper
32983314
}
32993315

3316+
override def translucentSuperType(implicit ctx: Context): Type = tycon match {
3317+
case tycon: TypeRef if tycon.symbol.is(Opaque) =>
3318+
tycon.translucentSuperType.applyIfParameterized(args)
3319+
case _ =>
3320+
superType
3321+
}
3322+
33003323
override def tryNormalize(implicit ctx: Context): Type = tycon match {
33013324
case tycon: TypeRef =>
33023325
def tryMatchAlias = tycon.info match {

0 commit comments

Comments
 (0)