@@ -8,6 +8,7 @@ import Uniques.unique
8
8
import dotc .transform .ExplicitOuter ._
9
9
import dotc .transform .ValueClasses ._
10
10
import transform .TypeUtils ._
11
+ import Decorators ._
11
12
import Definitions .MaxImplementedFunctionArity
12
13
import scala .annotation .tailrec
13
14
@@ -32,8 +33,8 @@ import scala.annotation.tailrec
32
33
*/
33
34
object TypeErasure {
34
35
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
37
38
38
39
/** A predicate that tests whether a type is a legal erased type. Only asInstanceOf and
39
40
* isInstanceOf may have types that do not satisfy the predicate.
@@ -46,7 +47,7 @@ object TypeErasure {
46
47
case tp : TypeRef =>
47
48
val sym = tp.symbol
48
49
sym.isClass &&
49
- ! erasureDependsOnArgs(tp ) &&
50
+ ! erasureDependsOnArgs(sym ) &&
50
51
! defn.erasedToObject.contains(sym) &&
51
52
! defn.isSyntheticFunctionClass(sym)
52
53
case _ : TermRef =>
@@ -192,37 +193,48 @@ object TypeErasure {
192
193
}
193
194
}
194
195
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
+
195
207
/** Is `tp` an abstract type or polymorphic type parameter that has `Any`, `AnyVal`,
196
208
* or a universal trait as upper bound and that is not Java defined? Arrays of such types are
197
209
* erased to `Object` instead of `Object[]`.
198
210
*/
199
211
def isUnboundedGeneric (tp : Type )(implicit ctx : Context ): Boolean = tp.dealias match {
200
- case tp : TypeRef =>
212
+ case tp : TypeRef if ! tp.symbol.is( Opaque ) =>
201
213
! tp.symbol.isClass &&
202
- ! tp .derivesFrom(defn.ObjectClass ) &&
214
+ ! classify(tp) .derivesFrom(defn.ObjectClass ) &&
203
215
! tp.symbol.is(JavaDefined )
204
216
case tp : TypeParamRef =>
205
- ! tp .derivesFrom(defn.ObjectClass ) &&
217
+ ! classify(tp) .derivesFrom(defn.ObjectClass ) &&
206
218
! tp.binder.resultType.isJavaMethod
207
219
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 )
210
222
case tp : AndType => isUnboundedGeneric(tp.tp1) && isUnboundedGeneric(tp.tp2)
211
223
case tp : OrType => isUnboundedGeneric(tp.tp1) || isUnboundedGeneric(tp.tp2)
212
224
case _ => false
213
225
}
214
226
215
227
/** Is `tp` an abstract type or polymorphic type parameter, or another unbounded generic type? */
216
228
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
218
230
case tp : TypeParamRef => true
219
- case tp : TypeProxy => isGeneric(tp.underlying )
231
+ case tp : TypeProxy => isGeneric(tp.translucentSuperType )
220
232
case tp : AndType => isGeneric(tp.tp1) || isGeneric(tp.tp2)
221
233
case tp : OrType => isGeneric(tp.tp1) || isGeneric(tp.tp2)
222
234
case _ => false
223
235
}
224
236
225
- /** The erased least upper bound is computed as follows
237
+ /** The erased least upper bound of two erased types is computed as follows
226
238
* - if both argument are arrays of objects, an array of the erased lub of the element types
227
239
* - if both arguments are arrays of same primitives, an array of this primitive
228
240
* - if one argument is array of primitives and the other is array of objects, Object
@@ -286,7 +298,8 @@ object TypeErasure {
286
298
}
287
299
}
288
300
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:
290
303
* - arrays over non-arrays
291
304
* - subtypes over supertypes, unless isJava is set
292
305
* - real classes over traits
@@ -317,15 +330,15 @@ object TypeErasure {
317
330
* possible instantiations?
318
331
*/
319
332
def hasStableErasure (tp : Type )(implicit ctx : Context ): Boolean = tp match {
320
- case tp : TypeRef =>
333
+ case tp : TypeRef if ! tp.symbol.is( Opaque ) =>
321
334
tp.info match {
322
335
case TypeAlias (alias) => hasStableErasure(alias)
323
336
case _ : ClassInfo => true
324
337
case _ => false
325
338
}
326
339
case tp : TypeParamRef => false
327
340
case tp : TypeBounds => false
328
- case tp : TypeProxy => hasStableErasure(tp.superType )
341
+ case tp : TypeProxy => hasStableErasure(tp.translucentSuperType )
329
342
case tp : AndType => hasStableErasure(tp.tp1) && hasStableErasure(tp.tp2)
330
343
case tp : OrType => hasStableErasure(tp.tp1) && hasStableErasure(tp.tp2)
331
344
case _ => false
@@ -381,16 +394,17 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
381
394
tp
382
395
case tp : TypeRef =>
383
396
val sym = tp.symbol
384
- if (! sym.isClass) this (tp.info )
397
+ if (! sym.isClass) this (tp.translucentSuperType )
385
398
else if (semiEraseVCs && isDerivedValueClass(sym)) eraseDerivedValueClassRef(tp)
386
399
else if (sym == defn.ArrayClass ) apply(tp.appliedTo(TypeBounds .empty)) // i966 shows that we can hit a raw Array type.
387
400
else if (defn.isSyntheticFunctionClass(sym)) defn.erasedFunctionType(sym)
388
401
else eraseNormalClassRef(tp)
389
402
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)
392
406
else if (tp.isRepeatedParam) apply(tp.underlyingIfRepeated(isJava))
393
- else apply(tp.superType )
407
+ else apply(tp.translucentSuperType )
394
408
case _ : TermRef | _ : ThisType =>
395
409
this (tp.widen)
396
410
case SuperType (thistpe, supertpe) =>
@@ -419,7 +433,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
419
433
case tp @ ClassInfo (pre, cls, parents, decls, _) =>
420
434
if (cls is Package ) tp
421
435
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
423
437
case tp : AppliedType if tp.tycon.isRef(defn.PairClass ) => defn.ObjectType
424
438
case _ => apply(tp)
425
439
}
@@ -446,11 +460,9 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
446
460
447
461
private def eraseArray (tp : Type )(implicit ctx : Context ) = {
448
462
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 )
452
464
else if (isUnboundedGeneric(elemtp) && ! isJava) defn.ObjectType
453
- else JavaArrayType (arrayErasure (elemtp))
465
+ else JavaArrayType (erasureFn(isJava, semiEraseVCs = false , isConstructor, wildcardOK) (elemtp))
454
466
}
455
467
456
468
private def erasePair (tp : Type )(implicit ctx : Context ): Type = {
@@ -502,8 +514,10 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
502
514
// constructor method should not be semi-erased.
503
515
else if (isConstructor && isDerivedValueClass(sym)) eraseNormalClassRef(tp)
504
516
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)
507
521
case _ =>
508
522
this (tp)
509
523
}
@@ -530,8 +544,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
530
544
}
531
545
val sym = tp.symbol
532
546
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" )
535
549
return sigName(info)
536
550
}
537
551
if (isDerivedValueClass(sym)) {
@@ -543,10 +557,11 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
543
557
else
544
558
normalizeClass(sym.asClass).fullName.asTypeName
545
559
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)
550
565
case ErasedValueType (_, underlying) =>
551
566
sigName(underlying)
552
567
case JavaArrayType (elem) =>
@@ -574,6 +589,4 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
574
589
println(s " no sig for $tp because of ${ex.printStackTrace()}" )
575
590
throw ex
576
591
}
577
-
578
-
579
592
}
0 commit comments