diff options
author | Dmitry Petrashko <dark@d-d.me> | 2014-12-01 10:59:32 +0100 |
---|---|---|
committer | Dmitry Petrashko <dark@d-d.me> | 2014-12-01 10:59:32 +0100 |
commit | 5ff3d0fe4370c525c8d29f6483892d0bf59cd4c0 (patch) | |
tree | daca896cc957412dc335d519f215bff5e36ccadd /src | |
parent | 745c8523ecdd9271b70447332cc2880a3f3ef19a (diff) | |
parent | 91c61e4694097971b9a0c139048b7239d0f05588 (diff) | |
download | dotty-5ff3d0fe4370c525c8d29f6483892d0bf59cd4c0.tar.gz dotty-5ff3d0fe4370c525c8d29f6483892d0bf59cd4c0.tar.bz2 dotty-5ff3d0fe4370c525c8d29f6483892d0bf59cd4c0.zip |
Merge pull request #254 from dotty-staging/fix/newArray-v2
Fix array creation v2
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/runtime/Arrays.scala | 47 | ||||
-rw-r--r-- | src/dotty/tools/dotc/TypeErasure.scala | 24 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/tpd.scala | 20 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Contexts.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Definitions.scala | 7 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/NameOps.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/StdNames.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Erasure.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 11 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/TypeAssigner.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 3 |
11 files changed, 107 insertions, 15 deletions
diff --git a/src/dotty/runtime/Arrays.scala b/src/dotty/runtime/Arrays.scala new file mode 100644 index 000000000..e7f819df8 --- /dev/null +++ b/src/dotty/runtime/Arrays.scala @@ -0,0 +1,47 @@ +package dotty.runtime + +import scala.reflect.ClassTag + +/** All but the first operation should be short-circuited and implemented specially by + * the backend. + */ +object Arrays { + + /** Creates an array of some element type determined by the given `ClassTag` + * argument. The erased type of applications of this method is `Object`. + */ + def newGenericArray[T](length: Int)(implicit tag: ClassTag[T]): Array[T] = + tag.newArray(length) + + /** Create an array of type T. T must be of form Array[E], with + * E being a reference type. + */ + 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] = ??? +}
\ No newline at end of file diff --git a/src/dotty/tools/dotc/TypeErasure.scala b/src/dotty/tools/dotc/TypeErasure.scala index 1786e2e29..7920667e7 100644 --- a/src/dotty/tools/dotc/TypeErasure.scala +++ b/src/dotty/tools/dotc/TypeErasure.scala @@ -142,7 +142,7 @@ object TypeErasure { tp.derivedPolyType( tp.paramNames, tp.paramNames map (Function.const(TypeBounds.upper(defn.ObjectType))), tp.resultType) - if ((sym eq defn.Any_asInstanceOf) || (sym eq defn.Any_isInstanceOf)) eraseParamBounds(sym.info.asInstanceOf[PolyType]) + if (defn.isPolymorphicAfterErasure(sym)) eraseParamBounds(sym.info.asInstanceOf[PolyType]) else if (sym.isAbstractType) TypeAlias(WildcardType) else if (sym.isConstructor) outer.addParam(sym.owner.asClass, erase(tp)(erasureCtx)) else eraseInfo(tp)(erasureCtx) match { @@ -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 diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 98609f9f1..98cc10a22 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -298,6 +298,24 @@ 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 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.ArrayType(elemType)).withPos(typeArg.pos) :: Nil) + } + // ------ Creating typed equivalents of trees that exist only in untyped form ------- /** new C(args), calling the primary constructor of C */ @@ -678,7 +696,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) diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 6293d18d2..6824cc36c 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -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 diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index d78e09418..20dd899f1 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -193,6 +193,10 @@ 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") + + def newRefArrayMethod = ctx.requiredMethod(DottyArraysModule.moduleClass.asClass, "newRefArray") + lazy val NilModule = ctx.requiredModule("scala.collection.immutable.Nil") lazy val PredefConformsClass = ctx.requiredClass("scala.Predef." + tpnme.Conforms) @@ -211,6 +215,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") @@ -428,6 +433,8 @@ class Definitions { lazy val PhantomClasses = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass) + lazy val isPolymorphicAfterErasure = Set[Symbol](Any_isInstanceOf, Any_asInstanceOf, newRefArrayMethod) + lazy val RootImports = List[Symbol](JavaLangPackageVal, ScalaPackageVal, ScalaPredefModule, DottyPredefModule) lazy val overriddenBySynthetic = Set[Symbol](Any_equals, Any_hashCode, Any_toString, Product_canEqual) diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala index bc15f6a06..a6b40fe66 100644 --- a/src/dotty/tools/dotc/core/NameOps.scala +++ b/src/dotty/tools/dotc/core/NameOps.scala @@ -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 */ diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala index 8393eb56f..959e9cb84 100644 --- a/src/dotty/tools/dotc/core/StdNames.scala +++ b/src/dotty/tools/dotc/core/StdNames.scala @@ -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" @@ -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) diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala index 0a34b9e7c..23f1aada9 100644 --- a/src/dotty/tools/dotc/transform/Erasure.scala +++ b/src/dotty/tools/dotc/transform/Erasure.scala @@ -89,7 +89,7 @@ class Erasure extends Phase with DenotTransformer { thisTransformer => */ def assertErased(tree: tpd.Tree)(implicit ctx: Context): Unit = { assertErased(tree.typeOpt, tree) - if (!(tree.symbol == defn.Any_isInstanceOf || tree.symbol == defn.Any_asInstanceOf)) + if (!defn.isPolymorphicAfterErasure(tree.symbol)) assertErased(tree.typeOpt.widen, tree) if (ctx.mode.isExpr) tree.tpe match { diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index ba770cf2c..fe45beb04 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -596,7 +596,16 @@ trait Applications extends Compatibility { self: Typer => checkBounds(typedArgs, pt) case _ => } - assignType(cpy.TypeApply(tree)(typedFn, typedArgs), typedFn, typedArgs) + convertNewArray( + assignType(cpy.TypeApply(tree)(typedFn, typedArgs), typedFn, typedArgs)) + } + + /** Rewrite `new Array[T]` trees to calls of newXYZArray methods. */ + def convertNewArray(tree: Tree)(implicit ctx: Context): Tree = tree match { + case TypeApply(tycon, targs) if tycon.symbol == defn.ArrayConstructor => + newArray(targs.head, tree.pos) + case _ => + tree } def typedUnApply(tree: untpd.Apply, selType: Type)(implicit ctx: Context): Tree = track("typedUnApply") { diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index 6c5e48edb..41dc3c3f7 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -208,7 +208,6 @@ trait TypeAssigner { case p.arrayApply => MethodType(defn.IntType :: Nil, arrayElemType) case p.arrayUpdate => MethodType(defn.IntType :: arrayElemType :: Nil, defn.UnitType) case p.arrayLength => MethodType(Nil, defn.IntType) - case p.arrayConstructor => MethodType(defn.IntType :: Nil, qualType) case nme.clone_ if qualType.isInstanceOf[JavaArrayType] => MethodType(Nil, qualType) case _ => accessibleSelectionType(tree, qual) } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 7d4e8d132..f6027165b 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -1326,7 +1326,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (pt.isInstanceOf[PolyProto]) tree else { val (_, tvars) = constrained(poly, tree) - adaptInterpolated(tree appliedToTypes tvars, pt, original) + convertNewArray( + adaptInterpolated(tree.appliedToTypes(tvars), pt, original)) } case wtp => pt match { |