Skip to content

Changes in array creation scheme #252

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/dotty/runtime/Arrays.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package dotty.runtime

import scala.reflect.ClassTag

object Arrays {
def newGenericArray[T](length: Int)(implicit tag: ClassTag[T]): Array[T] = tag.newArray(length)
def newRefArray[T](length: Int): Array[T] = ???
def newByteArray(length: Int): Array[Byte] = ???
def newShortArray(length: Int): Array[Short] = ???
def newCharArray(length: Int): Array[Char] = ???
def newIntArray(length: Int): Array[Int] = ???
def newLongArray(length: Int): Array[Long] = ???
def newFloatArray(length: Int): Array[Float] = ???
def newDoubleArray(length: Int): Array[Double] = ???
def newBooleanArray(length: Int): Array[Boolean] = ???
def newUnitArray(length: Int): Array[Unit] = ???
}
22 changes: 18 additions & 4 deletions src/dotty/tools/dotc/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,24 @@ object TypeErasure {
}
}

def isUnboundedGeneric(tp: Type)(implicit ctx: Context) = !(
(tp derivesFrom defn.ObjectClass) ||
tp.classSymbol.isPrimitiveValueClass ||
(tp.typeSymbol is JavaDefined))
/** Is `tp` an abstract type or polymorphic type parameter that has `Any`
* as upper bound and that is not Java defined? Arrays of such types are
* erased to `Object` instead of `ObjectArray`.
*/
def isUnboundedGeneric(tp: Type)(implicit ctx: Context): Boolean = tp match {
case tp: TypeRef =>
tp.symbol.isAbstractType &&
!tp.derivesFrom(defn.ObjectClass) &&
!tp.typeSymbol.is(JavaDefined)
case tp: PolyParam =>
!tp.derivesFrom(defn.ObjectClass) &&
!tp.binder.resultType.isInstanceOf[JavaMethodType]
case tp: TypeProxy => isUnboundedGeneric(tp.underlying)
case tp: AndType => isUnboundedGeneric(tp.tp1) || isUnboundedGeneric(tp.tp2)
case tp: OrType => isUnboundedGeneric(tp.tp1) && isUnboundedGeneric(tp.tp2)
case _ => false
}


/** The erased least upper bound is computed as follows
* - if both argument are arrays, an array of the lub of the element types
Expand Down
15 changes: 14 additions & 1 deletion src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,19 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
case ConstantType(value) => Literal(value)
}

/** A tree representing a `newXYZArray` operation of the right
* kind for the given element type. No type arguments or
* `length` arguments are given.
*/
def newArray(elemType: Type)(implicit ctx: Context) = {
val elemClass = elemType.classSymbol
val kind =
if (TypeErasure.isUnboundedGeneric(elemType)) "Generic"
else if (elemClass.isPrimitiveValueClass) elemClass.name.toString
else "Ref"
ref(defn.DottyArraysModule).select(s"new${kind}Array".toTermName)
}

// ------ Creating typed equivalents of trees that exist only in untyped form -------

/** new C(args), calling the primary constructor of C */
Expand Down Expand Up @@ -678,7 +691,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
Throw(New(defn.ClassCastExceptionClass.typeRef, Nil)) withPos tree.pos
}
}

def applyOverloaded(receiver: Tree, method: TermName, args: List[Tree], targs: List[Type], expectedType: Type, isAnnotConstructor: Boolean = false)(implicit ctx: Context): Tree = {
val typer = ctx.typer
val proto = new FunProtoTyped(args, expectedType, typer)
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ object Contexts {
protected def scope_=(scope: Scope) = _scope = scope
def scope: Scope = _scope

/** The current type assigner ot typer */
/** The current type assigner or typer */
private[this] var _typeAssigner: TypeAssigner = _
protected def typeAssigner_=(typeAssigner: TypeAssigner) = _typeAssigner = typeAssigner
def typeAssigner: TypeAssigner = _typeAssigner
Expand Down
2 changes: 2 additions & 0 deletions src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ class Definitions {
def staticsMethod(name: PreName) = ctx.requiredMethod(ScalaStaticsClass, name)

lazy val DottyPredefModule = ctx.requiredModule("dotty.DottyPredef")
lazy val DottyArraysModule = ctx.requiredModule("dotty.runtime.Arrays")
lazy val NilModule = ctx.requiredModule("scala.collection.immutable.Nil")
lazy val PredefConformsClass = ctx.requiredClass("scala.Predef." + tpnme.Conforms)

Expand All @@ -211,6 +212,7 @@ class Definitions {
lazy val Array_update = ctx.requiredMethod(ArrayClass, nme.update)
lazy val Array_length = ctx.requiredMethod(ArrayClass, nme.length)
lazy val Array_clone = ctx.requiredMethod(ArrayClass, nme.clone_)
lazy val ArrayConstructor = ctx.requiredMethod(ArrayClass, nme.CONSTRUCTOR)
lazy val traversableDropMethod = ctx.requiredMethod(ScalaRuntimeClass, nme.drop)
lazy val uncheckedStableClass: ClassSymbol = ctx.requiredClass("scala.annotation.unchecked.uncheckedStable")

Expand Down
1 change: 0 additions & 1 deletion src/dotty/tools/dotc/core/NameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,6 @@ object NameOps {
case nme.length => nme.primitive.arrayLength
case nme.update => nme.primitive.arrayUpdate
case nme.clone_ => nme.clone_
case nme.CONSTRUCTOR => nme.primitive.arrayConstructor
}

/** If name length exceeds allowable limit, replace part of it by hash */
Expand Down
4 changes: 1 addition & 3 deletions src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,6 @@ object StdNames {
val moduleClass : N = "moduleClass"
val name: N = "name"
val ne: N = "ne"
val newArray: N = "newArray"
val newFreeTerm: N = "newFreeTerm"
val newFreeType: N = "newFreeType"
val newNestedSymbol: N = "newNestedSymbol"
Expand Down Expand Up @@ -691,8 +690,7 @@ object StdNames {
val arrayApply: TermName = "[]apply"
val arrayUpdate: TermName = "[]update"
val arrayLength: TermName = "[]length"
val arrayConstructor: TermName = "[]<init>"
val names: Set[Name] = Set(arrayApply, arrayUpdate, arrayLength, arrayConstructor)
val names: Set[Name] = Set(arrayApply, arrayUpdate, arrayLength)
}

def isPrimitiveName(name: Name) = primitive.names.contains(name)
Expand Down
11 changes: 10 additions & 1 deletion src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,16 @@ trait Applications extends Compatibility { self: Typer =>
checkBounds(typedArgs, pt)
case _ =>
}
assignType(cpy.TypeApply(tree)(typedFn, typedArgs), typedFn, typedArgs)
val res = assignType(cpy.TypeApply(tree)(typedFn, typedArgs), typedFn, typedArgs)
if (res.symbol == defn.ArrayConstructor) {
val defn.ArrayType(elemType) = res.tpe.widen.resultType
val newArr = tpd.newArray(elemType).withPos(tree.pos)
newArr.tpe.widen match {
case _: PolyType => newArr.appliedToTypeTrees(typedArgs)
case _ => newArr
}
}
else res
}

def typedUnApply(tree: untpd.Apply, selType: Type)(implicit ctx: Context): Tree = track("typedUnApply") {
Expand Down
7 changes: 7 additions & 0 deletions tests/pos/new-array.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
object Test {
val w = new Array[String](10)
val x = new Array[Int](10)
def f[T: reflect.ClassTag] = new Array[T](10)
val y = new Array[Any](10)
val z = new Array[Unit](10)
}