Permalink
Browse files

removes array tags

Before 2.10 we had a notion of ClassManifest that could be used to retain
erasures of abstract types (type parameters, abstract type members) for
being used at runtime.

With the advent of ClassManifest (and its subtype Manifest)
it became possible to write:

  def mkGenericArray[T: Manifest] = Array[T]()

When compiling array instantiation, scalac would use a ClassManifest
implicit parameter from scope (in this case, provided by a context bound)
to remember Ts that have been passed to invoke mkGenericArray and
use that information to instantiate arrays at runtime (via Java reflection).

When redesigning manifests into what is now known as type tags, we decided
to explore a notion of ArrayTags that would stand for abstract and pure array
creators. Sure, ClassManifests were perfectly fine for this job, but they did
too much - technically speaking, one doesn't necessarily need a java.lang.Class
to create an array. Depending on a platform, e.g. within JavaScript runtime,
one would want to use a different mechanism.

As tempting as this idea was, it has also proven to be problematic.

First, it created an extra abstraction inside the compiler. Along with class tags
and type tags, we had a third flavor of tags - array tags. This has threaded the
additional complexity though implicits and typers.

Second, consequently, when redesigning tags multiple times over the course of
Scala 2.10.0 development, we had to carry this extra abstraction with us, which
exacerbated the overall feeling towards array tags.

Finally, array tags didn't fit into the naming scheme we had for tags.
Both class tags and type tags sound logical, because, they are descriptors for
the things they are supposed to tag, according to their names.
However array tags are the odd ones, because they don't actually tag any arrays.

As funny as it might sound, the naming problem was the last straw
that made us do away with the array tags. Hence this commit.
  • Loading branch information...
xeno-by committed Jun 7, 2012
1 parent 07f7baa commit bc5f42f51982eb473075bbd2f474a5d628813031
Showing with 269 additions and 510 deletions.
  1. +1 −1 lib/scala-compiler.jar.desired.sha1
  2. +1 −1 lib/scala-library.jar.desired.sha1
  3. +1 −1 lib/scala-reflect.jar.desired.sha1
  4. +0 −5 src/compiler/scala/reflect/reify/Taggers.scala
  5. +0 −2 src/compiler/scala/reflect/reify/package.scala
  6. +0 −2 src/compiler/scala/reflect/reify/phases/Reshape.scala
  7. +9 −9 src/compiler/scala/tools/nsc/transform/UnCurry.scala
  8. +3 −3 src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
  9. +4 −6 src/compiler/scala/tools/nsc/typechecker/Implicits.scala
  10. +3 −3 src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
  11. +0 −17 src/compiler/scala/tools/nsc/typechecker/Tags.scala
  12. +3 −3 src/compiler/scala/tools/nsc/typechecker/Typers.scala
  13. +0 −1 src/compiler/scala/tools/reflect/FastTrack.scala
  14. +23 −23 src/library/scala/Array.scala
  15. +4 −4 src/library/scala/collection/GenTraversableOnce.scala
  16. +1 −1 src/library/scala/collection/Traversable.scala
  17. +2 −2 src/library/scala/collection/TraversableOnce.scala
  18. +2 −2 src/library/scala/collection/TraversableProxyLike.scala
  19. +5 −5 ...ry/scala/collection/generic/{ArrayTagTraversableFactory.scala → ClassTagTraversableFactory.scala}
  20. +6 −6 ...ibrary/scala/collection/generic/{GenericArrayTagCompanion.scala → GenericClassTagCompanion.scala}
  21. +10 −10 ...ion/generic/{GenericArrayTagTraversableTemplate.scala → GenericClassTagTraversableTemplate.scala}
  22. +2 −2 src/library/scala/collection/generic/TraversableForwarder.scala
  23. +6 −6 src/library/scala/collection/generic/package.scala
  24. +6 −6 src/library/scala/collection/immutable/PagedSeq.scala
  25. +2 −2 src/library/scala/collection/immutable/StringLike.scala
  26. +8 −9 src/library/scala/collection/mutable/ArrayBuilder.scala
  27. +4 −4 src/library/scala/collection/mutable/ArrayOps.scala
  28. +2 −2 src/library/scala/collection/mutable/ArrayStack.scala
  29. +8 −8 src/library/scala/collection/mutable/UnrolledBuffer.scala
  30. +5 −5 src/library/scala/collection/mutable/WrappedArray.scala
  31. +3 −3 src/library/scala/collection/mutable/WrappedArrayBuilder.scala
  32. +10 −10 src/library/scala/collection/parallel/ParIterableLike.scala
  33. +2 −2 src/library/scala/collection/parallel/mutable/ParArray.scala
  34. +2 −2 src/library/scala/collection/parallel/mutable/UnrolledParArrayCombiner.scala
  35. +0 −25 src/library/scala/reflect/ArrayTag.scala
  36. +2 −6 src/library/scala/reflect/ClassTag.scala
  37. +3 −3 src/library/scala/reflect/base/TagInterop.scala
  38. +4 −13 src/library/scala/reflect/base/TypeTags.scala
  39. +0 −1 src/library/scala/reflect/makro/internal/package.scala
  40. +0 −2 src/library/scala/reflect/package.scala
  41. +1 −2 src/library/scala/runtime/ScalaRunTime.scala
  42. +8 −8 src/library/scala/util/Sorting.scala
  43. +0 −2 src/reflect/scala/reflect/internal/Definitions.scala
  44. +1 −2 src/reflect/scala/reflect/internal/StdNames.scala
  45. +3 −5 test/files/jvm/serialization-new.scala
  46. +1 −1 test/files/neg/classtags_contextbound_a.check
  47. +1 −1 test/files/neg/classtags_contextbound_c.check
  48. +1 −1 test/files/neg/classtags_dont_use_typetags.check
  49. +2 −5 test/files/neg/interop_classtags_arenot_manifests.check
  50. +0 −9 test/files/neg/interop_classtags_arenot_manifests.scala
  51. +4 −4 test/files/neg/t2775.check
  52. +2 −2 test/files/pos/implicits-new.scala
  53. +2 −2 test/files/pos/spec-constr-new.scala
  54. +2 −2 test/files/pos/spec-fields-new.scala
  55. +2 −2 test/files/pos/spec-params-new.scala
  56. +2 −2 test/files/pos/spec-sparsearray-new.scala
  57. +2 −2 test/files/pos/t2795-new.scala
  58. +2 −2 test/files/pos/t3498-new.scala
  59. +3 −3 test/files/pos/t5769.scala
  60. +1 −1 test/files/presentation/ide-bug-1000531.check
  61. +2 −2 test/files/run/arrayclone-new.scala
  62. +0 −36 test/files/run/arraytags_basic.check
  63. +0 −24 test/files/run/arraytags_basic.scala
  64. +0 −48 test/files/run/arraytags_core.check
  65. +0 −52 test/files/run/arraytags_core.scala
  66. +0 −3 test/files/run/arraytags_usage.check
  67. +0 −17 test/files/run/arraytags_usage.scala
  68. +0 −3 test/files/run/interop_classtags_are_classmanifests.check
  69. +0 −9 test/files/run/interop_classtags_are_classmanifests.scala
  70. +3 −3 test/files/run/interop_manifests_are_classtags.scala
  71. +1 −1 test/files/run/primitive-sigs-2-new.check
  72. +2 −2 test/files/run/primitive-sigs-2-new.scala
  73. +2 −2 test/files/run/reify_implicits-new.scala
  74. +2 −2 test/files/run/t0421-new.scala
  75. +2 −2 test/files/run/t0677-new.scala
  76. +4 −4 test/files/run/t4216.check
  77. +2 −2 test/files/run/t4216.scala
  78. +2 −2 test/files/scalacheck/array-new.scala
  79. +3 −3 test/files/specialized/spec-matrix-new.scala
  80. +1 −1 test/files/speclib/instrumented.jar.desired.sha1
  81. +1 −2 test/instrumented/library/scala/runtime/ScalaRunTime.scala
  82. +55 −14 test/instrumented/srt.patch
@@ -1 +1 @@
bf1b1d794688e661cd9d94ec42be37515f06f453 ?scala-compiler.jar
cd208e55a800a1b4fcc623f13b44e9df551b617d ?scala-compiler.jar
@@ -1 +1 @@
9cc8e09873316a58bddef7dc59229ca6e1c27e79 ?scala-library.jar
5d4aa46eabd2a034a3102fb1de168547ef7d977b ?scala-library.jar
@@ -1 +1 @@
ec3636a6da2b3055f6a54488a002a5c3fc2ae192 ?scala-reflect.jar
cebf7edbff7931c4b3d6ef1504b2bf66f1abf6fd ?scala-reflect.jar
@@ -26,11 +26,6 @@ abstract class Taggers {
NullClass.asType -> nme.Null,
StringClass.asType -> nme.String)
// todo. the following two methods won't be necessary once we implement implicit macro generators for tags
def materializeArrayTag(prefix: Tree, tpe: Type): Tree =
materializeClassTag(prefix, tpe)
def materializeClassTag(prefix: Tree, tpe: Type): Tree = {
val tagModule = ClassTagModule
materializeTag(prefix, tpe, tagModule, {
@@ -48,8 +48,6 @@ package object reify {
if (tpe.isSpliceable) {
val classTagInScope = typer0.resolveClassTag(enclosingMacroPosition, tpe, allowMaterialization = false)
if (!classTagInScope.isEmpty) return Select(classTagInScope, nme.runtimeClass)
val arrayTagInScope = typer0.resolveArrayTag(enclosingMacroPosition, tpe, allowMaterialization = false)
if (!arrayTagInScope.isEmpty) return gen.mkMethodCall(arrayElementClassMethod, List(arrayTagInScope))
if (concrete) throw new ReificationError(enclosingMacroPosition, "tpe %s is an unresolved spliceable type".format(tpe))
}
@@ -101,8 +101,6 @@ trait Reshape {
// hence we cannot reify references to them, because noone will be able to see them later
// when implicit macros are fixed, these sneaky macros will move to corresponding companion objects
// of, say, ClassTag or TypeTag
case Apply(TypeApply(_, List(tt)), _) if original.symbol == MacroInternal_materializeArrayTag =>
gen.mkNullaryCall(Predef_implicitly, List(appliedType(ArrayTagClass, tt.tpe)))
case Apply(TypeApply(_, List(tt)), _) if original.symbol == MacroInternal_materializeClassTag =>
gen.mkNullaryCall(Predef_implicitly, List(appliedType(ClassTagClass, tt.tpe)))
case Apply(TypeApply(_, List(tt)), List(pre)) if original.symbol == MacroInternal_materializeTypeTag =>
@@ -418,23 +418,23 @@ abstract class UnCurry extends InfoTransform
def sequenceToArray(tree: Tree) = {
val toArraySym = tree.tpe member nme.toArray
assert(toArraySym != NoSymbol)
def getArrayTag(tp: Type): Tree = {
val tag = localTyper.resolveArrayTag(tree.pos, tp)
def getClassTag(tp: Type): Tree = {
val tag = localTyper.resolveClassTag(tree.pos, tp)
// Don't want bottom types getting any further than this (SI-4024)
if (tp.typeSymbol.isBottomClass) getArrayTag(AnyClass.tpe)
if (tp.typeSymbol.isBottomClass) getClassTag(AnyClass.tpe)
else if (!tag.isEmpty) tag
else if (tp.bounds.hi ne tp) getArrayTag(tp.bounds.hi)
else localTyper.TyperErrorGen.MissingArrayTagError(tree, tp)
else if (tp.bounds.hi ne tp) getClassTag(tp.bounds.hi)
else localTyper.TyperErrorGen.MissingClassTagError(tree, tp)
}
def traversableArrayTag(tpe: Type): Tree = {
def traversableClassTag(tpe: Type): Tree = {
(tpe baseType TraversableClass).typeArgs match {
case targ :: _ => getArrayTag(targ)
case targ :: _ => getClassTag(targ)
case _ => EmptyTree
}
}
afterUncurry {
localTyper.typedPos(pos) {
gen.mkMethodCall(tree, toArraySym, Nil, List(traversableArrayTag(tree.tpe)))
gen.mkMethodCall(tree, toArraySym, Nil, List(traversableClassTag(tree.tpe)))
}
}
}
@@ -688,7 +688,7 @@ abstract class UnCurry extends InfoTransform
tree match {
/* Some uncurry post transformations add members to templates.
*
*
* Members registered by `addMembers` for the current template are added
* once the template transformation has finished.
*
@@ -562,9 +562,9 @@ trait ContextErrors {
def AbstractExistentiallyOverParamerizedTpeError(tree: Tree, tp: Type) =
issueNormalTypeError(tree, "can't existentially abstract over parameterized type " + tp)
// resolveArrayTag
def MissingArrayTagError(tree: Tree, tp: Type) = {
issueNormalTypeError(tree, "cannot find array tag for element type "+tp)
// resolveClassTag
def MissingClassTagError(tree: Tree, tp: Type) = {
issueNormalTypeError(tree, "cannot find class tag for element type "+tp)
setError(tree)
}
@@ -1133,7 +1133,6 @@ trait Implicits {
private def TagSymbols = TagMaterializers.keySet
private val TagMaterializers = Map[Symbol, Symbol](
ArrayTagClass -> MacroInternal_materializeArrayTag,
ClassTagClass -> MacroInternal_materializeClassTag,
TypeTagClass -> MacroInternal_materializeTypeTag,
ConcreteTypeTagClass -> MacroInternal_materializeConcreteTypeTag
@@ -1166,9 +1165,8 @@ trait Implicits {
}
val prefix = (
// ClassTags and ArrayTags only exist for scala.reflect, so their materializer
// doesn't care about prefixes
if ((tagClass eq ArrayTagClass) || (tagClass eq ClassTagClass)) gen.mkBasisUniverseRef
// ClassTags are not path-dependent, so their materializer doesn't care about prefixes
if (tagClass eq ClassTagClass) gen.mkBasisUniverseRef
else pre match {
// [Eugene to Martin] this is the crux of the interaction between
// implicits and reifiers here we need to turn a (supposedly
@@ -1296,7 +1294,7 @@ trait Implicits {
val tagInScope =
if (full) resolveTypeTag(pos, NoType, tp, concrete = true, allowMaterialization = false)
else resolveArrayTag(pos, tp, allowMaterialization = false)
else resolveClassTag(pos, tp, allowMaterialization = false)
if (tagInScope.isEmpty) mot(tp, Nil, Nil)
else {
if (full) {
@@ -1321,7 +1319,7 @@ trait Implicits {
if (full) {
val cm = typed(Ident(ReflectRuntimeCurrentMirror))
gen.mkMethodCall(ReflectRuntimeUniverse, nme.concreteTypeTagToManifest, List(tp), List(cm, tagInScope))
} else gen.mkMethodCall(ReflectRuntimeUniverse, nme.arrayTagToClassManifest, List(tp), List(tagInScope))
} else gen.mkMethodCall(ReflectRuntimeUniverse, nme.classTagToClassManifest, List(tp), List(tagInScope))
wrapResult(interop)
}
}
@@ -9,7 +9,7 @@ package typechecker
import symtab.Flags._
import scala.collection.mutable
import scala.ref.WeakReference
import scala.reflect.ArrayTag
import scala.reflect.ClassTag
/**
* @author Lukas Rytz
@@ -40,14 +40,14 @@ trait NamesDefaults { self: Analyzer =>
def isNamed(arg: Tree) = nameOf(arg).isDefined
/** @param pos maps indices from old to new */
def reorderArgs[T: ArrayTag](args: List[T], pos: Int => Int): List[T] = {
def reorderArgs[T: ClassTag](args: List[T], pos: Int => Int): List[T] = {
val res = new Array[T](args.length)
foreachWithIndex(args)((arg, index) => res(pos(index)) = arg)
res.toList
}
/** @param pos maps indices from new to old (!) */
def reorderArgsInv[T: ArrayTag](args: List[T], pos: Int => Int): List[T] = {
def reorderArgsInv[T: ClassTag](args: List[T], pos: Int => Int): List[T] = {
val argsArray = args.toArray
(argsArray.indices map (i => argsArray(pos(i)))).toList
}
@@ -23,23 +23,6 @@ trait Tags {
).tree)
}
/** Finds in scope or materializes an ArrayTag.
* Should be used instead of ClassTag or ClassManifest every time compiler needs to create an array.
*
* @param pos Position for error reporting. Please, provide meaningful value.
* @param tp Type we're looking an ArrayTag for, e.g. resolveArrayTag(pos, IntClass.tpe) will look for ArrayTag[Int].
* @param allowMaterialization If true (default) then the resolver is allowed to launch materialization macros when there's no array tag in scope.
* If false then materialization macros are prohibited from running.
*
* @returns Tree that represents an `scala.reflect.ArrayTag` for `tp` if everything is okay.
* EmptyTree if `allowMaterialization` is false, and there is no array tag in scope.
* EmptyTree if the result contains unresolved (i.e. not spliced) type parameters and abstract type members.
*/
def resolveArrayTag(pos: Position, tp: Type, allowMaterialization: Boolean = true): Tree = {
val taggedTp = appliedType(ArrayTagClass.typeConstructor, List(tp))
resolveTag(pos, taggedTp, allowMaterialization)
}
/** Finds in scope or materializes a ClassTag.
* Should be used instead of ClassManifest every time compiler needs to persist an erasure.
*
@@ -3158,7 +3158,7 @@ trait Typers extends Modes with Adaptations with Tags {
if (annInfo.atp.isErroneous) { hasError = true; None }
else Some(NestedAnnotArg(annInfo))
// use of Array.apply[T: ArrayTag](xs: T*): Array[T]
// use of Array.apply[T: ClassTag](xs: T*): Array[T]
// and Array.apply(x: Int, xs: Int*): Array[Int] (and similar)
case Apply(fun, args) =>
val typedFun = typed(fun, forFunMode(mode), WildcardType)
@@ -4864,8 +4864,8 @@ trait Typers extends Modes with Adaptations with Tags {
val Some((level, componentType)) = erasure.GenericArray.unapply(tpt.tpe)
val tagType = List.iterate(componentType, level)(tpe => appliedType(ArrayClass.asType, List(tpe))).last
val newArrayApp = atPos(tree.pos) {
val tag = resolveArrayTag(tree.pos, tagType)
if (tag.isEmpty) MissingArrayTagError(tree, tagType)
val tag = resolveClassTag(tree.pos, tagType)
if (tag.isEmpty) MissingClassTagError(tree, tagType)
else new ApplyToImplicitArgs(Select(tag, nme.newArray), args)
}
typed(newArrayApp, mode, pt)
@@ -36,7 +36,6 @@ trait FastTrack {
lazy val fastTrack: Map[Symbol, FastTrackEntry] = {
var registry = Map[Symbol, FastTrackEntry]()
implicit class BindTo(sym: Symbol) { def bindTo(expander: FastTrackExpander): Unit = if (sym != NoSymbol) registry += sym -> FastTrackEntry(sym, expander) }
MacroInternal_materializeArrayTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeArrayTag(u, tt.tpe) }
MacroInternal_materializeClassTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeClassTag(u, tt.tpe) }
MacroInternal_materializeTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, EmptyTree, tt.tpe, concrete = false) }
MacroInternal_materializeConcreteTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, EmptyTree, tt.tpe, concrete = true) }
Oops, something went wrong.

0 comments on commit bc5f42f

Please sign in to comment.