aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDmitry Petrashko <dark@d-d.me>2016-04-18 15:56:09 +0200
committerDmitry Petrashko <dark@d-d.me>2016-04-18 15:56:09 +0200
commit247e91365f06cd482bf5fc456bd643d89acca157 (patch)
tree30ea8adc3cf6d1e0f20edb3aedb7c7ffa774ee2c /src
parent8c9a3f7ce5fa7548f9611dc2a14900a5bd42c105 (diff)
parent5399fbed6d33dca132ca27314f2eba414aea4415 (diff)
downloaddotty-247e91365f06cd482bf5fc456bd643d89acca157.tar.gz
dotty-247e91365f06cd482bf5fc456bd643d89acca157.tar.bz2
dotty-247e91365f06cd482bf5fc456bd643d89acca157.zip
Merge pull request #1188 from dotty-staging/remove-newarray-magic
Fix #1167: Reduce the magic in Arrays.newRefArray. Implement multidimensional arrays
Diffstat (limited to 'src')
-rw-r--r--src/dotty/runtime/Arrays.scala35
-rw-r--r--src/dotty/tools/backend/jvm/DottyBackendInterface.scala9
-rw-r--r--src/dotty/tools/backend/sjs/JSCodeGen.scala44
-rw-r--r--src/dotty/tools/backend/sjs/JSPrimitives.scala12
-rw-r--r--src/dotty/tools/dotc/Compiler.scala3
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala31
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala9
-rw-r--r--src/dotty/tools/dotc/transform/ArrayConstructors.scala57
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala23
-rw-r--r--src/dotty/tools/dotc/transform/TreeChecker.scala3
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala21
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala2
12 files changed, 133 insertions, 116 deletions
diff --git a/src/dotty/runtime/Arrays.scala b/src/dotty/runtime/Arrays.scala
index 4469dced7..9ec5512ad 100644
--- a/src/dotty/runtime/Arrays.scala
+++ b/src/dotty/runtime/Arrays.scala
@@ -2,6 +2,8 @@ package dotty.runtime
import scala.reflect.ClassTag
+import java.lang.{reflect => jlr}
+
/** All but the first two operations should be short-circuited and implemented specially by
* the backend.
*/
@@ -22,35 +24,8 @@ object Arrays {
arr
}
- /** Create an array of type T. T must be of form Array[E], with
- * E being a reference type.
+ /** Create an array of a reference type T.
*/
- def newRefArray[T](length: Int): T = ???
-
- /** Create a Byte[] array */
- def newByteArray(length: Int): Array[Byte] = ???
-
- /** Create a Short[] array */
- def newShortArray(length: Int): Array[Short] = ???
-
- /** Create a Char[] array */
- def newCharArray(length: Int): Array[Char] = ???
-
- /** Create an Int[] array */
- def newIntArray(length: Int): Array[Int] = ???
-
- /** Create a Long[] array */
- def newLongArray(length: Int): Array[Long] = ???
-
- /** Create a Float[] array */
- def newFloatArray(length: Int): Array[Float] = ???
-
- /** Create a Double[] array */
- def newDoubleArray(length: Int): Array[Double] = ???
-
- /** Create a Boolean[] array */
- def newBooleanArray(length: Int): Array[Boolean] = ???
-
- /** Create a scala.runtime.BoxedUnit[] array */
- def newUnitArray(length: Int): Array[Unit] = ???
+ def newArray[Arr](componentType: Class[_], returnType: Class[Arr], dimensions: Array[Int]): Arr =
+ jlr.Array.newInstance(componentType, dimensions: _*).asInstanceOf[Arr]
}
diff --git a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
index ef8e4997f..a64ce5900 100644
--- a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
+++ b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
@@ -153,15 +153,8 @@ class DottyBackendInterface(outputDirectory: AbstractFile)(implicit ctx: Context
}.toMap
def unboxMethods: Map[Symbol, Symbol] = defn.ScalaValueClasses().map(x => (x, Erasure.Boxing.unboxMethod(x.asClass))).toMap
- private val mkArrayNames: Set[Name] = Set("Byte", "Float", "Char", "Double", "Boolean", "Unit", "Long", "Int", "Short", "Ref").map{ x=>
- ("new" + x + "Array").toTermName
- }
-
- val dottyArraysModuleClass = toDenot(defn.DottyArraysModule).moduleClass.asClass
-
-
override def isSyntheticArrayConstructor(s: Symbol) = {
- (toDenot(s).maybeOwner eq dottyArraysModuleClass) && mkArrayNames.contains(s.name)
+ s eq defn.newArrayMethod
}
def isBox(sym: Symbol): Boolean = Erasure.Boxing.isBox(sym)
diff --git a/src/dotty/tools/backend/sjs/JSCodeGen.scala b/src/dotty/tools/backend/sjs/JSCodeGen.scala
index ec75a1c4d..401e01784 100644
--- a/src/dotty/tools/backend/sjs/JSCodeGen.scala
+++ b/src/dotty/tools/backend/sjs/JSCodeGen.scala
@@ -718,9 +718,9 @@ class JSCodeGen()(implicit ctx: Context) {
if (sym.is(Module)) {
assert(!sym.is(Package), "Cannot use package as value: " + tree)
genLoadModule(sym)
- } else /*if (sym.isStaticMember) {
- genStaticMember(sym)
- } else if (paramAccessorLocals contains sym) {
+ } else if (sym.is(JavaStatic)) {
+ genLoadStaticField(sym)
+ } else /*if (paramAccessorLocals contains sym) {
paramAccessorLocals(sym).ref
} else if (isScalaJSDefinedJSClass(sym.owner)) {
val genQual = genExpr(qualifier)
@@ -1036,8 +1036,6 @@ class JSCodeGen()(implicit ctx: Context) {
genStringConcat(tree, receiver, args)
else if (code == HASH)
genScalaHash(tree, receiver)
- else if (isArrayNew(code))
- genArrayNew(tree, code)
else if (isArrayOp(code))
genArrayOp(tree, code)
else if (code == SYNCHRONIZED)
@@ -1409,24 +1407,6 @@ class JSCodeGen()(implicit ctx: Context) {
List(genExpr(receiver)))
}
- /** Gen JS code for a new array operation. */
- private def genArrayNew(tree: Tree, code: Int): js.Tree = {
- import scala.tools.nsc.backend.ScalaPrimitives._
-
- implicit val pos: Position = tree.pos
-
- val Apply(fun, args) = tree
- val genLength = genExpr(args.head)
-
- toIRType(tree.tpe) match {
- case arrayType: jstpe.ArrayType =>
- js.NewArray(arrayType, List(genLength))
-
- case irTpe =>
- throw new FatalError(s"ArrayNew $tree must have an array type but was $irTpe")
- }
- }
-
/** Gen JS code for an array operation (get, set or length) */
private def genArrayOp(tree: Tree, code: Int): js.Tree = {
import scala.tools.nsc.backend.ScalaPrimitives._
@@ -2328,6 +2308,24 @@ class JSCodeGen()(implicit ctx: Context) {
}
}
+ /** Gen JS code for loading a Java static field.
+ */
+ private def genLoadStaticField(sym: Symbol)(implicit pos: Position): js.Tree = {
+ /* Actually, there is no static member in Scala.js. If we come here, that
+ * is because we found the symbol in a Java-emitted .class in the
+ * classpath. But the corresponding implementation in Scala.js will
+ * actually be a val in the companion module.
+ */
+
+ if (sym == defn.BoxedUnit_UNIT) {
+ js.Undefined()
+ } else {
+ val instance = genLoadModule(sym.owner)
+ val method = encodeStaticMemberSym(sym)
+ js.Apply(instance, method, Nil)(toIRType(sym.info))
+ }
+ }
+
/** Gen JS code for loading a module.
*
* Can be given either the module symbol, or its module class symbol.
diff --git a/src/dotty/tools/backend/sjs/JSPrimitives.scala b/src/dotty/tools/backend/sjs/JSPrimitives.scala
index 52b5dc4b9..6c3c5715c 100644
--- a/src/dotty/tools/backend/sjs/JSPrimitives.scala
+++ b/src/dotty/tools/backend/sjs/JSPrimitives.scala
@@ -80,18 +80,6 @@ class JSPrimitives(ctx: Context) extends DottyPrimitives(ctx) {
val jsdefn = JSDefinitions.jsdefn
- // For some reason, the JVM primitive set does not register those
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newBooleanArray")), NEW_ZARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newByteArray")), NEW_BARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newShortArray")), NEW_SARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newCharArray")), NEW_CARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newIntArray")), NEW_IARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newLongArray")), NEW_LARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newFloatArray")), NEW_FARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newDoubleArray")), NEW_DARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newRefArray")), NEW_OARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newUnitArray")), NEW_OARRAY)
-
addPrimitive(defn.Any_getClass, GETCLASS)
for (i <- 0 to 22)
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index fe48ac30e..b63e0236d 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -66,7 +66,8 @@ class Compiler {
new Getters, // Replace non-private vals and vars with getter defs (fields are added later)
new ElimByName, // Expand by-name parameters and arguments
new AugmentScala2Traits, // Expand traits defined in Scala 2.11 to simulate old-style rewritings
- new ResolveSuper), // Implement super accessors and add forwarders to trait methods
+ new ResolveSuper, // Implement super accessors and add forwarders to trait methods
+ new ArrayConstructors), // Intercept creation of (non-generic) arrays and intrinsify.
List(new Erasure), // Rewrite types to JVM model, erasing all type parameters, abstract types and refinements.
List(new ElimErasedValueType, // Expand erased value types to their underlying implmementation types
new VCElideAllocations, // Peep-hole optimization to eliminate unnecessary value class allocations
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index 8d21953ae..5e5c842a8 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -125,8 +125,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def SeqLiteral(elems: List[Tree], elemtpt: Tree)(implicit ctx: Context): SeqLiteral =
ta.assignType(untpd.SeqLiteral(elems, elemtpt), elems, elemtpt)
- def JavaSeqLiteral(elems: List[Tree], elemtpt: Tree)(implicit ctx: Context): SeqLiteral =
- ta.assignType(new untpd.JavaSeqLiteral(elems, elemtpt), elems, elemtpt)
+ def JavaSeqLiteral(elems: List[Tree], elemtpt: Tree)(implicit ctx: Context): JavaSeqLiteral =
+ ta.assignType(new untpd.JavaSeqLiteral(elems, elemtpt), elems, elemtpt).asInstanceOf[JavaSeqLiteral]
def TypeTree(original: Tree)(implicit ctx: Context): TypeTree =
TypeTree(original.tpe, original)
@@ -362,18 +362,16 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
* kind for the given element type in `typeArg`. No type arguments or
* `length` arguments are given.
*/
- def newArray(typeArg: Tree, pos: Position)(implicit ctx: Context): Tree = {
- val elemType = typeArg.tpe
- val elemClass = elemType.classSymbol
- def newArr(kind: String) =
- ref(defn.DottyArraysModule).select(s"new${kind}Array".toTermName).withPos(pos)
- if (TypeErasure.isUnboundedGeneric(elemType))
- newArr("Generic").appliedToTypeTrees(typeArg :: Nil)
- else if (elemClass.isPrimitiveValueClass)
- newArr(elemClass.name.toString)
- else
- newArr("Ref").appliedToTypeTrees(
- TypeTree(defn.ArrayOf(elemType)).withPos(typeArg.pos) :: Nil)
+ def newArray(elemTpe: Type, returnTpe: Type, pos: Position, dims: JavaSeqLiteral)(implicit ctx: Context): Tree = {
+ val elemClass = elemTpe.classSymbol
+ def newArr =
+ ref(defn.DottyArraysModule).select(defn.newArrayMethod).withPos(pos)
+
+ if (!ctx.erasedTypes) {
+ assert(!TypeErasure.isUnboundedGeneric(elemTpe)) //needs to be done during typer. See Applications.convertNewGenericArray
+ newArr.appliedToTypeTrees(TypeTree(returnTpe) :: Nil).appliedToArgs(clsOf(elemTpe) :: clsOf(returnTpe) :: dims :: Nil).withPos(pos)
+ } else // after erasure
+ newArr.appliedToArgs(clsOf(elemTpe) :: clsOf(returnTpe) :: dims :: Nil).withPos(pos)
}
// ------ Creating typed equivalents of trees that exist only in untyped form -------
@@ -835,7 +833,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
case tpnme.Float => TYPE(defn.BoxedFloatModule)
case tpnme.Double => TYPE(defn.BoxedDoubleModule)
case tpnme.Unit => TYPE(defn.BoxedUnitModule)
- case _ => Literal(Constant(TypeErasure.erasure(tp)))
+ case _ =>
+ if(ctx.erasedTypes || !tp.derivesFrom(defn.ArrayClass))
+ Literal(Constant(TypeErasure.erasure(tp)))
+ else Literal(Constant(tp))
}
}
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 6625cff3f..5376ed591 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -246,8 +246,8 @@ class Definitions {
def DottyPredefModule(implicit ctx: Context) = DottyPredefModuleRef.symbol
lazy val DottyArraysModuleRef = ctx.requiredModuleRef("dotty.runtime.Arrays")
def DottyArraysModule(implicit ctx: Context) = DottyArraysModuleRef.symbol
-
- def newRefArrayMethod(implicit ctx: Context) = DottyArraysModule.requiredMethod("newRefArray")
+ def newGenericArrayMethod(implicit ctx: Context) = DottyArraysModule.requiredMethod("newGenericArray")
+ def newArrayMethod(implicit ctx: Context) = DottyArraysModule.requiredMethod("newArray")
lazy val NilModuleRef = ctx.requiredModuleRef("scala.collection.immutable.Nil")
def NilModule(implicit ctx: Context) = NilModuleRef.symbol
@@ -279,6 +279,9 @@ class Definitions {
def Array_clone(implicit ctx: Context) = Array_cloneR.symbol
lazy val ArrayConstructorR = ArrayClass.requiredMethodRef(nme.CONSTRUCTOR)
def ArrayConstructor(implicit ctx: Context) = ArrayConstructorR.symbol
+ lazy val ArrayModuleType = ctx.requiredModuleRef("scala.Array")
+ def ArrayModule(implicit ctx: Context) = ArrayModuleType.symbol.moduleClass.asClass
+
lazy val UnitType: TypeRef = valueTypeRef("scala.Unit", BoxedUnitType, java.lang.Void.TYPE, UnitEnc)
def UnitClass(implicit ctx: Context) = UnitType.symbol.asClass
@@ -622,7 +625,7 @@ class Definitions {
lazy val PhantomClasses = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass)
def isPolymorphicAfterErasure(sym: Symbol) =
- (sym eq Any_isInstanceOf) || (sym eq Any_asInstanceOf) || (sym eq newRefArrayMethod)
+ (sym eq Any_isInstanceOf) || (sym eq Any_asInstanceOf)
def isTupleType(tp: Type)(implicit ctx: Context) = {
val arity = tp.dealias.argInfos.length
diff --git a/src/dotty/tools/dotc/transform/ArrayConstructors.scala b/src/dotty/tools/dotc/transform/ArrayConstructors.scala
new file mode 100644
index 000000000..ec3bfa47f
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/ArrayConstructors.scala
@@ -0,0 +1,57 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import TreeTransforms._
+import Contexts.Context
+import Flags._
+import SymUtils._
+import Symbols._
+import SymDenotations._
+import Types._
+import Decorators._
+import DenotTransformers._
+import StdNames._
+import NameOps._
+import ast.Trees._
+import dotty.tools.dotc.ast.tpd
+import util.Positions._
+import Names._
+
+import collection.mutable
+import ResolveSuper._
+
+import scala.collection.immutable.::
+
+
+/** This phase rewrites calls to array constructors to newArray method in Dotty.runtime.Arrays module.
+ *
+ * It assummes that generic arrays have already been handled by typer(see Applications.convertNewGenericArray).
+ * Additionally it optimizes calls to scala.Array.ofDim functions by replacing them with calls to newArray with specific dimensions
+ */
+class ArrayConstructors extends MiniPhaseTransform { thisTransform =>
+ import ast.tpd._
+
+ override def phaseName: String = "arrayConstructors"
+
+ override def transformApply(tree: tpd.Apply)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ def rewrite(elemType: Type, dims: List[Tree]) =
+ tpd.newArray(elemType, tree.tpe, tree.pos, JavaSeqLiteral(dims, TypeTree(defn.IntClass.typeRef)))
+
+ if (tree.fun.symbol eq defn.ArrayConstructor) {
+ val TypeApply(tycon, targ :: Nil) = tree.fun
+ rewrite(targ.tpe, tree.args)
+ } else if ((tree.fun.symbol.maybeOwner eq defn.ArrayModule) && (tree.fun.symbol.name eq nme.ofDim) && !tree.tpe.isInstanceOf[MethodicType]) {
+
+ tree.fun match {
+ case Apply(TypeApply(t: Ident, targ), dims) if !TypeErasure.isUnboundedGeneric(targ.head.tpe) =>
+ rewrite(targ.head.tpe, dims)
+ case Apply(TypeApply(t: Select, targ), dims) if !TypeErasure.isUnboundedGeneric(targ.head.tpe) =>
+ Block(t.qualifier :: Nil, rewrite(targ.head.tpe, dims))
+ case _ => tree
+ }
+
+ } else tree
+ }
+}
+
diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala
index 7acb14af4..0b3a07f65 100644
--- a/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/transform/Erasure.scala
@@ -21,7 +21,7 @@ import core.Decorators._
import dotty.tools.dotc.ast.{Trees, tpd, untpd}
import ast.Trees._
import scala.collection.mutable.ListBuffer
-import dotty.tools.dotc.core.Flags
+import dotty.tools.dotc.core.{Constants, Flags}
import ValueClasses._
import TypeUtils._
import ExplicitOuter._
@@ -299,8 +299,9 @@ object Erasure extends TypeTestsCasts{
assignType(untpd.cpy.Typed(tree)(expr1, tpt1), tpt1)
}
- override def typedLiteral(tree: untpd.Literal)(implicit ctc: Context): Literal =
+ override def typedLiteral(tree: untpd.Literal)(implicit ctx: Context): Literal =
if (tree.typeOpt.isRef(defn.UnitClass)) tree.withType(tree.typeOpt)
+ else if (tree.const.tag == Constants.ClazzTag) Literal(Constant(erasure(tree.const.typeValue)))
else super.typedLiteral(tree)
/** Type check select nodes, applying the following rewritings exhaustively
@@ -467,28 +468,18 @@ object Erasure extends TypeTestsCasts{
tpt = untpd.TypedSplice(TypeTree(sym.info).withPos(vdef.tpt.pos))), sym)
override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = {
- var effectiveSym = sym
- if (sym == defn.newRefArrayMethod) {
- // newRefArray is treated specially: It's the only source-defined method
- // that has a polymorphic type after erasure. But treating its (dummy) definition
- // with a polymorphic type at and after erasure is an awkward special case.
- // We therefore rewrite the method definition with a new Symbol of type
- // (length: Int)Object
- val MethodType(pnames, ptypes) = sym.info.resultType
- effectiveSym = sym.copy(info = MethodType(pnames, ptypes, defn.ObjectType))
- }
val restpe =
- if (effectiveSym.isConstructor) defn.UnitType
- else effectiveSym.info.resultType
+ if (sym.isConstructor) defn.UnitType
+ else sym.info.resultType
val ddef1 = untpd.cpy.DefDef(ddef)(
tparams = Nil,
- vparamss = (outer.paramDefs(effectiveSym) ::: ddef.vparamss.flatten) :: Nil,
+ vparamss = (outer.paramDefs(sym) ::: ddef.vparamss.flatten) :: Nil,
tpt = untpd.TypedSplice(TypeTree(restpe).withPos(ddef.tpt.pos)),
rhs = ddef.rhs match {
case id @ Ident(nme.WILDCARD) => untpd.TypedSplice(id.withType(restpe))
case _ => ddef.rhs
})
- super.typedDefDef(ddef1, effectiveSym)
+ super.typedDefDef(ddef1, sym)
}
/** After erasure, we may have to replace the closure method by a bridge.
diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala
index 007869e06..f11789c9a 100644
--- a/src/dotty/tools/dotc/transform/TreeChecker.scala
+++ b/src/dotty/tools/dotc/transform/TreeChecker.scala
@@ -359,8 +359,7 @@ class TreeChecker extends Phase with SymTransformer {
def isNonMagicalMethod(x: Symbol) =
x.is(Method) &&
!x.isCompanionMethod &&
- !x.isValueClassConvertMethod &&
- x != defn.newRefArrayMethod
+ !x.isValueClassConvertMethod
val symbolsNotDefined = cls.classInfo.decls.toSet.filter(isNonMagicalMethod) -- impl.body.map(_.symbol) - constr.symbol
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index ec2508580..37a9f0ba0 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -560,7 +560,7 @@ trait Applications extends Compatibility { self: Typer =>
if (proto.argsAreTyped) new ApplyToTyped(tree, fun1, funRef, proto.typedArgs, pt)
else new ApplyToUntyped(tree, fun1, funRef, proto, pt)(argCtx(tree))
val result = app.result
- convertNewArray(ConstFold(result))
+ convertNewGenericArray(ConstFold(result))
} { (failedVal, failedState) =>
val fun2 = tryInsertImplicitOnQualifier(fun1, proto)
if (fun1 eq fun2) {
@@ -636,11 +636,22 @@ trait Applications extends Compatibility { self: Typer =>
def adaptTypeArg(tree: tpd.Tree, bound: Type)(implicit ctx: Context): tpd.Tree =
tree.withType(tree.tpe.etaExpandIfHK(bound))
- /** Rewrite `new Array[T](....)` trees to calls of newXYZArray methods. */
- def convertNewArray(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
- case Apply(TypeApply(tycon, targ :: Nil), args) if tycon.symbol == defn.ArrayConstructor =>
+ /** Rewrite `new Array[T](....)` if T is an unbounded generic to calls to newGenericArray.
+ * It is performed during typer as creation of generic arrays needs a classTag.
+ * we rely on implicit search to find one.
+ */
+ def convertNewGenericArray(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
+ case Apply(TypeApply(tycon, targs@(targ :: Nil)), args) if tycon.symbol == defn.ArrayConstructor =>
fullyDefinedType(tree.tpe, "array", tree.pos)
- tpd.cpy.Apply(tree)(newArray(targ, tree.pos), args)
+
+ def newGenericArrayCall =
+ ref(defn.DottyArraysModule)
+ .select(defn.newGenericArrayMethod).withPos(tree.pos)
+ .appliedToTypeTrees(targs).appliedToArgs(args)
+
+ if (TypeErasure.isUnboundedGeneric(targ.tpe))
+ newGenericArrayCall
+ else tree
case _ =>
tree
}
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 2575dbec2..53296f9c9 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -1684,7 +1684,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
case _ => Nil
}
if (typeArgs.isEmpty) typeArgs = constrained(poly, tree)._2
- convertNewArray(
+ convertNewGenericArray(
adaptInterpolated(tree.appliedToTypes(typeArgs), pt, original))
}
case wtp =>