Skip to content

Commit 969d2f1

Browse files
committed
Fix CCE in code generated by Array.apply[T] optimization
1 parent f48a3d5 commit 969d2f1

File tree

5 files changed

+44
-13
lines changed

5 files changed

+44
-13
lines changed

src/compiler/scala/tools/nsc/transform/CleanUp.scala

+18-13
Original file line numberDiff line numberDiff line change
@@ -486,21 +486,26 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL {
486486
// with just `ArrayValue(...).$asInstanceOf[...]`
487487
//
488488
// See scala/bug#6611; we must *only* do this for literal vararg arrays.
489-
case Apply(appMeth, Apply(wrapRefArrayMeth, (arg @ StripCast(ArrayValue(_, _))) :: Nil) :: _ :: Nil)
490-
if wrapRefArrayMeth.symbol == currentRun.runDefinitions.Predef_wrapRefArray && appMeth.symbol == ArrayModule_genericApply =>
491-
super.transform(arg)
492-
case Apply(appMeth, (ap1 @ Apply(wrapRefArrayMeth, (arg @ StripCast(ArrayValue(elemtpt, elems))) :: Nil)) :: classTagEvidence :: Nil)
493-
if wrapRefArrayMeth.symbol == currentRun.runDefinitions.Predef_genericWrapRefArray && appMeth.symbol == ArrayModule_genericApply &&
489+
case Apply(appMeth, Apply(wrapRefArrayMeth, (arg @ StripCast(ArrayValue(elemtpt, elems))) :: Nil) :: classTagEvidence :: Nil)
490+
if (wrapRefArrayMeth.symbol == currentRun.runDefinitions.Predef_genericWrapRefArray || wrapRefArrayMeth.symbol == currentRun.runDefinitions.Predef_wrapRefArray) && appMeth.symbol == ArrayModule_genericApply &&
494491
!elemtpt.tpe.typeSymbol.isBottomClass =>
495-
val arr = localTyper.typedPos(tree.pos)(gen.mkMethodCall(classTagEvidence, definitions.ClassTagClass.info.decl(nme.newArray), Nil, Literal(Constant(elems.size)) :: Nil))
496-
localTyper.typedPos(tree.pos) {
497-
gen.evalOnce(arr, currentOwner, unit) { arr =>
498-
val stats = mutable.ListBuffer[Tree]()
499-
foreachWithIndex(elems) { (elem, i) =>
500-
stats += gen.mkMethodCall(gen.mkCast(arr(), definitions.arrayType(elemtpt.tpe)), definitions.Array_update, Nil, Literal(Constant(i)) :: elem :: Nil)
492+
classTagEvidence.attachments.get[analyzer.MacroExpansionAttachment] match {
493+
case Some(att) if att.expandee.symbol.name == nme.materializeClassTag && tree.isInstanceOf[ApplyToImplicitArgs] =>
494+
super.transform(arg)
495+
case None =>
496+
localTyper.typedPos(tree.pos) {
497+
gen.evalOnce(classTagEvidence, currentOwner, unit) { ev =>
498+
val arr = localTyper.typedPos(tree.pos)(gen.mkMethodCall(classTagEvidence, definitions.ClassTagClass.info.decl(nme.newArray), Nil, Literal(Constant(elems.size)) :: Nil))
499+
gen.evalOnce(arr, currentOwner, unit) { arr =>
500+
val stats = mutable.ListBuffer[Tree]()
501+
foreachWithIndex(elems) { (elem, i) =>
502+
stats += gen.mkMethodCall(gen.mkAttributedRef(definitions.ScalaRunTimeModule), currentRun.runDefinitions.arrayUpdateMethod,
503+
Nil, arr() :: Literal(Constant(i)) :: elem :: Nil)
504+
}
505+
super.transform(Block(stats.toList, arr()))
506+
}
507+
}
501508
}
502-
Block(stats.toList, arr())
503-
}
504509
}
505510
case Apply(appMeth, elem0 :: Apply(wrapArrayMeth, (rest @ ArrayValue(elemtpt, _)) :: Nil) :: Nil)
506511
if wrapArrayMeth.symbol == Predef_wrapArray(elemtpt.tpe) && appMeth.symbol == ArrayModule_apply(elemtpt.tpe) =>

test/files/instrumented/t11882a.check

+2
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ Method call statistics:
33
1 OptimusSeq$.unsafeFromAnyArray1([Ljava/lang/Object;)LOptimusSeq;
44
1 Test$.doIt$1()LOptimusSeq;
55
1 scala/reflect/ClassTag$.AnyRef()Lscala/reflect/ClassTag;
6+
1 scala/reflect/ManifestFactory$ObjectManifest.newArray(I)Ljava/lang/Object;
7+
1 scala/reflect/ManifestFactory$ObjectManifest.newArray(I)[Ljava/lang/Object;

test/files/instrumented/t11882c.check

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Method call statistics:
2+
1 Test$.doIt$1()[Ljava/lang/String;

test/files/instrumented/t11882c.scala

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import scala.reflect.ClassTag
2+
import scala.tools.partest.instrumented._
3+
import scala.tools.partest.instrumented.Instrumentation._
4+
5+
object Test {
6+
def main(args: Array[String]): Unit = {
7+
def doIt = Array[String](null, null, null, null)
8+
doIt
9+
startProfiling()
10+
doIt
11+
stopProfiling()
12+
printStatistics()
13+
}
14+
}
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
object Test {
2+
def test[T <: AnyRef: reflect.ClassTag](t: T) = Array(t)
3+
def main(args: Array[String]): Unit = {
4+
// was: java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
5+
val x: Array[String] = test[String]("x")
6+
assert(x(0) == "x")
7+
}
8+
}

0 commit comments

Comments
 (0)