1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
package dotty.tools.dotc
package core
package transform
import Symbols._, Types._, Contexts._, Flags._, Names._
object Erasure {
/** The erasure |T| of a type T. This is:
*
* - For a refined type scala.Array+[T]:
* - if T is Nothing or Null, scala.Array+[Object]
* - otherwise, if T <: Object, scala.Array+[|T|]
* - otherwise, if T is a type paramter coming from Java, scala.Array+[Object].
* - otherwise, Object
* - For a constant type, NoType or NoPrefix, the type itself.
* - For all other type proxies: The erasure of the underlying type.
* - For a typeref scala.Any, scala.AnyVal, scala.Singleon or scala.NotNull, java.lang.Object.
* - For a typeref scala.Unit, scala.runtime.BoxedUnit.
* - For a typeref P.C where C refers to a toplevel class, P.C.
* - For a typeref P.C where C refers to a nested class, |P|.C.
* - For a typeref P.C where C refers to an alias type, the erasure of C's alias.
* - For a typeref P.C where C refers to an abstract type, the erasure of C's upper bound.
* - For T1 & T2, erasure(T1) (??)
* - For T1 | T2, the first base class in the linearization of T which is also a base class of T2
* - For a method type (Fs)scala.Unit, (|Fs|)scala.Unit.
* - For any other method type (Fs)T, (|Fs|)|T|.
* - For a polymorphic type, the erasure of its result type.
* - For the class info type of java.lang.Object, the same type without any parents.
* - For a class info type of a value class, the same type without any parents.
* - For any other class info type with parents Ps, the same type with
* parents |Ps|, but with duplicate references of Object removed.
* - For any other type, exception.
*/
def erasure(tp: Type)(implicit ctx: Context): Type = tp match {
case tp: TypeRef =>
val sym = tp.symbol
if (sym.isClass)
/*if (sym.isDerivedValueClass) eraseDerivedValueClassRef(tref)
else */if (sym.owner is Package) normalizeClass(sym.asClass).typeConstructor
else tp.derivedNamedType(erasure(tp.prefix))
else erasure(sym.info)
case tp: RefinedType =>
val parent = tp.parent
if (parent.dealias.typeSymbol == defn.ArrayClass) eraseArray(tp)
else erasure(parent)
case ConstantType(_) | NoType | NoPrefix =>
tp
case tp: TypeProxy =>
erasure(tp.underlying)
case AndType(tp1, tp2) =>
erasure(tp1)
case OrType(tp1, tp2) =>
erasure(tp.baseType(lubClass(tp1, tp2)))
case tp: MethodType =>
tp.derivedMethodType(
tp.paramNames, tp.paramTypes.mapConserve(erasure), resultErasure(tp.resultType))
case tp: PolyType =>
erasure(tp.resultType)
case tp @ ClassInfo(pre, cls, classParents, decls, optSelfType) =>
val parents: List[TypeRef] =
if (cls == defn.ObjectClass || cls.isPrimitiveValueClass) Nil
else if (cls == defn.ArrayClass) defn.ObjectClass.typeConstructor :: Nil
else removeLaterObjects(classParents mapConserve (erasure(_).asInstanceOf[TypeRef]))
tp.derivedClassInfo(erasure(pre), parents, NoType)
}
def eraseArray(tp: RefinedType)(implicit ctx: Context) = {
val (n, elemtp) = tp.splitArray
if (elemtp <:< defn.NullType)
defn.ObjectArrayType
else if (elemtp <:< defn.ObjectType)
(erasure(elemtp) /: (0 until n))((erased, _) =>
defn.ArrayType.appliedTo(erased))
else if (elemtp.typeSymbol is JavaDefined)
defn.ObjectArrayType
else
defn.ObjectType
}
def normalizeClass(cls: ClassSymbol)(implicit ctx: Context): ClassSymbol = {
if (cls.owner == defn.ScalaPackageClass) {
if (cls == defn.AnyClass || cls == defn.AnyValClass || cls == defn.SingletonClass || cls == defn.NotNullClass)
return defn.ObjectClass
if (cls == defn.UnitClass)
return defn.BoxedUnitClass
}
cls
}
def lubClass(tp1: Type, tp2: Type)(implicit ctx: Context): ClassSymbol = {
var bcs1 = tp1.baseClasses
val bc2 = tp2.baseClasses.head
while (bcs1.nonEmpty && !bc2.isNonBottomSubClass(bcs1.head))
bcs1 = bcs1.tail
if (bcs1.isEmpty) defn.ObjectClass else bcs1.head
}
/** The parameter signature of a type.
* Need to ensure correspondence with erasure
*/
def paramSignature(tp: Type)(implicit ctx: Context): TypeName = tp match {
case tp: TypeRef =>
val sym = tp.symbol
if (sym.isClass)
/*if (sym.isDerivedValueClass) eraseDerivedValueClassRef(tref)
else */if (sym.owner is Package) normalizeClass(sym.asClass).name
else sym.asClass.name
else paramSignature(sym.info)
case tp: RefinedType =>
val parent = tp.parent
if (parent.dealias.typeSymbol == defn.ArrayClass) paramSignature(eraseArray(tp))
else paramSignature(parent)
case tp: TypeProxy =>
paramSignature(tp.underlying)
case AndType(tp1, tp2) =>
paramSignature(tp1)
case OrType(tp1, tp2) =>
lubClass(tp1, tp2).name
}
def resultErasure(tp: Type)(implicit ctx: Context) =
if (tp.dealias.typeSymbol == defn.UnitClass) tp else erasure(tp)
def removeLaterObjects(trs: List[TypeRef])(implicit ctx: Context): List[TypeRef] = trs match {
case tr :: trs1 => tr :: (trs1 filter (_.typeSymbol != defn.ObjectClass))
case nil => nil
}
}
|