@@ -88,7 +88,7 @@ abstract class Erasure extends AddInterfaces
88
88
val eparams = typeParamsToExistentials(ClassClass , ClassClass .typeParams)
89
89
val upperBound = (
90
90
if (isPhantomClass(sym)) AnyClass .tpe
91
- else if (sym.isLocalClass) erasure. intersectionDominator(tp.parents) // erasure(tp )
91
+ else if (sym.isLocalClass) intersectionDominator(tp.parents)
92
92
else tp.widen
93
93
)
94
94
@@ -134,8 +134,9 @@ abstract class Erasure extends AddInterfaces
134
134
* - For a typeref P.C[Ts] where C refers to an alias type, the erasure of C's alias.
135
135
* - For a typeref P.C[Ts] where C refers to an abstract type, the
136
136
* erasure of C's upper bound.
137
- * - For a non-empty type intersection (possibly with refinement),
138
- * the erasure of its first parent.
137
+ * - For a non-empty type intersection (possibly with refinement)
138
+ * - in scala, the erasure of the intersection dominator
139
+ * - in java, the erasure of its first parent <--- @PP: not yet in spec.
139
140
* - For an empty type intersection, java.lang.Object.
140
141
* - For a method type (Fs)scala.Unit, (|Fs|)scala#Unit.
141
142
* - For any other method type (Fs)Y, (|Fs|)|T|.
@@ -146,29 +147,84 @@ abstract class Erasure extends AddInterfaces
146
147
* parents |Ps|, but with duplicate references of Object removed.
147
148
* - for all other types, the type itself (with any sub-components erased)
148
149
*/
149
- object erasure extends TypeMap {
150
- // Compute the dominant part of the intersection type with given `parents` according to new spec.
151
- def intersectionDominator (parents : List [Type ]): Type =
150
+ def erasure (sym : Symbol , tp : Type ): Type = {
151
+ if (sym != NoSymbol && sym.enclClass.isJavaDefined) {
152
+ val res = javaErasure(tp)
153
+ if (verifyJavaErasure && sym.isMethod) {
154
+ val old = scalaErasure(tp)
155
+ if (! (res =:= old))
156
+ log(" Identified divergence between java/scala erasure:\n scala: " + old + " \n java: " + res)
157
+ }
158
+ res
159
+ }
160
+ else scalaErasure(tp)
161
+ }
162
+
163
+ /** Scala's more precise erasure than java's is problematic as follows:
164
+ *
165
+ * - Symbols are read from classfiles and populated with types
166
+ * - The textual signature read from the bytecode is forgotten
167
+ * - Bytecode generation must know the precise signature of a method
168
+ * - the signature is derived from the erasure of the method type
169
+ * - If that derivation does not adhere to the rules by which the original
170
+ * signature was created, a NoSuchMethod error will result.
171
+ *
172
+ * For this reason and others (such as distinguishing constructors from other methods)
173
+ * erasure is now (Symbol, Type) => Type rather than Type => Type.
174
+ */
175
+ object scalaErasure extends ErasureMap {
176
+ /** In scala, calculate a useful parent.
177
+ * An intersection such as `Object with Trait` erases to Trait.
178
+ */
179
+ def mergeParents (parents : List [Type ]): Type =
180
+ intersectionDominator(parents)
181
+ }
182
+ object javaErasure extends ErasureMap {
183
+ /** In java, always take the first parent.
184
+ * An intersection such as `Object with Trait` erases to Object.
185
+ */
186
+ def mergeParents (parents : List [Type ]): Type =
152
187
if (parents.isEmpty) ObjectClass .tpe
153
- else {
154
- val psyms = parents map (_.typeSymbol)
155
- if (psyms contains ArrayClass ) {
156
- // treat arrays specially
157
- arrayType(
158
- intersectionDominator(
159
- parents filter (_.typeSymbol == ArrayClass ) map (_.typeArgs.head)))
160
- } else {
161
- // implement new spec for erasure of refined types.
162
- def isUnshadowed (psym : Symbol ) =
163
- ! (psyms exists (qsym => (psym ne qsym) && (qsym isNonBottomSubClass psym)))
164
- val cs = parents.iterator.filter { p => // isUnshadowed is a bit expensive, so try classes first
165
- val psym = p.typeSymbol
166
- psym.initialize
167
- psym.isClass && ! psym.isTrait && isUnshadowed(psym)
168
- }
169
- (if (cs.hasNext) cs else parents.iterator.filter(p => isUnshadowed(p.typeSymbol))).next()
188
+ else parents.head
189
+ }
190
+
191
+ /** The intersection dominator (SLS 3.7) of a list of types is computed as follows.
192
+ *
193
+ * - If the list contains one or more occurrences of scala.Array with
194
+ * type parameters El1, El2, ... then the dominator is scala.Array with
195
+ * type parameter of intersectionDominator(List(El1, El2, ...)). <--- @PP: not yet in spec.
196
+ * - Otherwise, the list is reduced to a subsequence containing only types
197
+ * which are not subtypes of other listed types (the span.)
198
+ * - If the span is empty, the dominator is Object.
199
+ * - If the span contains a class Tc which is not a trait and which is
200
+ * not Object, the dominator is Tc. <--- @PP: "which is not Object" not in spec.
201
+ * - Otherwise, the dominator is the first element of the span.
202
+ */
203
+ def intersectionDominator (parents : List [Type ]): Type = {
204
+ if (parents.isEmpty) ObjectClass .tpe
205
+ else {
206
+ val psyms = parents map (_.typeSymbol)
207
+ if (psyms contains ArrayClass ) {
208
+ // treat arrays specially
209
+ arrayType(
210
+ intersectionDominator(
211
+ parents filter (_.typeSymbol == ArrayClass ) map (_.typeArgs.head)))
212
+ } else {
213
+ // implement new spec for erasure of refined types.
214
+ def isUnshadowed (psym : Symbol ) =
215
+ ! (psyms exists (qsym => (psym ne qsym) && (qsym isNonBottomSubClass psym)))
216
+ val cs = parents.iterator.filter { p => // isUnshadowed is a bit expensive, so try classes first
217
+ val psym = p.typeSymbol
218
+ psym.initialize
219
+ psym.isClass && ! psym.isTrait && isUnshadowed(psym)
170
220
}
221
+ (if (cs.hasNext) cs else parents.iterator.filter(p => isUnshadowed(p.typeSymbol))).next()
171
222
}
223
+ }
224
+ }
225
+
226
+ abstract class ErasureMap extends TypeMap {
227
+ def mergeParents (parents : List [Type ]): Type
172
228
173
229
def apply (tp : Type ): Type = {
174
230
tp match {
@@ -183,7 +239,7 @@ abstract class Erasure extends AddInterfaces
183
239
else typeRef(apply(pre), sym, args map this )
184
240
else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass || sym == NotNullClass ) erasedTypeRef(ObjectClass )
185
241
else if (sym == UnitClass ) erasedTypeRef(BoxedUnitClass )
186
- else if (sym.isRefinementClass) apply(intersectionDominator (tp.parents))
242
+ else if (sym.isRefinementClass) apply(mergeParents (tp.parents))
187
243
else if (sym.isClass) typeRef(apply(rebindInnerClass(pre, sym)), sym, List ()) // #2585
188
244
else apply(sym.info) // alias type or abstract type
189
245
case PolyType (tparams, restpe) =>
@@ -196,12 +252,13 @@ abstract class Erasure extends AddInterfaces
196
252
if (restpe.typeSymbol == UnitClass )
197
253
erasedTypeRef(UnitClass )
198
254
else if (settings.YdepMethTpes .value)
199
- // this replaces each typeref that refers to an argument by the type `p.tpe` of the actual argument p (p in params)
255
+ // this replaces each typeref that refers to an argument
256
+ // by the type `p.tpe` of the actual argument p (p in params)
200
257
apply(mt.resultType(params map (_.tpe)))
201
258
else
202
259
apply(restpe))
203
260
case RefinedType (parents, decls) =>
204
- apply(intersectionDominator (parents))
261
+ apply(mergeParents (parents))
205
262
case AnnotatedType (_, atp, _) =>
206
263
apply(atp)
207
264
case ClassInfoType (parents, decls, clazz) =>
@@ -229,8 +286,8 @@ abstract class Erasure extends AddInterfaces
229
286
else if (! sym.owner.isPackageClass) traverse(pre)
230
287
case PolyType (_, _) | ExistentialType (_, _) =>
231
288
result = true
232
- case RefinedType (parents, decls ) =>
233
- if ( ! parents.isEmpty) traverse(parents.head)
289
+ case RefinedType (parents, _ ) =>
290
+ parents foreach traverse
234
291
case ClassInfoType (parents, _, _) =>
235
292
parents foreach traverse
236
293
case AnnotatedType (_, atp, _) =>
@@ -242,6 +299,7 @@ abstract class Erasure extends AddInterfaces
242
299
}
243
300
}
244
301
302
+ private def verifyJavaErasure = settings.Xverify .value || settings.debug.value
245
303
private def needsJavaSig (tp : Type ) = ! settings.Ynogenericsig .value && NeedsSigCollector .collect(tp)
246
304
247
305
// only refer to type params that will actually make it into the sig, this excludes:
@@ -418,7 +476,7 @@ abstract class Erasure extends AddInterfaces
418
476
)
419
477
}
420
478
}
421
- else jsig(erasure(tp), existentiallyBound, toplevel, primitiveOK)
479
+ else jsig(erasure(sym0, tp), existentiallyBound, toplevel, primitiveOK)
422
480
case PolyType (tparams, restpe) =>
423
481
assert(tparams.nonEmpty)
424
482
def boundSig (bounds : List [Type ]) = {
@@ -447,7 +505,7 @@ abstract class Erasure extends AddInterfaces
447
505
println(" something's wrong: " + sym0+ " :" + sym0.tpe+ " has a bounded wildcard type" )
448
506
jsig(bounds.hi, existentiallyBound, toplevel, primitiveOK)
449
507
case _ =>
450
- val etp = erasure(tp)
508
+ val etp = erasure(sym0, tp)
451
509
if (etp eq tp) throw new UnknownSig
452
510
else jsig(etp)
453
511
}
@@ -465,7 +523,7 @@ abstract class Erasure extends AddInterfaces
465
523
466
524
/** Type reference after erasure */
467
525
def erasedTypeRef (sym : Symbol ): Type =
468
- typeRef(erasure(sym.owner.tpe), sym, List ())
526
+ typeRef(erasure(sym, sym .owner.tpe), sym, List ())
469
527
470
528
/** Remove duplicate references to class Object in a list of parent classes */
471
529
private def removeDoubleObject (tps : List [Type ]): List [Type ] = tps match {
@@ -487,25 +545,25 @@ abstract class Erasure extends AddInterfaces
487
545
if (sym == Object_asInstanceOf )
488
546
sym.info
489
547
else if (sym == Object_isInstanceOf || sym == ArrayClass )
490
- PolyType (sym.info.typeParams, erasure(sym.info.resultType))
548
+ PolyType (sym.info.typeParams, erasure(sym, sym .info.resultType))
491
549
else if (sym.isAbstractType)
492
550
TypeBounds (WildcardType , WildcardType )
493
551
else if (sym.isTerm && sym.owner == ArrayClass ) {
494
552
if (sym.isClassConstructor)
495
553
tp match {
496
- case MethodType (params, TypeRef (pre, sym , args)) =>
497
- MethodType (cloneSymbols(params) map (p => p.setInfo(erasure(p.tpe))),
498
- typeRef(erasure(pre), sym , args))
554
+ case MethodType (params, TypeRef (pre, sym1 , args)) =>
555
+ MethodType (cloneSymbols(params) map (p => p.setInfo(erasure(sym, p.tpe))),
556
+ typeRef(erasure(sym, pre), sym1 , args))
499
557
}
500
558
else if (sym.name == nme.apply)
501
559
tp
502
560
else if (sym.name == nme.update)
503
561
(tp : @ unchecked) match {
504
562
case MethodType (List (index, tvar), restpe) =>
505
- MethodType (List (index.cloneSymbol.setInfo(erasure(index.tpe)), tvar),
563
+ MethodType (List (index.cloneSymbol.setInfo(erasure(sym, index.tpe)), tvar),
506
564
erasedTypeRef(UnitClass ))
507
565
}
508
- else erasure(tp)
566
+ else erasure(sym, tp)
509
567
} else if (
510
568
sym.owner != NoSymbol &&
511
569
sym.owner.owner == ArrayClass &&
@@ -522,7 +580,7 @@ abstract class Erasure extends AddInterfaces
522
580
else
523
581
erasure(tp)
524
582
*/
525
- transformMixinInfo(erasure(tp))
583
+ transformMixinInfo(erasure(sym, tp))
526
584
}
527
585
}
528
586
@@ -903,7 +961,7 @@ abstract class Erasure extends AddInterfaces
903
961
val other = opc.overridden
904
962
// Console.println("bridge? " + member + ":" + member.tpe + member.locationString + " to " + other + ":" + other.tpe + other.locationString)//DEBUG
905
963
if (atPhase(currentRun.explicitouterPhase)(! member.isDeferred)) {
906
- val otpe = erasure(other.tpe)
964
+ val otpe = erasure(owner, other.tpe)
907
965
val bridgeNeeded = atPhase(phase.next) (
908
966
! (other.tpe =:= member.tpe) &&
909
967
! (deconstMap(other.tpe) =:= deconstMap(member.tpe)) &&
@@ -940,7 +998,7 @@ abstract class Erasure extends AddInterfaces
940
998
((fun, vparams) => Apply (fun, vparams map Ident )))
941
999
});
942
1000
if (settings.debug.value)
943
- log(" generating bridge from " + other + " (" + Flags .flagsToString(bridge.flags) + " )" + " :" + otpe + other.locationString + " to " + member + " :" + erasure(member.tpe) + member.locationString + " =\n " + bridgeDef);
1001
+ log(" generating bridge from " + other + " (" + Flags .flagsToString(bridge.flags) + " )" + " :" + otpe + other.locationString + " to " + member + " :" + erasure(owner, member.tpe) + member.locationString + " =\n " + bridgeDef);
944
1002
bridgeDef
945
1003
}
946
1004
} :: bridges
@@ -1004,16 +1062,20 @@ abstract class Erasure extends AddInterfaces
1004
1062
val level = unboundedGenericArrayLevel(arg.tpe)
1005
1063
def isArrayTest (arg : Tree ) =
1006
1064
gen.mkRuntimeCall(" isArray" , List (arg, Literal (Constant (level))))
1065
+
1007
1066
global.typer.typedPos(tree.pos) {
1008
1067
if (level == 1 ) isArrayTest(qual)
1009
- else
1010
- gen.evalOnce(qual, currentOwner, unit) { qual1 =>
1011
- gen.mkAnd(
1012
- Apply (TypeApply (Select (qual1(), fun.symbol),
1013
- List (TypeTree (erasure(arg.tpe)))),
1014
- List ()),
1015
- isArrayTest(qual1()))
1016
- }
1068
+ else gen.evalOnce(qual, currentOwner, unit) { qual1 =>
1069
+ gen.mkAnd(
1070
+ gen.mkMethodCall(
1071
+ qual1(),
1072
+ fun.symbol,
1073
+ List (erasure(fun.symbol, arg.tpe)),
1074
+ Nil
1075
+ ),
1076
+ isArrayTest(qual1())
1077
+ )
1078
+ }
1017
1079
}
1018
1080
case TypeApply (fun, args) if (fun.symbol.owner != AnyClass &&
1019
1081
fun.symbol != Object_asInstanceOf &&
@@ -1030,7 +1092,7 @@ abstract class Erasure extends AddInterfaces
1030
1092
// need to do the cast in adaptMember
1031
1093
treeCopy.Apply (
1032
1094
tree,
1033
- SelectFromArray (qual, name, erasure(qual.tpe)).copyAttrs(fn),
1095
+ SelectFromArray (qual, name, erasure(tree.symbol, qual.tpe)).copyAttrs(fn),
1034
1096
args)
1035
1097
1036
1098
case Apply (fn @ Select (qual, _), Nil ) if interceptedMethods(fn.symbol) =>
@@ -1150,7 +1212,7 @@ abstract class Erasure extends AddInterfaces
1150
1212
1151
1213
case Literal (ct) if ct.tag == ClassTag
1152
1214
&& ct.typeValue.typeSymbol != definitions.UnitClass =>
1153
- treeCopy.Literal (tree, Constant (erasure(ct.typeValue)))
1215
+ treeCopy.Literal (tree, Constant (erasure(NoSymbol , ct.typeValue)))
1154
1216
1155
1217
case _ =>
1156
1218
tree
@@ -1168,10 +1230,10 @@ abstract class Erasure extends AddInterfaces
1168
1230
val tree1 = preErase(tree)
1169
1231
tree1 match {
1170
1232
case EmptyTree | TypeTree () =>
1171
- tree1 setType erasure(tree1.tpe)
1233
+ tree1 setType erasure(NoSymbol , tree1.tpe)
1172
1234
case DefDef (_, _, _, _, tpt, _) =>
1173
1235
val result = super .transform(tree1) setType null
1174
- tpt.tpe = erasure(tree1.symbol.tpe).resultType
1236
+ tpt.tpe = erasure(tree1.symbol, tree1.symbol .tpe).resultType
1175
1237
result
1176
1238
case _ =>
1177
1239
super .transform(tree1) setType null
0 commit comments