From 2b09d8caf5497c4e016a3e1179e5f7e842766176 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Mon, 23 Apr 2012 17:51:28 +0200 Subject: rethinks tags * introduces ArrayTag and ErasureTag * all type tags now feature erasure --- lib/scala-compiler.jar.desired.sha1 | 2 +- lib/scala-library.jar.desired.sha1 | 2 +- .../scala/reflect/internal/Definitions.scala | 16 +- src/compiler/scala/reflect/internal/StdNames.scala | 42 ++- src/compiler/scala/reflect/internal/TreeInfo.scala | 6 +- src/compiler/scala/reflect/internal/Types.scala | 21 +- .../scala/reflect/makro/runtime/Reifiers.scala | 123 +------ src/compiler/scala/reflect/reify/Errors.scala | 8 +- src/compiler/scala/reflect/reify/Reifier.scala | 38 +- .../scala/reflect/reify/codegen/Symbols.scala | 2 +- .../scala/reflect/reify/codegen/Types.scala | 18 +- src/compiler/scala/reflect/reify/package.scala | 38 +- .../scala/tools/nsc/interpreter/RichClass.scala | 4 +- .../scala/tools/nsc/transform/Erasure.scala | 10 +- .../scala/tools/nsc/transform/UnCurry.scala | 2 +- .../scala/tools/nsc/typechecker/Implicits.scala | 18 +- .../scala/tools/nsc/typechecker/Macros.scala | 52 ++- .../tools/nsc/typechecker/PatMatVirtualiser.scala | 1 + .../scala/tools/nsc/typechecker/Taggings.scala | 71 ++++ .../scala/tools/nsc/typechecker/Typers.scala | 50 +-- src/compiler/scala/tools/reflect/package.scala | 3 +- src/library/scala/Predef.scala | 26 +- src/library/scala/reflect/ArrayTag.scala | 8 +- src/library/scala/reflect/ClassTag.scala | 206 +++-------- src/library/scala/reflect/DummyMirror.scala | 2 + src/library/scala/reflect/ErasureTag.scala | 23 ++ src/library/scala/reflect/ReflectionUtils.scala | 1 + src/library/scala/reflect/TagMaterialization.scala | 122 ------- src/library/scala/reflect/api/Symbols.scala | 8 + src/library/scala/reflect/api/TypeTags.scala | 246 ++++++------- src/library/scala/reflect/api/Universe.scala | 23 +- src/library/scala/reflect/makro/Context.scala | 21 +- src/library/scala/reflect/makro/Reifiers.scala | 25 +- .../scala/reflect/makro/internal/Utils.scala | 86 +++-- src/library/scala/reflect/package.scala | 5 +- src/library/scala/runtime/ScalaRunTime.scala | 21 +- src/library/scala/util/Marshal.scala | 36 +- test/files/neg/classtags_contextbound_a.check | 2 +- test/files/neg/classtags_contextbound_c.check | 2 +- test/files/neg/classtags_dont_use_typetags.check | 4 + test/files/neg/classtags_dont_use_typetags.scala | 3 + test/files/neg/macro-invalidret-nontree.check | 14 +- .../neg/macro-invalidret-nonuniversetree.check | 14 +- test/files/neg/t5689.check | 2 +- test/files/run/arraytags_basic.check | 36 ++ test/files/run/arraytags_basic.scala | 22 ++ test/files/run/arraytags_core.check | 48 +++ test/files/run/arraytags_core.scala | 50 +++ test/files/run/arraytags_usage.check | 3 + test/files/run/arraytags_usage.scala | 15 + test/files/run/classtags_core.check | 62 ++-- test/files/run/classtags_core.scala | 2 + test/files/run/classtags_multi.check | 5 + test/files/run/classtags_multi.scala | 7 + .../files/run/classtags_use_concretetypetags.scala | 3 + test/files/run/concretetypetags_core.check | 32 ++ test/files/run/concretetypetags_core.scala | 34 ++ test/files/run/concretetypetags_multi.check | 5 + test/files/run/concretetypetags_multi.scala | 7 + test/files/run/erasuretags_abstract.check | 4 + test/files/run/erasuretags_abstract.scala | 9 + test/files/run/erasuretags_basic.check | 24 ++ test/files/run/erasuretags_basic.scala | 21 ++ test/files/run/erasuretags_core.check | 32 ++ test/files/run/erasuretags_core.scala | 34 ++ test/files/run/erasuretags_usage.scala | 12 + test/files/run/groundtypetags_core.check | 30 -- test/files/run/groundtypetags_core.scala | 32 -- .../Impls_Macros_1.scala | 7 - .../run/macro-typecheck-macrosdisabled2.check | 5 + .../run/macro-typecheck-macrosdisabled2.flags | 1 + .../Impls_Macros_1.scala | 29 ++ .../macro-typecheck-macrosdisabled2/Test_2.scala | 4 + .../run/toolbox_typecheck_macrosdisabled2.check | 5 + .../run/toolbox_typecheck_macrosdisabled2.scala | 17 + test/files/run/typetags_core.check | 62 ++-- test/files/run/typetags_core.scala | 2 + test/files/run/typetags_multi.check | 5 + test/files/run/typetags_multi.scala | 7 + test/files/speclib/instrumented.jar.desired.sha1 | 2 +- test/instrumented/boxes.patch | 40 +-- .../library/scala/runtime/BoxesRunTime.java | 384 +++++++++------------ .../library/scala/runtime/ScalaRunTime.scala | 93 ++--- test/instrumented/srt.patch | 17 +- 84 files changed, 1426 insertions(+), 1210 deletions(-) create mode 100644 src/compiler/scala/tools/nsc/typechecker/Taggings.scala create mode 100644 src/library/scala/reflect/ErasureTag.scala delete mode 100644 src/library/scala/reflect/TagMaterialization.scala create mode 100644 test/files/neg/classtags_dont_use_typetags.check create mode 100644 test/files/neg/classtags_dont_use_typetags.scala create mode 100644 test/files/run/arraytags_basic.check create mode 100644 test/files/run/arraytags_basic.scala create mode 100644 test/files/run/arraytags_core.check create mode 100644 test/files/run/arraytags_core.scala create mode 100644 test/files/run/arraytags_usage.check create mode 100644 test/files/run/arraytags_usage.scala create mode 100644 test/files/run/classtags_multi.check create mode 100644 test/files/run/classtags_multi.scala create mode 100644 test/files/run/classtags_use_concretetypetags.scala create mode 100644 test/files/run/concretetypetags_core.check create mode 100644 test/files/run/concretetypetags_core.scala create mode 100644 test/files/run/concretetypetags_multi.check create mode 100644 test/files/run/concretetypetags_multi.scala create mode 100644 test/files/run/erasuretags_abstract.check create mode 100644 test/files/run/erasuretags_abstract.scala create mode 100644 test/files/run/erasuretags_basic.check create mode 100644 test/files/run/erasuretags_basic.scala create mode 100644 test/files/run/erasuretags_core.check create mode 100644 test/files/run/erasuretags_core.scala create mode 100644 test/files/run/erasuretags_usage.scala delete mode 100644 test/files/run/groundtypetags_core.check delete mode 100644 test/files/run/groundtypetags_core.scala create mode 100644 test/files/run/macro-typecheck-macrosdisabled2.check create mode 100644 test/files/run/macro-typecheck-macrosdisabled2.flags create mode 100644 test/files/run/macro-typecheck-macrosdisabled2/Impls_Macros_1.scala create mode 100644 test/files/run/macro-typecheck-macrosdisabled2/Test_2.scala create mode 100644 test/files/run/toolbox_typecheck_macrosdisabled2.check create mode 100644 test/files/run/toolbox_typecheck_macrosdisabled2.scala create mode 100644 test/files/run/typetags_multi.check create mode 100644 test/files/run/typetags_multi.scala diff --git a/lib/scala-compiler.jar.desired.sha1 b/lib/scala-compiler.jar.desired.sha1 index 7479a1861e..5a541f8cf3 100644 --- a/lib/scala-compiler.jar.desired.sha1 +++ b/lib/scala-compiler.jar.desired.sha1 @@ -1 +1 @@ -5d99e65aaa8e00c4815e011a8dfc495cb38bdfcc ?scala-compiler.jar +c020eccb8cf37963725985f36b44d070915cf4d2 ?scala-compiler.jar diff --git a/lib/scala-library.jar.desired.sha1 b/lib/scala-library.jar.desired.sha1 index 76914369b5..d059e861f0 100644 --- a/lib/scala-library.jar.desired.sha1 +++ b/lib/scala-library.jar.desired.sha1 @@ -1 +1 @@ -53ddaba2c7d56b360eda1a56c3eef5ec23ef14ca ?scala-library.jar +31c7188cef85c28b84b9ce35bc6780996e5dd139 ?scala-library.jar diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 24fc7c7cc4..28905dd240 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -380,6 +380,8 @@ trait Definitions extends reflect.api.StandardDefinitions { def arrayCloneMethod = getMember(ScalaRunTimeModule, nme.array_clone) def ensureAccessibleMethod = getMember(ScalaRunTimeModule, nme.ensureAccessible) def scalaRuntimeSameElements = getMember(ScalaRunTimeModule, nme.sameElements) + def arrayClassMethod = getMember(ScalaRunTimeModule, nme.arrayClass) + def arrayElementClassMethod = getMember(ScalaRunTimeModule, nme.arrayElementClass) // classes with special meanings lazy val StringAddClass = getRequiredClass("scala.runtime.StringAdd") @@ -409,7 +411,7 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val EqualsPatternClass = specialPolyClass(tpnme.EQUALS_PATTERN_NAME, 0L)(_ => AnyClass.tpe) lazy val JavaRepeatedParamClass = specialPolyClass(tpnme.JAVA_REPEATED_PARAM_CLASS_NAME, COVARIANT)(tparam => arrayType(tparam.tpe)) lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS_NAME, COVARIANT)(tparam => seqType(tparam.tpe)) - + lazy val MarkerCPSTypes = getClassIfDefined("scala.util.continuations.cpsParam") def isByNameParamType(tp: Type) = tp.typeSymbol == ByNameParamClass @@ -479,7 +481,9 @@ trait Definitions extends reflect.api.StandardDefinitions { // scala.reflect lazy val ReflectPackageClass = getMember(ScalaPackageClass, nme.reflect) lazy val ReflectPackage = getPackageObject("scala.reflect") - def Reflect_mirror = getMember(ReflectPackage, nme.mirror) + def ReflectMirror = getMember(ReflectPackage, nme.mirror) + // [Eugene] is this a good place for ReflectMirrorPrefix? + def ReflectMirrorPrefix = gen.mkAttributedRef(ReflectMirror) setType singleType(ReflectMirror.owner.thisPrefix, ReflectMirror) lazy val ExprClass = getMember(getRequiredClass("scala.reflect.api.Exprs"), tpnme.Expr) def ExprTree = getMemberClass(ExprClass, nme.tree) @@ -488,6 +492,8 @@ trait Definitions extends reflect.api.StandardDefinitions { def ExprValue = getMember(ExprClass, nme.value) lazy val ExprModule = getMember(getRequiredClass("scala.reflect.api.Exprs"), nme.Expr) + lazy val ArrayTagClass = requiredClass[scala.reflect.ArrayTag[_]] + lazy val ErasureTagClass = requiredClass[scala.reflect.ErasureTag[_]] lazy val ClassTagModule = requiredModule[scala.reflect.ClassTag[_]] lazy val ClassTagClass = requiredClass[scala.reflect.ClassTag[_]] lazy val TypeTagsClass = requiredClass[scala.reflect.api.TypeTags] @@ -496,7 +502,9 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val ConcreteTypeTagClass = getMemberClass(TypeTagsClass, tpnme.ConcreteTypeTag) lazy val ConcreteTypeTagModule = getMemberModule(TypeTagsClass, nme.ConcreteTypeTag) - def ClassTagErasure = getMemberMethod(ClassTagClass, nme.erasure) + def ArrayTagWrap = getMemberMethod(ArrayTagClass, nme.wrap) + def ArrayTagNewArray = getMemberMethod(ArrayTagClass, nme.newArray) + def ErasureTagErasure = getMemberMethod(ErasureTagClass, nme.erasure) def ClassTagTpe = getMemberMethod(ClassTagClass, nme.tpe) def TypeTagTpe = getMemberMethod(TypeTagClass, nme.tpe) @@ -507,6 +515,8 @@ trait Definitions extends reflect.api.StandardDefinitions { def MacroContextReify = getMember(MacroContextClass, nme.reify) lazy val MacroImplAnnotation = getRequiredClass("scala.reflect.makro.internal.macroImpl") lazy val MacroInternalPackage = getPackageObject("scala.reflect.makro.internal") + def MacroInternal_materializeArrayTag = getMemberMethod(MacroInternalPackage, nme.materializeArrayTag) + def MacroInternal_materializeErasureTag = getMemberMethod(MacroInternalPackage, nme.materializeErasureTag) def MacroInternal_materializeClassTag = getMemberMethod(MacroInternalPackage, nme.materializeClassTag) def MacroInternal_materializeTypeTag = getMemberMethod(MacroInternalPackage, nme.materializeTypeTag) def MacroInternal_materializeConcreteTypeTag = getMemberMethod(MacroInternalPackage, nme.materializeConcreteTypeTag) diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala index 54be83c98f..4ce6afe1f3 100644 --- a/src/compiler/scala/reflect/internal/StdNames.scala +++ b/src/compiler/scala/reflect/internal/StdNames.scala @@ -562,6 +562,8 @@ trait StdNames { val applyOrElse: NameType = "applyOrElse" val args : NameType = "args" val argv : NameType = "argv" + val arrayClass: NameType = "arrayClass" + val arrayElementClass: NameType = "arrayElementClass" val arrayValue: NameType = "arrayValue" val array_apply : NameType = "array_apply" val array_clone : NameType = "array_clone" @@ -628,9 +630,11 @@ trait StdNames { val main: NameType = "main" val manifest: NameType = "manifest" val map: NameType = "map" + val materializeArrayTag: NameType = "materializeArrayTag" val materializeClassTag: NameType = "materializeClassTag" - val materializeTypeTag: NameType = "materializeTypeTag" val materializeConcreteTypeTag: NameType = "materializeConcreteTypeTag" + val materializeErasureTag: NameType= "materializeErasureTag" + val materializeTypeTag: NameType = "materializeTypeTag" val mirror : NameType = "mirror" val moduleClass : NameType = "moduleClass" val name: NameType = "name" @@ -813,10 +817,11 @@ trait StdNames { val ROOTPKG: TermName = "_root_" val EQEQ_LOCAL_VAR: TermName = "eqEqTemp$" - def getCause = sn.GetCause - def getClass_ = sn.GetClass - def getMethod_ = sn.GetMethod - def invoke_ = sn.Invoke + def getCause = sn.GetCause + def getClass_ = sn.GetClass + def getComponentType = sn.GetComponentType + def getMethod_ = sn.GetMethod + def invoke_ = sn.Invoke val ADD = encode("+") val AND = encode("&") @@ -1005,6 +1010,7 @@ trait StdNames { val ForName : TermName val GetCause : TermName val GetClass : TermName + val GetComponentType : TermName val GetMethod : TermName val Invoke : TermName val JavaLang : TermName @@ -1090,12 +1096,13 @@ trait StdNames { final val Throwable: TypeName = "java.lang.Throwable" final val ValueType: TypeName = tpnme.NO_NAME - final val ForName: TermName = newTermName("forName") - final val GetCause: TermName = newTermName("getCause") - final val GetClass: TermName = newTermName("getClass") - final val GetMethod: TermName = newTermName("getMethod") - final val Invoke: TermName = newTermName("invoke") - final val JavaLang: TermName = newTermName("java.lang") + final val ForName: TermName = newTermName("forName") + final val GetCause: TermName = newTermName("getCause") + final val GetClass: TermName = newTermName("getClass") + final val GetComponentType: TermName = newTermName("getComponentType") + final val GetMethod: TermName = newTermName("getMethod") + final val Invoke: TermName = newTermName("invoke") + final val JavaLang: TermName = newTermName("java.lang") val Boxed = immutable.Map[TypeName, TypeName]( tpnme.Boolean -> BoxedBoolean, @@ -1127,12 +1134,13 @@ trait StdNames { final val Throwable: TypeName = "System.Exception" final val ValueType: TypeName = "System.ValueType" - final val ForName: TermName = newTermName("GetType") - final val GetCause: TermName = newTermName("InnerException") /* System.Reflection.TargetInvocationException.InnerException */ - final val GetClass: TermName = newTermName("GetType") - final val GetMethod: TermName = newTermName("GetMethod") - final val Invoke: TermName = newTermName("Invoke") - final val JavaLang: TermName = newTermName("System") + final val ForName: TermName = newTermName("GetType") + final val GetCause: TermName = newTermName("InnerException") /* System.Reflection.TargetInvocationException.InnerException */ + final val GetClass: TermName = newTermName("GetType") + final val GetComponentType: TermName = newTermName("GetElementType") + final val GetMethod: TermName = newTermName("GetMethod") + final val Invoke: TermName = newTermName("Invoke") + final val JavaLang: TermName = newTermName("System") val Boxed = immutable.Map[TypeName, TypeName]( tpnme.Boolean -> "System.Boolean", diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala index 937b3ea5d6..48dfe8bcfc 100644 --- a/src/compiler/scala/reflect/internal/TreeInfo.scala +++ b/src/compiler/scala/reflect/internal/TreeInfo.scala @@ -676,14 +676,14 @@ abstract class TreeInfo { case ValDef(_, name, _, Apply(Select(mrRef1 @ Ident(_), newFreeType), List(_, _, value, Literal(Constant(flags: Long)), Literal(Constant(origin: String))))) if mrRef1.name == nme.MIRROR_SHORT && (newFreeType == newFreeTypeMethod.name || newFreeType == newFreeExistentialMethod.name) => value match { - case Apply(TypeApply(Select(Select(mrRef2 @ Ident(_), typeTag), apply), List(binding)), List(Literal(Constant(null)))) + case Apply(TypeApply(Select(Select(mrRef2 @ Ident(_), typeTag), apply), List(binding)), List(Literal(Constant(null)), _)) if mrRef2.name == nme.MIRROR_SHORT && typeTag == nme.TypeTag && apply == nme.apply => Some(mrRef1, name, binding, flags, origin) - case Apply(TypeApply(Select(mrRef2 @ Ident(_), typeTag), List(binding)), List(Literal(Constant(null)))) + case Apply(TypeApply(Select(mrRef2 @ Ident(_), typeTag), List(binding)), List(Literal(Constant(null)), _)) if mrRef2.name == nme.MIRROR_SHORT && typeTag == nme.TypeTag => Some(mrRef1, name, binding, flags, origin) case _ => - throw new Error("unsupported free type def: " + showRaw(tree)) + throw new Error("unsupported free type def: %s%n%s".format(value, showRaw(value))) } case _ => None diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 32b09eddeb..815a5c0710 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -264,7 +264,23 @@ trait Types extends api.Types { self: SymbolTable => def nonPrivateDeclaration(name: Name): Symbol = nonPrivateDecl(name) def declarations = decls def typeArguments = typeArgs - def erasure = transformedType(this) + def erasure = this match { + case ConstantType(value) => widen.erasure // [Eugene to Martin] constant types are unaffected by erasure. weird. + case _ => + var result = transformedType(this) + result = result.normalize match { // necessary to deal with erasures of HK types, typeConstructor won't work + case PolyType(undets, underlying) => existentialAbstraction(undets, underlying) // we don't want undets in the result + case _ => result + } + // [Eugene] erasure screws up all ThisTypes for modules into PackageTypeRefs + // we need to unscrew them, or certain typechecks will fail mysteriously + // http://groups.google.com/group/scala-internals/browse_thread/thread/6d3277ae21b6d581 + result = result.map(tpe => tpe match { + case tpe: PackageTypeRef => ThisType(tpe.sym) + case _ => tpe + }) + result + } def substituteTypes(from: List[Symbol], to: List[Type]): Type = subst(from, to) // [Eugene] to be discussed and refactored @@ -1342,7 +1358,8 @@ trait Types extends api.Types { self: SymbolTable => if (period != currentPeriod) { tpe.underlyingPeriod = currentPeriod if (!isValid(period)) { - tpe.underlyingCache = tpe.pre.memberType(tpe.sym).resultType; + // [Eugene to Paul] needs review + tpe.underlyingCache = if (tpe.sym == NoSymbol) ThisType(RootClass) else tpe.pre.memberType(tpe.sym).resultType; assert(tpe.underlyingCache ne tpe, tpe) } } diff --git a/src/compiler/scala/reflect/makro/runtime/Reifiers.scala b/src/compiler/scala/reflect/makro/runtime/Reifiers.scala index d9a89d0e6d..1c5af4b752 100644 --- a/src/compiler/scala/reflect/makro/runtime/Reifiers.scala +++ b/src/compiler/scala/reflect/makro/runtime/Reifiers.scala @@ -12,124 +12,23 @@ trait Reifiers { import mirror._ import definitions._ - private lazy val ClassTagModule = ClassTagClass.companionSymbol + lazy val reflectMirrorPrefix: Tree = ReflectMirrorPrefix - // [Eugene] imho this logic should be moved into `erasure` - private def calculateTagErasure(tpe: Type) = tpe match { - case tpe if tpe.typeSymbol.isDerivedValueClass => tpe // [Eugene to Martin] is this correct? - case ConstantType(value) => tpe.widen.erasure - case _ => - // [Eugene] magikz. needs review - // necessary to deal with erasures of HK types, typeConstructor won't work - tpe.erasure.normalize match { - // we don't want undets in the result - case PolyType(undets, underlying) => existentialAbstraction(undets, underlying) - case result => result - } - } - private def classTagFromArgument(tpe: Type, arg: Tree) = { - gen.mkMethodCall(ClassTagModule, nme.apply, List(tpe), List(arg)) - // val factory = TypeApply(Select(Ident(ClassTagModule), nme.apply), List(TypeTree(tpe))) - // Apply(factory, List(typeArg)) - } - private def classTagFromErasure(tpe: Type) = { - val erasure = calculateTagErasure(tpe) - classTagFromArgument(tpe, gen.mkNullaryCall(Predef_classOf, List(erasure))) - // val targ = TypeApply(Select(Ident(PredefModule), nme.classOf), List(TypeTree(erasure))) - // classTagFromArgument(tpe, targ) - } - private def typetagIsSynthetic(tree: Tree) = tree match { - case Block(_, _) => true - case _ => tree exists (_ hasSymbolWhich Set(TypeTagModule, ConcreteTypeTagModule)) + def reifyTree(prefix: Tree, tree: Tree): Tree = { + val result = scala.reflect.reify.`package`.reifyTree(mirror)(callsiteTyper, prefix, tree) + logFreeVars(enclosingPosition, result) + result } - lazy val reflectMirrorPrefix: Tree = { - // [Eugene] how do I typecheck this without undergoing this tiresome (and, in general, incorrect) procedure? - val prefix: Tree = Select(Select(Ident(definitions.ScalaPackage), newTermName("reflect")), newTermName("mirror")) - val prefixTpe = typeCheck(TypeApply(Select(prefix, newTermName("asInstanceOf")), List(SingletonTypeTree(prefix)))).tpe - typeCheck(prefix) setType prefixTpe + def reifyType(prefix: Tree, tpe: Type, dontSpliceAtTopLevel: Boolean = false, concrete: Boolean = false): Tree = { + val result = scala.reflect.reify.`package`.reifyType(mirror)(callsiteTyper, prefix, tpe, dontSpliceAtTopLevel, concrete) + logFreeVars(enclosingPosition, result) + result } - def reifyTree(prefix: Tree, tree: Tree): Tree = - reifyTopLevel(prefix, tree) - - def reifyType(prefix: Tree, tpe: Type, dontSpliceAtTopLevel: Boolean = false, requireConcreteTypeTag: Boolean = false): Tree = - reifyTopLevel(prefix, tpe, dontSpliceAtTopLevel, requireConcreteTypeTag) - - def reifyErasure(tpe: Type): Tree = { - val positionBearer = (enclosingMacros.find(_.macroApplication.pos != NoPosition) match { - case None => EmptyTree - case Some(m) => m.macroApplication - }).asInstanceOf[Tree] - - val typetagInScope = callsiteTyper.context.withMacrosDisabled( - callsiteTyper.resolveTypeTag( - positionBearer, - singleType(Reflect_mirror.owner.thisPrefix, Reflect_mirror), - tpe, - full = true - ) - ) - typetagInScope match { - case success if !success.isEmpty && !typetagIsSynthetic(success) => - classTagFromArgument(tpe, typetagInScope) - case _ => - if (tpe.typeSymbol == ArrayClass) { - val componentTpe = tpe.typeArguments(0) - val componentTag = callsiteTyper.resolveClassTag(positionBearer, componentTpe) - Select(componentTag, nme.wrap) - } - // [Eugene] what's the intended behavior? there's no spec on ClassManifests - // for example, should we ban Array[T] or should we tag them with Array[AnyRef]? - // if its the latter, what should be the result of tagging Array[T] where T <: Int? - else if (tpe.isSpliceable) { - throw new ReificationError(enclosingPosition, - "tpe %s is an unresolved spliceable type".format(tpe)) - } - else classTagFromErasure(tpe) - } - } + def reifyErasure(tpe: Type, concrete: Boolean = true): Tree = + scala.reflect.reify.`package`.reifyErasure(mirror)(callsiteTyper, tpe, concrete) def unreifyTree(tree: Tree): Tree = Select(tree, definitions.ExprEval) - - def reifyTopLevel(prefix: Tree, reifee: Any, dontSpliceAtTopLevel: Boolean = false, requireConcreteTypeTag: Boolean = false): Tree = { - // [Eugene] the plumbing is not very pretty, but anyways factoring out the reifier seems like a necessary step to me - import scala.reflect.reify._ - val reifier = mkReifier(mirror)(callsiteTyper, prefix, reifee, dontSpliceAtTopLevel, requireConcreteTypeTag) - - try { - val result = reifier.reified - logFreeVars(enclosingPosition, result) - result - } catch { - case ex: reifier.ReificationError => -// // this is a "soft" exception - it will normally be caught by the macro -// // consequently, we need to log the stack trace here, so that it doesn't get lost -// if (settings.Yreifydebug.value) { -// val message = new java.io.StringWriter() -// ex.printStackTrace(new java.io.PrintWriter(message)) -// println(scala.compat.Platform.EOL + message) -// } - val xlated = new ReificationError(ex.pos, ex.msg) - xlated.setStackTrace(ex.getStackTrace) - throw xlated - case ex: reifier.UnexpectedReificationError => - val xlated = new UnexpectedReificationError(ex.pos, ex.msg, ex.cause) - xlated.setStackTrace(ex.getStackTrace) - throw xlated - } - } - - class ReificationError(var pos: Position, val msg: String) extends Throwable(msg) - - object ReificationError extends ReificationErrorExtractor { - def unapply(error: ReificationError): Option[(Position, String)] = Some((error.pos, error.msg)) - } - - class UnexpectedReificationError(val pos: Position, val msg: String, val cause: Throwable = null) extends Throwable(msg, cause) - - object UnexpectedReificationError extends UnexpectedReificationErrorExtractor { - def unapply(error: UnexpectedReificationError): Option[(Position, String, Throwable)] = Some((error.pos, error.msg, error.cause)) - } } diff --git a/src/compiler/scala/reflect/reify/Errors.scala b/src/compiler/scala/reflect/reify/Errors.scala index 30c6c06c7b..1a881455f2 100644 --- a/src/compiler/scala/reflect/reify/Errors.scala +++ b/src/compiler/scala/reflect/reify/Errors.scala @@ -1,7 +1,8 @@ package scala.reflect package reify -import scala.tools.nsc.Global +import scala.reflect.makro.ReificationError +import scala.reflect.makro.UnexpectedReificationError trait Errors { self: Reifier => @@ -9,9 +10,6 @@ trait Errors { import mirror._ import definitions._ - class ReificationError(var pos: Position, val msg: String) extends Throwable(msg) - class UnexpectedReificationError(val pos: Position, val msg: String, val cause: Throwable = null) extends Throwable(msg) - lazy val defaultErrorPosition: Position = mirror.analyzer.openMacros.find(c => c.macroApplication.pos != NoPosition).map(_.macroApplication.pos).getOrElse(NoPosition) @@ -60,4 +58,4 @@ trait Errors { val msg = "internal error: erroneous reifees are not supported, make sure that your reifee has typechecked successfully before passing it to the reifier" throw new UnexpectedReificationError(defaultErrorPosition, msg) } -} \ No newline at end of file +} diff --git a/src/compiler/scala/reflect/reify/Reifier.scala b/src/compiler/scala/reflect/reify/Reifier.scala index c89ebf0d39..fea825358e 100644 --- a/src/compiler/scala/reflect/reify/Reifier.scala +++ b/src/compiler/scala/reflect/reify/Reifier.scala @@ -2,6 +2,8 @@ package scala.reflect package reify import scala.tools.nsc.Global +import scala.reflect.makro.ReificationError +import scala.reflect.makro.UnexpectedReificationError /** Given a tree or a type, generate a tree that when executed at runtime produces the original tree or type. * See more info in the comments to ``reify'' in scala.reflect.api.Universe. @@ -21,7 +23,7 @@ abstract class Reifier extends Phases val prefix: Tree val reifee: Any val dontSpliceAtTopLevel: Boolean - val requireConcreteTypeTag: Boolean + val concrete: Boolean /** * For ``reifee'' and other reification parameters, generate a tree of the form @@ -47,15 +49,6 @@ abstract class Reifier extends Phases if (prefix exists (_.isErroneous)) CannotReifyErroneousPrefix(prefix) if (prefix.tpe == null) CannotReifyUntypedPrefix(prefix) - def reifyErasure(tpe: Type): Tree = { - val result = typer.resolveClassTag(positionBearer, tpe) - if (result == EmptyTree) throw new Error("cannot reify erasure for %s: ".format(tpe)) - result match { - case Apply(TypeApply(Select(_, _), _), List(clazz)) => clazz - case _ => Select(result, nme.erasure) - } - } - val rtree = reifee match { case tree: Tree => reifyTrace("reifying = ")(if (opt.showTrees) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString) @@ -81,11 +74,11 @@ abstract class Reifier extends Phases if (tree.tpe exists (sub => sub.typeSymbol.isLocalToReifee)) CannotReifyReifeeThatHasTypeLocalToReifee(tree) - val manifestedType = typer.packedType(tree, NoSymbol) - val tagModule = if (definitelyConcrete) ConcreteTypeTagModule else TypeTagModule - val tagCtor = TypeApply(Select(Ident(nme.MIRROR_SHORT), tagModule.name), List(TypeTree(manifestedType))) - val exprCtor = TypeApply(Select(Ident(nme.MIRROR_SHORT), ExprModule.name), List(TypeTree(manifestedType))) - val tagArgs = if (definitelyConcrete) List(reify(manifestedType), reifyErasure(manifestedType)) else List(reify(manifestedType)) + val taggedType = typer.packedType(tree, NoSymbol) + val tagModule = if (reificationIsConcrete) ConcreteTypeTagModule else TypeTagModule + val tagCtor = TypeApply(Select(Ident(nme.MIRROR_SHORT), tagModule.name), List(TypeTree(taggedType))) + val exprCtor = TypeApply(Select(Ident(nme.MIRROR_SHORT), ExprModule.name), List(TypeTree(taggedType))) + val tagArgs = List(reify(taggedType), reifyErasure(mirror)(typer, taggedType, concrete = false)) Apply(Apply(exprCtor, List(rtree)), List(Apply(tagCtor, tagArgs))) case tpe: Type => @@ -93,10 +86,10 @@ abstract class Reifier extends Phases reifyTrace("prefix = ")(prefix) val rtree = reify(tpe) - val manifestedType = tpe - val tagModule = if (definitelyConcrete) ConcreteTypeTagModule else TypeTagModule - val ctor = TypeApply(Select(Ident(nme.MIRROR_SHORT), tagModule.name), List(TypeTree(manifestedType))) - val args = if (definitelyConcrete) List(rtree, reifyErasure(manifestedType)) else List(rtree) + val taggedType = tpe + val tagModule = if (reificationIsConcrete) ConcreteTypeTagModule else TypeTagModule + val ctor = TypeApply(Select(Ident(nme.MIRROR_SHORT), tagModule.name), List(TypeTree(taggedType))) + val args = List(rtree, reifyErasure(mirror)(typer, taggedType, concrete = false)) Apply(ctor, args) case _ => @@ -137,9 +130,16 @@ abstract class Reifier extends Phases // 4) trivial tree splice inlining in Reify (Trees.scala) // 5) trivial type splice inlining in Reify (Types.scala) val freevarBindings = symbolTable collect { case entry @ FreeDef(_, _, binding, _, _) => binding.symbol } toSet + // [Eugene] yeah, ugly and extremely brittle, but we do need to do resetAttrs. will be fixed later + var importantSymbols = Set[Symbol](PredefModule, ScalaRunTimeModule) + importantSymbols ++= importantSymbols map (_.companionSymbol) + importantSymbols ++= importantSymbols map (_.moduleClass) + importantSymbols ++= importantSymbols map (_.linkedClassOfClass) + def importantSymbol(sym: Symbol): Boolean = sym != null && sym != NoSymbol && importantSymbols(sym) val untyped = resetAllAttrs(wrapped, leaveAlone = { case ValDef(_, mr, _, _) if mr == nme.MIRROR_SHORT => true case tree if freevarBindings contains tree.symbol => true + case tree if importantSymbol(tree.symbol) => true case _ => false }) diff --git a/src/compiler/scala/reflect/reify/codegen/Symbols.scala b/src/compiler/scala/reflect/reify/codegen/Symbols.scala index 7f8b9c53b6..21a08b7efb 100644 --- a/src/compiler/scala/reflect/reify/codegen/Symbols.scala +++ b/src/compiler/scala/reflect/reify/codegen/Symbols.scala @@ -76,7 +76,7 @@ trait Symbols { case None => if (reifyDebug) println("Free type: %s (%s)".format(sym, sym.accurateKindString)) var name = newTermName(nme.MIRROR_FREE_PREFIX + sym.name) - val phantomTypeTag = Apply(TypeApply(Select(Ident(nme.MIRROR_SHORT), nme.TypeTag), List(value)), List(Literal(Constant(null)))) + val phantomTypeTag = Apply(TypeApply(Select(Ident(nme.MIRROR_SHORT), nme.TypeTag), List(value)), List(Literal(Constant(null)), Literal(Constant(null)))) val flavor = if (sym.isExistential) nme.newFreeExistential else nme.newFreeType locallyReify(sym, name, mirrorCall(flavor, reify(sym.name.toString), reify(sym.info), phantomTypeTag, reify(sym.flags), reify(origin(sym)))) } diff --git a/src/compiler/scala/reflect/reify/codegen/Types.scala b/src/compiler/scala/reflect/reify/codegen/Types.scala index e2a2a69828..841ec61e60 100644 --- a/src/compiler/scala/reflect/reify/codegen/Types.scala +++ b/src/compiler/scala/reflect/reify/codegen/Types.scala @@ -65,11 +65,11 @@ trait Types { private var spliceTypesEnabled = !dontSpliceAtTopLevel /** Keeps track of whether this reification contains abstract type parameters */ - private var _definitelyConcrete = true - def definitelyConcrete = _definitelyConcrete - def definitelyConcrete_=(value: Boolean) { - _definitelyConcrete = value - if (!value && requireConcreteTypeTag) { + private var _reificationIsConcrete = true + def reificationIsConcrete = _reificationIsConcrete + def reificationIsConcrete_=(value: Boolean) { + _reificationIsConcrete = value + if (!value && concrete) { assert(current.isInstanceOf[Type], current) val offender = current.asInstanceOf[Type] CannotReifyConcreteTypeTagHavingUnresolvedTypeParameters(offender) @@ -89,7 +89,7 @@ trait Types { if (reifyDebug) println("splicing " + tpe) if (spliceTypesEnabled) { - var tagClass = if (requireConcreteTypeTag) ConcreteTypeTagClass else TypeTagClass + var tagClass = if (concrete) ConcreteTypeTagClass else TypeTagClass val tagTpe = singleType(prefix.tpe, prefix.tpe member tagClass.name) // [Eugene] this should be enough for an abstract type, right? @@ -99,13 +99,13 @@ trait Types { // if this fails, it might produce the dreaded "erroneous or inaccessible type" error // to find out the whereabouts of the error run scalac with -Ydebug if (reifyDebug) println("launching implicit search for %s.%s[%s]".format(prefix, tagClass.name, tpe)) - typer.resolveTypeTag(positionBearer, prefix.tpe, tpe, requireConcreteTypeTag) match { + typer.resolveTypeTag(positionBearer.pos, prefix.tpe, tpe, concrete) match { case failure if failure.isEmpty => if (reifyDebug) println("implicit search was fruitless") EmptyTree case success => if (reifyDebug) println("implicit search has produced a result: " + success) - definitelyConcrete &= requireConcreteTypeTag + reificationIsConcrete &= concrete var splice = Select(success, nme.tpe) splice match { case InlinedTypeSplice(_, inlinedSymbolTable, tpe) => @@ -123,7 +123,7 @@ trait Types { if (reifyDebug) println("splicing has been cancelled: spliceTypesEnabled = false") } - definitelyConcrete = false + reificationIsConcrete = false } spliceTypesEnabled = true diff --git a/src/compiler/scala/reflect/reify/package.scala b/src/compiler/scala/reflect/reify/package.scala index 85cf92fe2f..fa11c6313d 100644 --- a/src/compiler/scala/reflect/reify/package.scala +++ b/src/compiler/scala/reflect/reify/package.scala @@ -1,14 +1,16 @@ package scala.reflect import scala.tools.nsc.Global +import scala.reflect.makro.ReificationError +import scala.reflect.makro.UnexpectedReificationError package object reify { - def mkReifier(global: Global)(typer: global.analyzer.Typer, prefix: global.Tree, reifee: Any, dontSpliceAtTopLevel: Boolean = false, requireConcreteTypeTag: Boolean = false): Reifier { val mirror: global.type } = { + private def mkReifier(global: Global)(typer: global.analyzer.Typer, prefix: global.Tree, reifee: Any, dontSpliceAtTopLevel: Boolean = false, concrete: Boolean = false): Reifier { val mirror: global.type } = { val typer1: typer.type = typer val prefix1: prefix.type = prefix val reifee1 = reifee val dontSpliceAtTopLevel1 = dontSpliceAtTopLevel - val requireConcreteTypeTag1 = requireConcreteTypeTag + val concrete1 = concrete new { val mirror: global.type = global @@ -16,7 +18,37 @@ package object reify { val prefix = prefix1 val reifee = reifee1 val dontSpliceAtTopLevel = dontSpliceAtTopLevel1 - val requireConcreteTypeTag = requireConcreteTypeTag1 + val concrete = concrete1 } with Reifier } + + def reifyTree(global: Global)(typer: global.analyzer.Typer, prefix: global.Tree, tree: global.Tree): global.Tree = + mkReifier(global)(typer, prefix, tree, false, false).reified.asInstanceOf[global.Tree] + + def reifyType(global: Global)(typer: global.analyzer.Typer, prefix: global.Tree, tpe: global.Type, dontSpliceAtTopLevel: Boolean = false, concrete: Boolean = false): global.Tree = + mkReifier(global)(typer, prefix, tpe, dontSpliceAtTopLevel, concrete).reified.asInstanceOf[global.Tree] + + def reifyErasure(global: Global)(typer0: global.analyzer.Typer, tpe: global.Type, concrete: Boolean = true): global.Tree = { + import global._ + import definitions._ + val positionBearer = analyzer.openMacros.find(_.macroApplication.pos != NoPosition).map(_.macroApplication).getOrElse(EmptyTree).asInstanceOf[Tree] + val inScope = typer0.context.withMacrosDisabled(typer0.resolveErasureTag(positionBearer.pos, tpe, concrete = concrete), typer0.resolveArrayTag(positionBearer.pos, tpe)) + inScope match { + case (success, _) if !success.isEmpty => + Select(success, nme.erasure) + case (_, success) if !success.isEmpty => + gen.mkMethodCall(arrayElementClassMethod, List(success)) + case _ => + if (tpe.typeSymbol == ArrayClass) { + val componentTpe = tpe.typeArguments(0) + val componentErasure = reifyErasure(global)(typer0, componentTpe, concrete) + gen.mkMethodCall(arrayClassMethod, List(componentErasure)) + } else { + if (tpe.isSpliceable && concrete) throw new ReificationError(positionBearer.pos, "tpe %s is an unresolved spliceable type".format(tpe)) + var erasure = tpe.erasure + if (tpe.typeSymbol.isDerivedValueClass && global.phase.id < global.currentRun.erasurePhase.id) erasure = tpe + gen.mkNullaryCall(Predef_classOf, List(erasure)) + } + } + } } diff --git a/src/compiler/scala/tools/nsc/interpreter/RichClass.scala b/src/compiler/scala/tools/nsc/interpreter/RichClass.scala index b1bee6ce93..3d4d22063e 100644 --- a/src/compiler/scala/tools/nsc/interpreter/RichClass.scala +++ b/src/compiler/scala/tools/nsc/interpreter/RichClass.scala @@ -6,8 +6,10 @@ package scala.tools.nsc package interpreter +import scala.reflect.{mirror => rm} + class RichClass[T](val clazz: Class[T]) { - def toManifest: Manifest[T] = Manifest[T](ClassManifest[T](clazz).tpe) + def toManifest: Manifest[T] = Manifest[T](rm.classToType(clazz)) def toTypeString: String = TypeStrings.fromClazz(clazz) // Sadly isAnonymousClass does not return true for scala anonymous diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 45dacd5c14..c766b52159 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -617,8 +617,12 @@ abstract class Erasure extends AddInterfaces // See SI-4731 for one example of how this occurs. log("Attempted to cast to Unit: " + tree) tree.duplicate setType pt - } - else gen.mkAttributedCast(tree, pt) + } else if (tree.tpe != null && tree.tpe.typeSymbol == ArrayClass && pt.typeSymbol == ArrayClass) { + // See SI-2386 for one example of when this might be necessary. + val needsExtraCast = isScalaValueType(tree.tpe.typeArgs.head) && !isScalaValueType(pt.typeArgs.head) + val tree1 = if (needsExtraCast) gen.mkRuntimeCall(nme.toObjectArray, List(tree)) else tree + gen.mkAttributedCast(tree1, pt) + } else gen.mkAttributedCast(tree, pt) } /** Adapt `tree` to expected type `pt`. @@ -992,7 +996,7 @@ abstract class Erasure extends AddInterfaces } // Rewrite 5.getClass to ScalaRunTime.anyValClass(5) else if (isPrimitiveValueClass(qual.tpe.typeSymbol)) - global.typer.typed(gen.mkRuntimeCall(nme.anyValClass, List(qual, typer.resolveClassTag(tree, qual.tpe.widen)))) + global.typer.typed(gen.mkRuntimeCall(nme.anyValClass, List(qual, typer.resolveErasureTag(tree.pos, qual.tpe.widen, true)))) else tree diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 6b894a724f..35e26b39b5 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -486,7 +486,7 @@ abstract class UnCurry extends InfoTransform val toArraySym = tree.tpe member nme.toArray assert(toArraySym != NoSymbol) def getClassTag(tp: Type): Tree = { - val tag = localTyper.resolveClassTag(tree, tp) + val tag = localTyper.resolveArrayTag(tree.pos, tp) // Don't want bottom types getting any further than this (SI-4024) if (tp.typeSymbol.isBottomClass) getClassTag(AnyClass.tpe) else if (!tag.isEmpty) tag diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index f8da6a462d..3f4e941ec6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -1120,9 +1120,10 @@ trait Implicits { implicitInfoss1 } - // these should be lazy, otherwise we wouldn't be able to compile scala-library with starr - private val TagSymbols = Set[Symbol](ClassTagClass, TypeTagClass, ConcreteTypeTagClass) - private val TagMaterializers = Map[Symbol, MethodSymbol]( + private def TagSymbols = TagMaterializers.keySet + private val TagMaterializers = Map[Symbol, Symbol]( + ArrayTagClass -> MacroInternal_materializeArrayTag, + ErasureTagClass -> MacroInternal_materializeErasureTag, ClassTagClass -> MacroInternal_materializeClassTag, TypeTagClass -> MacroInternal_materializeTypeTag, ConcreteTypeTagClass -> MacroInternal_materializeConcreteTypeTag @@ -1143,10 +1144,7 @@ trait Implicits { val prefix = ( // ClassTags only exist for scala.reflect.mirror, so their materializer // doesn't care about prefixes - if (tagClass eq ClassTagClass) ( - gen.mkAttributedRef(Reflect_mirror) - setType singleType(Reflect_mirror.owner.thisPrefix, Reflect_mirror) - ) + if ((tagClass eq ArrayTagClass) || (tagClass eq ErasureTagClass) || (tagClass eq ClassTagClass)) ReflectMirrorPrefix else pre match { // [Eugene to Martin] this is the crux of the interaction between // implicits and reifiers here we need to turn a (supposedly @@ -1173,7 +1171,7 @@ trait Implicits { else failure(materializer, "macros are disabled") } - /** The manifest corresponding to type `pt`, provided `pt` is an instance of Manifest. + /** The tag corresponding to type `pt`, provided `pt` is a flavor of a tag. */ private def implicitTagOrOfExpectedType(pt: Type): SearchResult = pt.dealias match { case TypeRef(pre, sym, arg :: Nil) if TagSymbols(sym) => @@ -1183,13 +1181,13 @@ trait Implicits { case _ => searchImplicit(implicitsOfExpectedType, false) // shouldn't we pass `pt` to `implicitsOfExpectedType`, or is the recursive case - // for an abstract type really only meant for manifests? + // for an abstract type really only meant for tags? } /** The result of the implicit search: * First search implicits visible in current context. * If that fails, search implicits in expected type `pt`. - * // [Eugene] the following two lines should be deleted after we migrate delegate manifest materialization to implicit macros + * // [Eugene] the following two lines should be deleted after we migrate delegate tag materialization to implicit macros * If that fails, and `pt` is an instance of a ClassTag, try to construct a class tag. * If that fails, and `pt` is an instance of a TypeTag, try to construct a type tag. * If all fails return SearchFailure diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 9b4dd09c98..5d4cd0be77 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -155,7 +155,7 @@ trait Macros { self: Analyzer => case TypeRef(SingleType(NoPrefix, contextParam), sym, List(tparam)) => var wannabe = sym while (wannabe.isAliasType) wannabe = wannabe.info.typeSymbol - if (wannabe != definitions.TypeTagClass) + if (wannabe != definitions.TypeTagClass && wannabe != definitions.ConcreteTypeTagClass) List(param) else transform(param, tparam.typeSymbol) map (_ :: Nil) getOrElse Nil @@ -353,6 +353,16 @@ trait Macros { self: Analyzer => if (actparamss.length != reqparamss.length) compatibilityError("number of parameter sections differ") + def checkSubType(slot: String, reqtpe: Type, acttpe: Type): Unit = { + val ok = if (macroDebug) { + if (reqtpe eq acttpe) println(reqtpe + " <: " + acttpe + "?" + EOL + "true") + withTypesExplained(reqtpe <:< acttpe) + } else reqtpe <:< acttpe + if (!ok) { + compatibilityError("type mismatch for %s: %s does not conform to %s".format(slot, reqtpe.toString.abbreviateCoreAliases, acttpe.toString.abbreviateCoreAliases)) + } + } + if (!hasErrors) { try { for ((rparams, aparams) <- reqparamss zip actparamss) { @@ -378,27 +388,19 @@ trait Macros { self: Analyzer => compatibilityError("types incompatible for parameter "+aparam.name+": corresponding is not a vararg parameter") if (!hasErrors) { var atpe = aparam.tpe.substSym(flatactparams, flatreqparams).instantiateTypeParams(tparams, tvars) - // strip the { type PrefixType = ... } refinement off the Context or otherwise we get compatibility errors atpe = atpe match { case RefinedType(List(tpe), Scope(sym)) if tpe == MacroContextClass.tpe && sym.allOverriddenSymbols.contains(MacroContextPrefixType) => tpe case _ => atpe } - - val ok = if (macroDebug) withTypesExplained(rparam.tpe <:< atpe) else rparam.tpe <:< atpe - if (!ok) { - compatibilityError("type mismatch for parameter "+rparam.name+": "+rparam.tpe.toString.abbreviateCoreAliases+" does not conform to "+atpe) - } + checkSubType("parameter " + rparam.name, rparam.tpe, atpe) } } } } if (!hasErrors) { val atpe = actres.substSym(flatactparams, flatreqparams).instantiateTypeParams(tparams, tvars) - val ok = if (macroDebug) withTypesExplained(atpe <:< reqres) else atpe <:< reqres - if (!ok) { - compatibilityError("type mismatch for return type : "+reqres.toString.abbreviateCoreAliases+" does not conform to "+(if (ddef.tpt.tpe != null) atpe.toString else atpe.toString.abbreviateCoreAliases)) - } + checkSubType("return type", atpe, reqres) } if (!hasErrors) { val targs = solvedTypes(tvars, tparams, tparams map varianceInType(actres), false, @@ -873,9 +875,8 @@ trait Macros { self: Analyzer => // then T and U need to be inferred from the lexical scope of the call using ``asSeenFrom'' // whereas V won't be resolved by asSeenFrom and need to be loaded directly from ``expandee'' which needs to contain a TypeApply node // also, macro implementation reference may contain a regular type as a type argument, then we pass it verbatim - paramss = transformTypeTagEvidenceParams(paramss, (param, tparam) => Some(tparam)) - if (paramss.lastOption map (params => !params.isEmpty && params.forall(_.isType)) getOrElse false) argss = argss :+ Nil - val evidences = paramss.last takeWhile (_.isType) map (tparam => { + val resolved = collection.mutable.Map[Symbol, Type]() + paramss = transformTypeTagEvidenceParams(paramss, (param, tparam) => { val TypeApply(_, implRefTargs) = ann.args(0) var implRefTarg = implRefTargs(tparam.paramPos).tpe.typeSymbol val tpe = if (implRefTarg.isTypeParameterOrSkolem) { @@ -892,12 +893,27 @@ trait Macros { self: Analyzer => } else implRefTarg.tpe if (macroDebug) println("resolved tparam %s as %s".format(tparam, tpe)) - tpe - }) map (tpe => { - val ttag = TypeTag(tpe) + resolved(tparam) = tpe + param.tpe.typeSymbol match { + case sym if sym == definitions.TypeTagClass => + // do nothing + case sym if sym == definitions.ConcreteTypeTagClass => + if (!tpe.isConcrete) context.abort(context.enclosingPosition, "cannot create ConcreteTypeTag from a type %s having unresolved type parameters".format(tpe)) + // otherwise do nothing + case _ => + throw new Error("unsupported tpe: %s".format(tpe)) + } + Some(tparam) + }) + val tags = paramss.last takeWhile (_.isType) map (resolved(_)) map (tpe => { + // generally speaking, it's impossible to calculate erasure from a tpe here + // the tpe might be compiled by this run, so its jClass might not exist yet + // hence I just pass `null` instead and leave this puzzle to macro programmers + val ttag = TypeTag(tpe, null) if (ttag.isConcrete) ttag.toConcrete else ttag }) - argss = argss.dropRight(1) :+ (evidences ++ argss.last) + if (paramss.lastOption map (params => !params.isEmpty && params.forall(_.isType)) getOrElse false) argss = argss :+ Nil + argss = argss.dropRight(1) :+ (tags ++ argss.last) // todo. add support for context bounds in argss assert(argss.length == paramss.length, "argss: %s, paramss: %s".format(argss, paramss)) val rawArgss = for ((as, ps) <- argss zip paramss) yield { diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala index 88cea2231f..02e53cb624 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -828,6 +828,7 @@ class Foo(x: Other) { x._1 } // no error in this order private def typeTest(binderToTest: Symbol, expectedTp: Type, disableOuterCheck: Boolean = false, dynamic: Boolean = false): Tree = { import CODE._ // def coreTest = if (disableOuterCheck) codegen._isInstanceOf(binderToTest, expectedTp) else maybeWithOuterCheck(binderToTest, expectedTp)(codegen._isInstanceOf(binderToTest, expectedTp)) + // [Eugene to Adriaan] use `resolveErasureTag` instead of `findManifest`. please, provide a meaningful position // if (opt.experimental && containsUnchecked(expectedTp)) { // if (dynamic) { // val expectedTpTagTree = findManifest(expectedTp, true) diff --git a/src/compiler/scala/tools/nsc/typechecker/Taggings.scala b/src/compiler/scala/tools/nsc/typechecker/Taggings.scala new file mode 100644 index 0000000000..d276b39f16 --- /dev/null +++ b/src/compiler/scala/tools/nsc/typechecker/Taggings.scala @@ -0,0 +1,71 @@ +package scala.tools.nsc +package typechecker + +trait Taggings { + self: Analyzer => + + import global._ + import definitions._ + + trait Tagging { + self: Typer => + + private def resolveTag(pos: Position, taggedTp: Type) = beforeTyper { + inferImplicit( + EmptyTree, + taggedTp, + /*reportAmbiguous =*/ true, + /*isView =*/ false, + /*context =*/ context, + /*saveAmbiguousDivergent =*/ true, + /*pos =*/ pos + ).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]. + * + * @returns Tree that represents an `scala.reflect.ArrayTag` for `tp` if everything is okay. + * EmptyTree if the result contains unresolved (i.e. not spliced) type parameters and abstract type members. + */ + def resolveArrayTag(pos: Position, tp: Type): Tree = { + val taggedTp = appliedType(ArrayTagClass.typeConstructor, List(tp)) + resolveTag(pos, taggedTp) + } + + /** Finds in scope or materializes an ErasureTag (if `concrete` is false) or a ClassTag (if `concrete` is true). + * Should be used instead of ClassTag or ClassManifest every time compiler needs to persist an erasure. + * + * @param pos Position for error reporting. Please, provide meaningful value. + * @param tp Type we're looking an ErasureTag for, e.g. resolveErasureTag(pos, IntClass.tpe, true) will look for ClassTag[Int]. + * @param concrete If true then the result must not contain unresolved (i.e. not spliced) type parameters and abstract type members. + * If false then the function will always succeed (abstract types will be erased to their upper bounds). + * + * @returns Tree that represents an `scala.reflect.ErasureTag` for `tp` if everything is okay. + * EmptyTree if `concrete` is true and the result contains unresolved (i.e. not spliced) type parameters and abstract type members. + */ + def resolveErasureTag(pos: Position, tp: Type, concrete: Boolean): Tree = { + val taggedTp = appliedType(if (concrete) ClassTagClass.typeConstructor else ErasureTagClass.typeConstructor, List(tp)) + resolveTag(pos, taggedTp) + } + + /** Finds in scope or materializes a TypeTag (if `concrete` is false) or a ConcreteTypeTag (if `concrete` is true). + * + * @param pos Position for error reporting. Please, provide meaningful value. + * @param pre Prefix that represents a universe this type tag will be bound to. + * @param tp Type we're looking a TypeTag for, e.g. resolveTypeTag(pos, reflectMirrorPrefix, IntClass.tpe, false) will look for scala.reflect.mirror.TypeTag[Int]. + * @param concrete If true then the result must not contain unresolved (i.e. not spliced) type parameters and abstract type members. + * If false then the function will always succeed (abstract types will be reified as free types). + * + * @returns Tree that represents a `scala.reflect.TypeTag` for `tp` if everything is okay. + * EmptyTree if `concrete` is true and the result contains unresolved (i.e. not spliced) type parameters and abstract type members. + */ + def resolveTypeTag(pos: Position, pre: Type, tp: Type, concrete: Boolean): Tree = { + val taggedTp = appliedType(singleType(pre, pre member (if (concrete) ConcreteTypeTagClass else TypeTagClass).name), List(tp)) + resolveTag(pos, taggedTp) + } + } +} \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 54be9c9a87..ba6a363095 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -26,7 +26,7 @@ import util.Statistics._ * @author Martin Odersky * @version 1.0 */ -trait Typers extends Modes with Adaptations with PatMatVirtualiser { +trait Typers extends Modes with Adaptations with Taggings with PatMatVirtualiser { self: Analyzer => import global._ @@ -83,7 +83,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { private def isPastTyper = phase.id > currentRun.typerPhase.id - abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation with TyperContextErrors { + abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation with Tagging with TyperContextErrors { import context0.unit import typeDebug.{ ptTree, ptBlock, ptLine } import TyperErrorGen._ @@ -830,11 +830,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { context.undetparams = inferExprInstance(tree, context.extractUndetparams(), pt, // approximate types that depend on arguments since dependency on implicit argument is like dependency on type parameter mt.approximate, - // if we are looking for a manifest, instantiate type to Nothing anyway, - // as we would get ambiguity errors otherwise. Example - // Looking for a manifest of Nil: This has many potential types, - // so we need to instantiate to minimal type List[Nothing]. - keepNothings = false, // retract Nothing's that indicate failure, ambiguities in manifests are dealt with in manifestOfType + keepNothings = false, useWeaklyCompatible = true) // #3808 } @@ -3103,7 +3099,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (annInfo.atp.isErroneous) { hasError = true; None } else Some(NestedAnnotArg(annInfo)) - // use of Array.apply[T: ClassManifest](xs: T*): Array[T] + // use of Array.apply[T: ArrayTag](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) @@ -4840,12 +4836,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // [Eugene] no more MaxArrayDims. ClassTags are flexible enough to allow creation of arrays of arbitrary dimensionality (w.r.t JVM restrictions) 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 = resolveClassTag(tree, tagType) + val newArrayApp = atPos(tree.pos) { + val tag = resolveArrayTag(tree.pos, tagType) if (tag.isEmpty) MissingClassTagError(tree, tagType) else new ApplyToImplicitArgs(Select(tag, nme.newArray), args) - } - typed(newArrayApp, mode, pt) + } + typed(newArrayApp, mode, pt) case tree1 => tree1 } @@ -5210,36 +5206,6 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case None => typed(tree, mode, pt) } - // `tree` is only necessary here for its position - // but that's invaluable for error reporting, so I decided to include it into this method's contract - // before passing EmptyTree, please, consider passing something meaningful first - def resolveClassTag(tree: Tree, tp: Type): Tree = beforeTyper { - inferImplicit( - EmptyTree, - appliedType(ClassTagClass.typeConstructor, List(tp)), - /*reportAmbiguous =*/ true, - /*isView =*/ false, - /*context =*/ context, - /*saveAmbiguousDivergent =*/ true, - /*pos =*/ tree.pos - ).tree - } - - // `tree` is only necessary here for its position - // but that's invaluable for error reporting, so I decided to include it into this method's contract - // before passing EmptyTree, please, consider passing something meaningful first - def resolveTypeTag(tree: Tree, pre: Type, tp: Type, full: Boolean): Tree = beforeTyper { - inferImplicit( - EmptyTree, - appliedType(singleType(pre, pre member (if (full) ConcreteTypeTagClass else TypeTagClass).name), List(tp)), - /*reportAmbiguous =*/ true, - /*isView =*/ false, - /*context =*/ context, - /*saveAmbiguousDivergent =*/ true, - /*pos =*/ tree.pos - ).tree - } - /* def convertToTypeTree(tree: Tree): Tree = tree match { case TypeTree() => tree diff --git a/src/compiler/scala/tools/reflect/package.scala b/src/compiler/scala/tools/reflect/package.scala index f5c836a4e9..744bf9b226 100644 --- a/src/compiler/scala/tools/reflect/package.scala +++ b/src/compiler/scala/tools/reflect/package.scala @@ -7,6 +7,7 @@ package scala.tools import java.lang.reflect.Method import java.{ lang => jl } +import scala.reflect.{mirror => rm} package object reflect { def nameAndArity(m: Method) = (m.getName, m.getParameterTypes.size) @@ -27,7 +28,7 @@ package object reflect { } } - def zeroOfClass(clazz: Class[_]) = zeroOf(Manifest(ClassManifest(clazz).tpe)) + def zeroOfClass(clazz: Class[_]) = zeroOf(Manifest(rm.classToType(clazz))) def zeroOf[T](implicit m: Manifest[T]): AnyRef = { if (m == manifest[Boolean] || m == manifest[jl.Boolean]) false: jl.Boolean else if (m == manifest[Unit] || m == manifest[jl.Void] || m == manifest[scala.runtime.BoxedUnit]) scala.runtime.BoxedUnit.UNIT diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala index 15e007528b..093f972f72 100644 --- a/src/library/scala/Predef.scala +++ b/src/library/scala/Predef.scala @@ -119,20 +119,24 @@ object Predef extends LowPriorityImplicits { def optManifest[T](implicit m: OptManifest[T]) = m // Tag types and companions, and incantations for summoning - type ClassTag[T] = scala.reflect.ClassTag[T] - type TypeTag[T] = scala.reflect.TypeTag[T] - type ConcreteTypeTag[T] = scala.reflect.ConcreteTypeTag[T] - val ClassTag = scala.reflect.ClassTag // doesn't need to be lazy, because it's not a path-dependent type + type ArrayTag[T] = scala.reflect.ArrayTag[T] + type ErasureTag[T] = scala.reflect.ErasureTag[T] + type ClassTag[T] = scala.reflect.ClassTag[T] + type TypeTag[T] = scala.reflect.TypeTag[T] + type ConcreteTypeTag[T] = scala.reflect.ConcreteTypeTag[T] + val ClassTag = scala.reflect.ClassTag // doesn't need to be lazy, because it's not a path-dependent type // [Paul to Eugene] No lazy vals in Predef. Too expensive. Have to work harder on breaking initialization dependencies. - lazy val TypeTag = scala.reflect.TypeTag // needs to be lazy, because requires scala.reflect.mirror instance - lazy val ConcreteTypeTag = scala.reflect.ConcreteTypeTag + lazy val TypeTag = scala.reflect.TypeTag // needs to be lazy, because requires scala.reflect.mirror instance + lazy val ConcreteTypeTag = scala.reflect.ConcreteTypeTag // [Eugene to Martin] it's really tedious to type "implicitly[...]" all the time, so I'm reintroducing these shortcuts - def classTag[T](implicit ctag: ClassTag[T]) = ctag - def tag[T](implicit ttag: TypeTag[T]) = ttag - def typeTag[T](implicit ttag: TypeTag[T]) = ttag - def concreteTag[T](implicit cttag: ConcreteTypeTag[T]) = cttag - def concreteTypeTag[T](implicit cttag: ConcreteTypeTag[T]) = cttag + def arrayTag[T](implicit atag: ArrayTag[T]) = atag + def erasureTag[T](implicit etag: ErasureTag[T]) = etag + def classTag[T](implicit ctag: ClassTag[T]) = ctag + def tag[T](implicit ttag: TypeTag[T]) = ttag + def typeTag[T](implicit ttag: TypeTag[T]) = ttag + def concreteTag[T](implicit cttag: ConcreteTypeTag[T]) = cttag + def concreteTypeTag[T](implicit cttag: ConcreteTypeTag[T]) = cttag // Minor variations on identity functions def identity[A](x: A): A = x // @see `conforms` for the implicit version diff --git a/src/library/scala/reflect/ArrayTag.scala b/src/library/scala/reflect/ArrayTag.scala index 8df7fe5f4e..ba0c075723 100644 --- a/src/library/scala/reflect/ArrayTag.scala +++ b/src/library/scala/reflect/ArrayTag.scala @@ -3,11 +3,17 @@ package scala.reflect /** An `ArrayTag[T]` is a descriptor that is requested by the compiler every time * when an array is instantiated, but the element type is unknown at compile time. * + * Implicit in the contract of `ArrayTag[T]` is the fact that `T` + * cannot contain unresolved references to type parameters or abstract types. + * * Scala library provides a standard implementation of this trait, - * `ClassTag[T]` that explicitly carries the `java.lang.Class` erasure of type T. + * `ClassTag[T]` that explicitly carries the `java.lang.Class` erasure of type T + * and uses Java reflection to instantiate arrays. * * However other platforms (e.g. a Scala -> JS crosscompiler) may reimplement this trait as they see fit * and then expose the implementation via an implicit macro. + * + * @see [[scala.reflect.api.TypeTags]] */ @annotation.implicitNotFound(msg = "No ArrayTag available for ${T}") trait ArrayTag[T] { diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala index 142025f600..e485691747 100644 --- a/src/library/scala/reflect/ClassTag.scala +++ b/src/library/scala/reflect/ClassTag.scala @@ -3,6 +3,7 @@ package scala.reflect import java.lang.{ Class => jClass } import scala.reflect.{ mirror => rm } import language.{implicitConversions, existentials} +import scala.runtime.ScalaRunTime.arrayClass /** A `ClassTag[T]` wraps a Java class, which can be accessed via the `erasure` method. * @@ -18,34 +19,17 @@ import language.{implicitConversions, existentials} * If the type T contains unresolved references to type parameters or abstract types, a static error results. * * A ConcreteTypeTag member of the reflect.mirror object is convertible to a ClassTag via an implicit conversion - * (this is not possible to do in all reflection universes because an operation that converts a type to a Java class might not be available). */ -// please, don't add any APIs here, like it was with `newWrappedArray` and `newArrayBuilder` -// class tags, and all tags in general, should be as minimalistic as possible + * (this is not possible to do in all reflection universes because an operation that converts a type to a Java class might not be available). + * + * @see [[scala.reflect.api.TypeTags]] + */ @annotation.implicitNotFound(msg = "No ClassTag available for ${T}") -abstract case class ClassTag[T](erasure: jClass[_]) extends ArrayTag[T] { - // quick and dirty fix to a deadlock in Predef: - // http://groups.google.com/group/scala-internals/browse_thread/thread/977de028a4e75d6f - // todo. fix that in a sane way - // assert(erasure != null) - - /** A Scala reflection type representing T. - * For ClassTags this representation is lossy (in their case tpe is retrospectively constructed from erasure). - * For TypeTags and ConcreteTypeTags the representation is almost precise, because they use reification - * (information is lost only when T refers to non-locatable symbols, which are then reified as free variables). */ - def tpe: rm.Type = rm.classToType(erasure) - - /** A Scala reflection symbol representing T. */ - def symbol: rm.Symbol = rm.classToSymbol(erasure) +trait ClassTag[T] extends ArrayTag[T] with ErasureTag[T] with Equals with Serializable { + // please, don't add any APIs here, like it was with `newWrappedArray` and `newArrayBuilder` + // class tags, and all tags in general, should be as minimalistic as possible /** Produces a `ClassTag` that knows how to build `Array[Array[T]]` */ - def wrap: ClassTag[Array[T]] = { - // newInstance throws an exception if the erasure is Void.TYPE - // see SI-5680 - val arrayClazz = - if (erasure == java.lang.Void.TYPE) classOf[Array[Unit]] - else java.lang.reflect.Array.newInstance(erasure, 0).getClass.asInstanceOf[jClass[Array[T]]] - ClassTag[Array[T]](arrayClazz) - } + def wrap: ClassTag[Array[T]] = ClassTag[Array[T]](arrayClass(erasure)) /** Produces a new array with element type `T` and length `len` */ def newArray(len: Int): Array[T] = @@ -61,31 +45,39 @@ abstract case class ClassTag[T](erasure: jClass[_]) extends ArrayTag[T] { case java.lang.Void.TYPE => new Array[Unit](len).asInstanceOf[Array[T]] case _ => java.lang.reflect.Array.newInstance(erasure, len).asInstanceOf[Array[T]] } + + /** case class accessories */ + override def canEqual(x: Any) = x.isInstanceOf[ClassTag[_]] + override def equals(x: Any) = x.isInstanceOf[ClassTag[_]] && this.erasure == x.asInstanceOf[ClassTag[_]].erasure + override def hashCode = scala.runtime.ScalaRunTime.hash(erasure) + override def toString = "ClassTag[" + erasure + "]" } object ClassTag { + private val NothingTYPE = classOf[scala.runtime.Nothing$] + private val NullTYPE = classOf[scala.runtime.Null$] private val ObjectTYPE = classOf[java.lang.Object] private val StringTYPE = classOf[java.lang.String] - val Byte : ClassTag[scala.Byte] = new ClassTag[scala.Byte](java.lang.Byte.TYPE) { private def readResolve() = ClassTag.Byte } - val Short : ClassTag[scala.Short] = new ClassTag[scala.Short](java.lang.Short.TYPE) { private def readResolve() = ClassTag.Short } - val Char : ClassTag[scala.Char] = new ClassTag[scala.Char](java.lang.Character.TYPE) { private def readResolve() = ClassTag.Char } - val Int : ClassTag[scala.Int] = new ClassTag[scala.Int](java.lang.Integer.TYPE) { private def readResolve() = ClassTag.Int } - val Long : ClassTag[scala.Long] = new ClassTag[scala.Long](java.lang.Long.TYPE) { private def readResolve() = ClassTag.Long } - val Float : ClassTag[scala.Float] = new ClassTag[scala.Float](java.lang.Float.TYPE) { private def readResolve() = ClassTag.Float } - val Double : ClassTag[scala.Double] = new ClassTag[scala.Double](java.lang.Double.TYPE) { private def readResolve() = ClassTag.Double } - val Boolean : ClassTag[scala.Boolean] = new ClassTag[scala.Boolean](java.lang.Boolean.TYPE) { private def readResolve() = ClassTag.Boolean } - val Unit : ClassTag[scala.Unit] = new ClassTag[scala.Unit](java.lang.Void.TYPE) { private def readResolve() = ClassTag.Unit } - val Any : ClassTag[scala.Any] = new ClassTag[scala.Any](ObjectTYPE) { private def readResolve() = ClassTag.Any } - val Object : ClassTag[java.lang.Object] = new ClassTag[java.lang.Object](ObjectTYPE) { private def readResolve() = ClassTag.Object } - val AnyVal : ClassTag[scala.AnyVal] = new ClassTag[scala.AnyVal](ObjectTYPE) { private def readResolve() = ClassTag.AnyVal } - val AnyRef : ClassTag[scala.AnyRef] = new ClassTag[scala.AnyRef](ObjectTYPE) { private def readResolve() = ClassTag.AnyRef } - val Nothing : ClassTag[scala.Nothing] = new ClassTag[scala.Nothing](ObjectTYPE) { private def readResolve() = ClassTag.Nothing } - val Null : ClassTag[scala.Null] = new ClassTag[scala.Null](ObjectTYPE) { private def readResolve() = ClassTag.Null } - val String : ClassTag[java.lang.String] = new ClassTag[java.lang.String](StringTYPE) { private def readResolve() = ClassTag.String } - - def apply[T](clazz: jClass[_]): ClassTag[T] = - clazz match { + val Byte : ClassTag[scala.Byte] = new ClassTag[scala.Byte]{ def erasure = java.lang.Byte.TYPE; private def readResolve() = ClassTag.Byte } + val Short : ClassTag[scala.Short] = new ClassTag[scala.Short]{ def erasure = java.lang.Short.TYPE; private def readResolve() = ClassTag.Short } + val Char : ClassTag[scala.Char] = new ClassTag[scala.Char]{ def erasure = java.lang.Character.TYPE; private def readResolve() = ClassTag.Char } + val Int : ClassTag[scala.Int] = new ClassTag[scala.Int]{ def erasure = java.lang.Integer.TYPE; private def readResolve() = ClassTag.Int } + val Long : ClassTag[scala.Long] = new ClassTag[scala.Long]{ def erasure = java.lang.Long.TYPE; private def readResolve() = ClassTag.Long } + val Float : ClassTag[scala.Float] = new ClassTag[scala.Float]{ def erasure = java.lang.Float.TYPE; private def readResolve() = ClassTag.Float } + val Double : ClassTag[scala.Double] = new ClassTag[scala.Double]{ def erasure = java.lang.Double.TYPE; private def readResolve() = ClassTag.Double } + val Boolean : ClassTag[scala.Boolean] = new ClassTag[scala.Boolean]{ def erasure = java.lang.Boolean.TYPE; private def readResolve() = ClassTag.Boolean } + val Unit : ClassTag[scala.Unit] = new ClassTag[scala.Unit]{ def erasure = java.lang.Void.TYPE; private def readResolve() = ClassTag.Unit } + val Any : ClassTag[scala.Any] = new ClassTag[scala.Any]{ def erasure = ObjectTYPE; private def readResolve() = ClassTag.Any } + val Object : ClassTag[java.lang.Object] = new ClassTag[java.lang.Object]{ def erasure = ObjectTYPE; private def readResolve() = ClassTag.Object } + val AnyVal : ClassTag[scala.AnyVal] = new ClassTag[scala.AnyVal]{ def erasure = ObjectTYPE; private def readResolve() = ClassTag.AnyVal } + val AnyRef : ClassTag[scala.AnyRef] = new ClassTag[scala.AnyRef]{ def erasure = ObjectTYPE; private def readResolve() = ClassTag.AnyRef } + val Nothing : ClassTag[scala.Nothing] = new ClassTag[scala.Nothing]{ def erasure = NothingTYPE; private def readResolve() = ClassTag.Nothing } + val Null : ClassTag[scala.Null] = new ClassTag[scala.Null]{ def erasure = NullTYPE; private def readResolve() = ClassTag.Null } + val String : ClassTag[java.lang.String] = new ClassTag[java.lang.String]{ def erasure = StringTYPE; private def readResolve() = ClassTag.String } + + def apply[T](erasure1: jClass[_]): ClassTag[T] = + erasure1 match { case java.lang.Byte.TYPE => ClassTag.Byte.asInstanceOf[ClassTag[T]] case java.lang.Short.TYPE => ClassTag.Short.asInstanceOf[ClassTag[T]] case java.lang.Character.TYPE => ClassTag.Char.asInstanceOf[ClassTag[T]] @@ -97,128 +89,8 @@ object ClassTag { case java.lang.Void.TYPE => ClassTag.Unit.asInstanceOf[ClassTag[T]] case ObjectTYPE => ClassTag.Object.asInstanceOf[ClassTag[T]] case StringTYPE => ClassTag.String.asInstanceOf[ClassTag[T]] - case _ => new ClassTag[T](clazz) {} - } - - def apply[T](tpe: rm.Type): ClassTag[T] = - tpe match { - case rm.ByteTpe => ClassTag.Byte.asInstanceOf[ClassTag[T]] - case rm.ShortTpe => ClassTag.Short.asInstanceOf[ClassTag[T]] - case rm.CharTpe => ClassTag.Char.asInstanceOf[ClassTag[T]] - case rm.IntTpe => ClassTag.Int.asInstanceOf[ClassTag[T]] - case rm.LongTpe => ClassTag.Long.asInstanceOf[ClassTag[T]] - case rm.FloatTpe => ClassTag.Float.asInstanceOf[ClassTag[T]] - case rm.DoubleTpe => ClassTag.Double.asInstanceOf[ClassTag[T]] - case rm.BooleanTpe => ClassTag.Boolean.asInstanceOf[ClassTag[T]] - case rm.UnitTpe => ClassTag.Unit.asInstanceOf[ClassTag[T]] - case rm.AnyTpe => ClassTag.Any.asInstanceOf[ClassTag[T]] - case rm.ObjectTpe => ClassTag.Object.asInstanceOf[ClassTag[T]] - case rm.AnyValTpe => ClassTag.AnyVal.asInstanceOf[ClassTag[T]] - case rm.AnyRefTpe => ClassTag.AnyRef.asInstanceOf[ClassTag[T]] - case rm.NothingTpe => ClassTag.Nothing.asInstanceOf[ClassTag[T]] - case rm.NullTpe => ClassTag.Null.asInstanceOf[ClassTag[T]] - case rm.StringTpe => ClassTag.String.asInstanceOf[ClassTag[T]] - case _ => apply[T](rm.typeToClass(tpe.erasure)) + case _ => new ClassTag[T]{ def erasure = erasure1 } } - def apply[T](ttag: rm.ConcreteTypeTag[T]): ClassTag[T] = - if (ttag.erasure != null) ClassTag[T](ttag.erasure) - else ClassTag[T](ttag.tpe) - - implicit def toDeprecatedClassManifestApis[T](ctag: ClassTag[T]): DeprecatedClassManifestApis[T] = new DeprecatedClassManifestApis[T](ctag) - - @deprecated("Use apply instead", "2.10.0") - def fromClass[T](clazz: jClass[T]): ClassManifest[T] = apply(clazz) - - /** Manifest for the singleton type `value.type'. */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def singleType[T <: AnyRef](value: AnyRef): Manifest[T] = ??? - - /** ClassManifest for the class type `clazz', where `clazz' is - * a top-level or static class. - * @note This no-prefix, no-arguments case is separate because we - * it's called from ScalaRunTime.boxArray itself. If we - * pass varargs as arrays into this, we get an infinitely recursive call - * to boxArray. (Besides, having a separate case is more efficient) - */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def classType[T <: AnyRef](clazz: jClass[_]): ClassManifest[T] = ClassTag[T](clazz) - - /** ClassManifest for the class type `clazz[args]', where `clazz' is - * a top-level or static class and `args` are its type arguments */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def classType[T <: AnyRef](clazz: jClass[_], arg1: OptManifest[_], args: OptManifest[_]*): ClassManifest[T] = ClassTag[T](clazz) - - /** ClassManifest for the class type `clazz[args]', where `clazz' is - * a class with non-package prefix type `prefix` and type arguments `args`. - */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def classType[T <: AnyRef](prefix: OptManifest[_], clazz: jClass[_], args: OptManifest[_]*): ClassManifest[T] = ClassTag[T](clazz) - - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def arrayType[T](arg: OptManifest[_]): ClassManifest[Array[T]] = arg match { - case x: ConcreteTypeTag[_] => ClassManifest[Array[T]](x.erasure) - case _ => Object.asInstanceOf[ClassManifest[Array[T]]] // was there in 2.9.x - } - - /** ClassManifest for the abstract type `prefix # name'. `upperBound' is not - * strictly necessary as it could be obtained by reflection. It was - * added so that erasure can be calculated without reflection. */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def abstractType[T](prefix: OptManifest[_], name: String, clazz: jClass[_], args: OptManifest[_]*): ClassManifest[T] = ClassTag[T](clazz) - - /** ClassManifest for the abstract type `prefix # name'. `upperBound' is not - * strictly necessary as it could be obtained by reflection. It was - * added so that erasure can be calculated without reflection. - * todo: remove after next boostrap - */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def abstractType[T](prefix: OptManifest[_], name: String, upperbound: ClassManifest[_], args: OptManifest[_]*): ClassManifest[T] = ClassTag[T](upperbound.erasure) - - class DeprecatedClassManifestApis[T](ctag: ClassTag[T]) { - import scala.collection.mutable.{ WrappedArray, ArrayBuilder } - - @deprecated("Use `tpe` to analyze the underlying type", "2.10.0") - def <:<(that: ClassManifest[_]): Boolean = ctag.tpe <:< that.tpe - - @deprecated("Use `tpe` to analyze the underlying type", "2.10.0") - def >:>(that: ClassManifest[_]): Boolean = that <:< ctag - - @deprecated("Use `wrap` instead", "2.10.0") - def arrayManifest: ClassManifest[Array[T]] = ctag.wrap - - @deprecated("Use a combination of `wrap` and `newArray` instead", "2.10.0") - def newArray2(len: Int): Array[Array[T]] = ctag.wrap.newArray(len) - - @deprecated("Use a combination of `wrap` and `newArray` instead", "2.10.0") - def newArray3(len: Int): Array[Array[Array[T]]] = ctag.wrap.wrap.newArray(len) - - @deprecated("Use a combination of `wrap` and `newArray` instead", "2.10.0") - def newArray4(len: Int): Array[Array[Array[Array[T]]]] = ctag.wrap.wrap.wrap.newArray(len) - - @deprecated("Use a combination of `wrap` and `newArray` instead", "2.10.0") - def newArray5(len: Int): Array[Array[Array[Array[Array[T]]]]] = ctag.wrap.wrap.wrap.wrap.newArray(len) - - @deprecated("Use `@scala.collection.mutable.WrappedArray` object instead", "2.10.0") - def newWrappedArray(len: Int): WrappedArray[T] = - ctag.erasure match { - case java.lang.Byte.TYPE => new WrappedArray.ofByte(new Array[Byte](len)).asInstanceOf[WrappedArray[T]] - case java.lang.Short.TYPE => new WrappedArray.ofShort(new Array[Short](len)).asInstanceOf[WrappedArray[T]] - case java.lang.Character.TYPE => new WrappedArray.ofChar(new Array[Char](len)).asInstanceOf[WrappedArray[T]] - case java.lang.Integer.TYPE => new WrappedArray.ofInt(new Array[Int](len)).asInstanceOf[WrappedArray[T]] - case java.lang.Long.TYPE => new WrappedArray.ofLong(new Array[Long](len)).asInstanceOf[WrappedArray[T]] - case java.lang.Float.TYPE => new WrappedArray.ofFloat(new Array[Float](len)).asInstanceOf[WrappedArray[T]] - case java.lang.Double.TYPE => new WrappedArray.ofDouble(new Array[Double](len)).asInstanceOf[WrappedArray[T]] - case java.lang.Boolean.TYPE => new WrappedArray.ofBoolean(new Array[Boolean](len)).asInstanceOf[WrappedArray[T]] - case java.lang.Void.TYPE => new WrappedArray.ofUnit(new Array[Unit](len)).asInstanceOf[WrappedArray[T]] - case _ => new WrappedArray.ofRef[T with AnyRef](ctag.newArray(len).asInstanceOf[Array[T with AnyRef]]).asInstanceOf[WrappedArray[T]] - } - - @deprecated("Use `@scala.collection.mutable.ArrayBuilder` object instead", "2.10.0") - def newArrayBuilder(): ArrayBuilder[T] = ArrayBuilder.make[T]()(ctag) - - @deprecated("`typeArguments` is no longer supported, and will always return an empty list. Use `@scala.reflect.TypeTag` or `@scala.reflect.ConcreteTypeTag` to capture and analyze type arguments", "2.10.0") - def typeArguments: List[OptManifest[_]] = List() - } -} - + def unapply[T](ctag: ClassTag[T]): Option[Class[_]] = Some(ctag.erasure) +} \ No newline at end of file diff --git a/src/library/scala/reflect/DummyMirror.scala b/src/library/scala/reflect/DummyMirror.scala index dd4791e57c..8b2ddde2a1 100644 --- a/src/library/scala/reflect/DummyMirror.scala +++ b/src/library/scala/reflect/DummyMirror.scala @@ -430,6 +430,8 @@ class DummyMirror(cl: ClassLoader) extends api.Mirror { def fullName: String = notSupported() def id: Int = notSupported() def orElse[T](alt: => Symbol): Symbol = notSupported() + def filter(cond: Symbol => Boolean): Symbol = notSupported() + def suchThat(cond: Symbol => Boolean): Symbol = notSupported() def privateWithin: Symbol = notSupported() def companionSymbol: Symbol = notSupported() def moduleClass: Symbol = notSupported() diff --git a/src/library/scala/reflect/ErasureTag.scala b/src/library/scala/reflect/ErasureTag.scala new file mode 100644 index 0000000000..f95451fab2 --- /dev/null +++ b/src/library/scala/reflect/ErasureTag.scala @@ -0,0 +1,23 @@ +package scala.reflect + +import java.lang.{Class => jClass} + +/** An `ErasureTag[T]` is a descriptor that is requested by the compiler every time + * when it needs to persist an erasure of a type. + * + * Scala library provides a standard implementation of this trait, + * `TypeTag[T]` that carries the `java.lang.Class` erasure for arbitrary types. + * + * However other platforms may reimplement this trait as they see fit + * and then expose the implementation via an implicit macro. + * + * If you need to guarantee that the type does not contain + * references to type parameters or abstract types, use `ClassTag[T]`. + * + * @see [[scala.reflect.api.TypeTags]] + */ +@annotation.implicitNotFound(msg = "No ErasureTag available for ${T}") +trait ErasureTag[T] { + /** Returns an erasure of type `T` */ + def erasure: jClass[_] +} diff --git a/src/library/scala/reflect/ReflectionUtils.scala b/src/library/scala/reflect/ReflectionUtils.scala index 79a42f6ec4..6ea69cb80d 100644 --- a/src/library/scala/reflect/ReflectionUtils.scala +++ b/src/library/scala/reflect/ReflectionUtils.scala @@ -5,6 +5,7 @@ package scala.reflect +import java.lang.{Class => jClass} import java.lang.reflect.{ InvocationTargetException, UndeclaredThrowableException } /** A few java-reflection oriented utility functions useful during reflection bootstrapping. diff --git a/src/library/scala/reflect/TagMaterialization.scala b/src/library/scala/reflect/TagMaterialization.scala deleted file mode 100644 index e8d4571228..0000000000 --- a/src/library/scala/reflect/TagMaterialization.scala +++ /dev/null @@ -1,122 +0,0 @@ -package scala.reflect - -import api.Universe -import makro.Context -import language.implicitConversions - -// todo. unfortunately, current type inferencer doesn't infer type parameters of implicit values -// this means that during macro expansion these macros will get Nothing instead of real T -// Oh how much I'd love to implement this now, but I have to postpone this until we have a solution for type inference - -/** This object is required by the compiler and should not be used in client code. */ - - /** !!! Some of this code is copy-pasted four places. This situation - * should be resolved ASAP. - */ -object TagMaterialization { - def materializeClassTag[T: c.TypeTag](c: Context): c.Expr[ClassTag[T]] = { - import c.mirror._ - val tpe = implicitly[c.TypeTag[T]].tpe - c.materializeClassTag(tpe) - } - - def materializeTypeTag[T: c.TypeTag](c: Context { type PrefixType = Universe }): c.Expr[c.prefix.value.TypeTag[T]] = { - import c.mirror._ - val tpe = implicitly[c.TypeTag[T]].tpe - c.materializeTypeTag(tpe, requireConcreteTypeTag = false) - } - - def materializeConcreteTypeTag[T: c.TypeTag](c: Context { type PrefixType = Universe }): c.Expr[c.prefix.value.ConcreteTypeTag[T]] = { - import c.mirror._ - val tpe = implicitly[c.TypeTag[T]].tpe - c.materializeTypeTag(tpe, requireConcreteTypeTag = true) - } - - private implicit def context2utils(c0: Context) : Utils { val c: c0.type } = new { val c: c0.type = c0 } with Utils - - private abstract class Utils { - val c: Context - - import c.mirror._ - import definitions._ - - val coreTags = Map( - ByteClass.asType -> newTermName("Byte"), - ShortClass.asType -> newTermName("Short"), - CharClass.asType -> newTermName("Char"), - IntClass.asType -> newTermName("Int"), - LongClass.asType -> newTermName("Long"), - FloatClass.asType -> newTermName("Float"), - DoubleClass.asType -> newTermName("Double"), - BooleanClass.asType -> newTermName("Boolean"), - UnitClass.asType -> newTermName("Unit"), - AnyClass.asType -> newTermName("Any"), - ObjectClass.asType -> newTermName("Object"), - AnyValClass.asType -> newTermName("AnyVal"), - AnyRefClass.asType -> newTermName("AnyRef"), - NothingClass.asType -> newTermName("Nothing"), - NullClass.asType -> newTermName("Null")) - - val ReflectPackage = staticModule("scala.reflect.package") - val Reflect_mirror = selectTerm(ReflectPackage, "mirror") - val ClassTagClass = staticClass("scala.reflect.ClassTag") - val ClassTagErasure = selectTerm(ClassTagClass, "erasure") - val ClassTagModule = staticModule("scala.reflect.ClassTag") - val TypeTagsClass = staticClass("scala.reflect.api.TypeTags") - val TypeTagClass = selectType(TypeTagsClass, "TypeTag") - val TypeTagTpe = selectTerm(TypeTagClass, "tpe") - val TypeTagModule = selectTerm(TypeTagsClass, "TypeTag") - val ConcreteTypeTagClass = selectType(TypeTagsClass, "ConcreteTypeTag") - val ConcreteTypeTagModule = selectTerm(TypeTagsClass, "ConcreteTypeTag") - - def materializeClassTag(tpe: Type): Tree = - materializeTag(c.reflectMirrorPrefix, tpe, ClassTagModule, c.reifyErasure(tpe)) - - def materializeTypeTag(tpe: Type, requireConcreteTypeTag: Boolean): Tree = { - def prefix: Tree = ??? // todo. needs to be synthesized from c.prefix - val tagModule = if (requireConcreteTypeTag) ConcreteTypeTagModule else TypeTagModule - materializeTag(prefix, tpe, tagModule, c.reifyType(prefix, tpe, dontSpliceAtTopLevel = true, requireConcreteTypeTag = requireConcreteTypeTag)) - } - - private def materializeTag(prefix: Tree, tpe: Type, tagModule: Symbol, materializer: => Tree): Tree = { - val result = - tpe match { - case coreTpe if coreTags contains coreTpe => - Select(Select(prefix, tagModule.name), coreTags(coreTpe)) - case _ => - try materializer - catch { - case ex: Throwable => - // [Eugene] cannot pattern match on an abstract type, so had to do this - val ex1 = ex - if (ex.getClass.toString.endsWith("$ReificationError")) { - ex match { - case c.ReificationError(pos, msg) => - c.error(pos, msg) - EmptyTree - } - } else if (ex.getClass.toString.endsWith("$UnexpectedReificationError")) { - ex match { - case c.UnexpectedReificationError(pos, err, cause) => - if (cause != null) throw cause else throw ex - } - } else { - throw ex - } - } - } - try c.typeCheck(result) - catch { case terr @ c.TypeError(pos, msg) => fail(terr) } - } - - private def fail(reason: Any): Nothing = { - val Apply(TypeApply(fun, List(tpeTree)), _) = c.macroApplication - val tpe = tpeTree.tpe - val PolyType(_, MethodType(_, tagTpe)) = fun.tpe - val tagModule = tagTpe.typeSymbol.companionSymbol - if (c.compilerSettings.contains("-Xlog-implicits")) - c.echo(c.enclosingPosition, "cannot materialize " + tagModule.name + "[" + tpe + "] because:\n" + reason) - c.abort(c.enclosingPosition, "No %s available for %s".format(tagModule.name, tpe)) - } - } -} diff --git a/src/library/scala/reflect/api/Symbols.scala b/src/library/scala/reflect/api/Symbols.scala index 767246a294..dbd264c0ab 100755 --- a/src/library/scala/reflect/api/Symbols.scala +++ b/src/library/scala/reflect/api/Symbols.scala @@ -148,6 +148,14 @@ trait Symbols { self: Universe => */ def orElse[T](alt: => Symbol): Symbol + /** ... + */ + def filter(cond: Symbol => Boolean): Symbol + + /** ... + */ + def suchThat(cond: Symbol => Boolean): Symbol + /** * Set when symbol has a modifier of the form private[X], NoSymbol otherwise. * diff --git a/src/library/scala/reflect/api/TypeTags.scala b/src/library/scala/reflect/api/TypeTags.scala index b90475b15a..c58b0fcec2 100644 --- a/src/library/scala/reflect/api/TypeTags.scala +++ b/src/library/scala/reflect/api/TypeTags.scala @@ -6,7 +6,6 @@ package scala.reflect package api -import scala.reflect.{ mirror => rm } import java.lang.{ Class => jClass } import language.implicitConversions @@ -15,22 +14,41 @@ import language.implicitConversions * They are supposed to replace the pre-2.10 concept of a [[scala.reflect.Manifest]]. * TypeTags are much better integrated with reflection than manifests are, and are consequently much simpler. * - * Type tags are organized in a hierarchy of two classes: + * === Overview === + * + * Type tags are organized in a hierarchy of five classes: + * [[scala.reflect.ArrayTag]], [[scala.reflect.ErasureTag]], [[scala.reflect.ClassTag]], * [[scala.reflect.api.Universe#TypeTag]] and [[scala.reflect.api.Universe#ConcreteTypeTag]]. - * A [[scala.reflect.api.Universe#TypeTag]] value wraps a full Scala type in its tpe field. - * A [[scala.reflect.api.Universe#ConcreteTypeTag]] value is a type tag that is guaranteed not to contain any references to type parameters or abstract types. * - * It is also possible to capture Java classes by using a different kind of tag. - * A [[scala.reflect.ClassTag]] value wraps a Java class, which can be accessed via the erasure method. + * An [[scala.reflect.ArrayTag]] value carries knowledge about how to build an array of elements of type T. + * Typically such operation is performed by storing an erasure and instantiating arrays via Java reflection, + * but [[scala.reflect.ArrayTag]] only defines an interface, not an implementation, hence it only contains the factory methods + * `newArray` and `wrap` that can be used to build, correspondingly, single-dimensional and multi-dimensional arrays. * - * TypeTags correspond loosely to Manifests. More precisely: - * The previous notion of a [[scala.reflect.ClassManifest]] corresponds to a scala.reflect.ClassTag, - * The previous notion of a [[scala.reflect.Manifest]] corresponds to scala.reflect.mirror.ConcreteTypeTag, - * Whereas scala.reflect.mirror.TypeTag is approximated by the previous notion of [[scala.reflect.OptManifest]]. + * An [[scala.reflect.ErasureTag]] value wraps a Java class, which can be accessed via the `erasure` method. + * This notion, previously embodied in a [[scala.reflect.ClassManifest]] together with the notion of array creation, + * deserves a concept of itself. Quite often (e.g. for serialization or classloader introspection) it's useful to + * know an erasure, and only it, so we've implemented this notion in [[scala.reflect.ErasureTag]]. * - * Implicit in the contract for all Tag classes is that the reified type tpe represents the type parameter T. - * Tags are typically created by the compiler, which makes sure that this contract is kept. + * A [[scala.reflect.ClassTag]] is a standard implementation of both [[scala.reflect.ArrayTag]] and [[scala.reflect.ErasureTag]]. + * It guarantees that the source type T did not to contain any references to type parameters or abstract types. + * [[scala.reflect.ClassTag]] corresponds to a previous notion of [[scala.reflect.ClassManifest]]. * + * A [[scala.reflect.api.Universe#TypeTag]] value wraps a full Scala type in its tpe field. + * A [[scala.reflect.api.Universe#ConcreteTypeTag]] value is a [[scala.reflect.api.Universe#TypeTag]] + * that is guaranteed not to contain any references to type parameters or abstract types. + * Both flavors of TypeTags also carry an erasure, so [[scala.reflect.api.Universe#TypeTag]] is also an [[scala.reflect.ErasureTag]], + * and [[scala.reflect.api.Universe#ConcreteTypeTag]] is additionally an [[scala.reflect.ArrayTag]] and a [[scala.reflect.ClassTag]] + * + * It is recommended to use the tag supertypes of to precisely express your intent, i.e.: + * use ArrayTag when you want to construct arrays, + * use ErasureTag when you need an erasure and don't mind it being generated for untagged abstract types, + * use ClassTag only when you need an erasure of a type that doesn't refer to untagged abstract types. + * + * === Splicing === + * + * Tags can be spliced, i.e. if compiler generates a tag for a type that contains references to tagged + * type parameters or abstract type members, it will retrieve the corresponding tag and embed it into the result. * An example that illustrates the TypeTag embedding, consider the following function: * * import reflect.mirror._ @@ -44,6 +62,54 @@ import language.implicitConversions * TypeTag(<[ String => U ]>). * * Note that T has been replaced by String, because it comes with a TypeTag in f, whereas U was left as a type parameter. + * + * === ErasureTag vs ClassTag and TypeTag vs ConcreteTypeTag === + * + * Be careful with ErasureTag and TypeTag, because they will reify types even if these types are abstract. + * This makes it easy to forget to tag one of the methods in the call chain and discover it much later in the runtime + * by getting cryptic errors far away from their source. For example, consider the following snippet: + * + * def bind[T: TypeTag](name: String, value: T): IR.Result = bind((name, value)) + * def bind(p: NamedParam): IR.Result = bind(p.name, p.tpe, p.value) + * object NamedParam { + * implicit def namedValue[T: TypeTag](name: String, x: T): NamedParam = apply(name, x) + * def apply[T: TypeTag](name: String, x: T): NamedParam = new Typed[T](name, x) + * } + * + * This fragment of Scala REPL implementation defines a `bind` function that carries a named value along with its type + * into the heart of the REPL. Using a [[scala.reflect.api.Universe#TypeTag]] here is reasonable, because it is desirable + * to work with all types, even if they are type parameters or abstract type members. + * + * However if any of the three `TypeTag` context bounds is omitted, the resulting code will be incorrect, + * because the missing `TypeTag` will be transparently generated by the compiler, carrying meaningless information. + * Most likely, this problem will manifest itself elsewhere, making debugging complicated. + * If `TypeTag` context bounds were replaced with `ConcreteTypeTag`, then such errors would be reported statically. + * But in that case we wouldn't be able to use `bind` in arbitrary contexts. + * + * === Backward compatibility === + * + * TypeTags correspond loosely to Manifests. More precisely: + * The previous notion of a [[scala.reflect.ClassManifest]] corresponds to a scala.reflect.ClassTag, + * The previous notion of a [[scala.reflect.Manifest]] corresponds to scala.reflect.mirror.ConcreteTypeTag, + * Whereas scala.reflect.mirror.TypeTag is approximated by the previous notion of [[scala.reflect.OptManifest]]. + * + * In Scala 2.10, manifests are deprecated, so it's adviseable to migrate them to tags, + * because manifests might be removed in the next major release. + * + * In most cases it will be enough to replace ClassManifests with ClassTags and Manifests with ConcreteTypeTags, + * however there are a few caveats: + * + * 1) The notion of OptManifest is no longer supported. Tags can reify arbitrary types, so they are always available. + * // [Eugene] it might be useful, though, to guard against abstractness of the incoming type. + * + * 2) There's no equivalent for AnyValManifest. Consider comparing your tag with one of the core tags + * (defined in the corresponding companion objects) to find out whether it represents a primitive value class. + * + * 3) There's no replacement for factory methods defined in `ClassManifest` and `Manifest` companion objects. + * Consider assembling corresponding types using reflection API provided by Java (for classes) and Scala (for types). + * + * 4) Certain manifest functions (such as `<:<`, `>:>` and `typeArguments`) weren't included in the tag API. + * Consider using reflection API provided by Java (for classes) and Scala (for types) instead. */ trait TypeTags { self: Universe => @@ -56,25 +122,20 @@ trait TypeTags { self: Universe => * @see [[scala.reflect.api.TypeTags]] */ @annotation.implicitNotFound(msg = "No TypeTag available for ${T}") - abstract case class TypeTag[T](tpe: Type) { - // it's unsafe to use assert here, because we might run into deadlocks with Predef - // also see comments in ClassTags.scala - // assert(tpe != null) - - def sym = tpe.typeSymbol - def isConcrete = tpe.isConcrete - def notConcrete = !isConcrete - def toConcrete: ConcreteTypeTag[T] = ConcreteTypeTag[T](tpe) - - override def toString = { - if (!self.isInstanceOf[DummyMirror]) { - var prefix = if (isConcrete) "ConcreteTypeTag" else "TypeTag" - if (prefix != this.productPrefix) prefix = "*" + prefix - prefix + "[" + tpe + "]" - } else { - this.productPrefix + "[?]" - } - } + trait TypeTag[T] extends ErasureTag[T] with Equals with Serializable { + + def tpe: Type + def sym: Symbol = tpe.typeSymbol + + def isConcrete: Boolean = tpe.isConcrete + def notConcrete: Boolean = !isConcrete + def toConcrete: ConcreteTypeTag[T] = ConcreteTypeTag[T](tpe, erasure) + + /** case class accessories */ + override def canEqual(x: Any) = x.isInstanceOf[TypeTag[_]] + override def equals(x: Any) = x.isInstanceOf[TypeTag[_]] && this.tpe == x.asInstanceOf[TypeTag[_]].tpe + override def hashCode = scala.runtime.ScalaRunTime.hash(tpe) + override def toString = if (!self.isInstanceOf[DummyMirror]) (if (isConcrete) "*ConcreteTypeTag" else "TypeTag") + "[" + tpe + "]" else "TypeTag[?]" } object TypeTag { @@ -95,8 +156,10 @@ trait TypeTags { self: Universe => val Null : TypeTag[scala.Null] = ConcreteTypeTag.Null val String : TypeTag[java.lang.String] = ConcreteTypeTag.String - def apply[T](tpe: Type): TypeTag[T] = - tpe match { + // todo. uncomment after I redo the starr + // def apply[T](tpe1: Type, erasure1: jClass[_]): TypeTag[T] = + def apply[T](tpe1: Type, erasure1: jClass[_]): TypeTag[T] = + tpe1 match { case ByteTpe => TypeTag.Byte.asInstanceOf[TypeTag[T]] case ShortTpe => TypeTag.Short.asInstanceOf[TypeTag[T]] case CharTpe => TypeTag.Char.asInstanceOf[TypeTag[T]] @@ -113,8 +176,10 @@ trait TypeTags { self: Universe => case NothingTpe => TypeTag.Nothing.asInstanceOf[TypeTag[T]] case NullTpe => TypeTag.Null.asInstanceOf[TypeTag[T]] case StringTpe => TypeTag.String.asInstanceOf[TypeTag[T]] - case _ => new TypeTag[T](tpe) {} + case _ => new TypeTag[T]{ def tpe = tpe1; def erasure = erasure1 } } + + def unapply[T](ttag: TypeTag[T]): Option[Type] = Some(ttag.tpe) } /** @@ -124,36 +189,40 @@ trait TypeTags { self: Universe => * @see [[scala.reflect.api.TypeTags]] */ @annotation.implicitNotFound(msg = "No ConcreteTypeTag available for ${T}") - abstract class ConcreteTypeTag[T](tpe: Type, val erasure: jClass[_]) extends TypeTag[T](tpe) { + trait ConcreteTypeTag[T] extends TypeTag[T] with ClassTag[T] with Equals with Serializable { if (!self.isInstanceOf[DummyMirror]) { -// it's unsafe to use assert here, because we might run into deadlocks with Predef -// also see comments in ClassTags.scala -// assert(isConcrete, tpe) if (notConcrete) throw new Error("%s (%s) is not concrete and cannot be used to construct a concrete type tag".format(tpe, tpe.kind)) } - override def productPrefix = "ConcreteTypeTag" + + /** case class accessories */ + override def canEqual(x: Any) = x.isInstanceOf[TypeTag[_]] // this is done on purpose. TypeTag(tpe) and ConcreteTypeTag(tpe) should be equal if tpe's are equal + override def equals(x: Any) = x.isInstanceOf[TypeTag[_]] && this.tpe == x.asInstanceOf[TypeTag[_]].tpe + override def hashCode = scala.runtime.ScalaRunTime.hash(tpe) + override def toString = if (!self.isInstanceOf[DummyMirror]) "ConcreteTypeTag[" + tpe + "]" else "ConcreteTypeTag[?]" } object ConcreteTypeTag { - val Byte : ConcreteTypeTag[scala.Byte] = new ConcreteTypeTag[scala.Byte](ByteTpe, ClassTag.Byte.erasure) { private def readResolve() = ConcreteTypeTag.Byte } - val Short : ConcreteTypeTag[scala.Short] = new ConcreteTypeTag[scala.Short](ShortTpe, ClassTag.Short.erasure) { private def readResolve() = ConcreteTypeTag.Short } - val Char : ConcreteTypeTag[scala.Char] = new ConcreteTypeTag[scala.Char](CharTpe, ClassTag.Char.erasure) { private def readResolve() = ConcreteTypeTag.Char } - val Int : ConcreteTypeTag[scala.Int] = new ConcreteTypeTag[scala.Int](IntTpe, ClassTag.Int.erasure) { private def readResolve() = ConcreteTypeTag.Int } - val Long : ConcreteTypeTag[scala.Long] = new ConcreteTypeTag[scala.Long](LongTpe, ClassTag.Long.erasure) { private def readResolve() = ConcreteTypeTag.Long } - val Float : ConcreteTypeTag[scala.Float] = new ConcreteTypeTag[scala.Float](FloatTpe, ClassTag.Float.erasure) { private def readResolve() = ConcreteTypeTag.Float } - val Double : ConcreteTypeTag[scala.Double] = new ConcreteTypeTag[scala.Double](DoubleTpe, ClassTag.Double.erasure) { private def readResolve() = ConcreteTypeTag.Double } - val Boolean : ConcreteTypeTag[scala.Boolean] = new ConcreteTypeTag[scala.Boolean](BooleanTpe, ClassTag.Boolean.erasure) { private def readResolve() = ConcreteTypeTag.Boolean } - val Unit : ConcreteTypeTag[scala.Unit] = new ConcreteTypeTag[scala.Unit](UnitTpe, ClassTag.Unit.erasure) { private def readResolve() = ConcreteTypeTag.Unit } - val Any : ConcreteTypeTag[scala.Any] = new ConcreteTypeTag[scala.Any](AnyTpe, ClassTag.Any.erasure) { private def readResolve() = ConcreteTypeTag.Any } - val Object : ConcreteTypeTag[java.lang.Object] = new ConcreteTypeTag[java.lang.Object](ObjectTpe, ClassTag.Object.erasure) { private def readResolve() = ConcreteTypeTag.Object } - val AnyVal : ConcreteTypeTag[scala.AnyVal] = new ConcreteTypeTag[scala.AnyVal](AnyValTpe, ClassTag.AnyVal.erasure) { private def readResolve() = ConcreteTypeTag.AnyVal } - val AnyRef : ConcreteTypeTag[scala.AnyRef] = new ConcreteTypeTag[scala.AnyRef](AnyRefTpe, ClassTag.AnyRef.erasure) { private def readResolve() = ConcreteTypeTag.AnyRef } - val Nothing : ConcreteTypeTag[scala.Nothing] = new ConcreteTypeTag[scala.Nothing](NothingTpe, ClassTag.Nothing.erasure) { private def readResolve() = ConcreteTypeTag.Nothing } - val Null : ConcreteTypeTag[scala.Null] = new ConcreteTypeTag[scala.Null](NullTpe, ClassTag.Null.erasure) { private def readResolve() = ConcreteTypeTag.Null } - val String : ConcreteTypeTag[java.lang.String] = new ConcreteTypeTag[java.lang.String](StringTpe, ClassTag.String.erasure) { private def readResolve() = ConcreteTypeTag.String } - - def apply[T](tpe: Type, erasure: jClass[_] = null): ConcreteTypeTag[T] = - tpe match { + val Byte : ConcreteTypeTag[scala.Byte] = new ConcreteTypeTag[scala.Byte]{ def tpe = ByteTpe; def erasure = ClassTag.Byte.erasure; private def readResolve() = ConcreteTypeTag.Byte } + val Short : ConcreteTypeTag[scala.Short] = new ConcreteTypeTag[scala.Short]{ def tpe = ShortTpe; def erasure = ClassTag.Short.erasure; private def readResolve() = ConcreteTypeTag.Short } + val Char : ConcreteTypeTag[scala.Char] = new ConcreteTypeTag[scala.Char]{ def tpe = CharTpe; def erasure = ClassTag.Char.erasure; private def readResolve() = ConcreteTypeTag.Char } + val Int : ConcreteTypeTag[scala.Int] = new ConcreteTypeTag[scala.Int]{ def tpe = IntTpe; def erasure = ClassTag.Int.erasure; private def readResolve() = ConcreteTypeTag.Int } + val Long : ConcreteTypeTag[scala.Long] = new ConcreteTypeTag[scala.Long]{ def tpe = LongTpe; def erasure = ClassTag.Long.erasure; private def readResolve() = ConcreteTypeTag.Long } + val Float : ConcreteTypeTag[scala.Float] = new ConcreteTypeTag[scala.Float]{ def tpe = FloatTpe; def erasure = ClassTag.Float.erasure; private def readResolve() = ConcreteTypeTag.Float } + val Double : ConcreteTypeTag[scala.Double] = new ConcreteTypeTag[scala.Double]{ def tpe = DoubleTpe; def erasure = ClassTag.Double.erasure; private def readResolve() = ConcreteTypeTag.Double } + val Boolean : ConcreteTypeTag[scala.Boolean] = new ConcreteTypeTag[scala.Boolean]{ def tpe = BooleanTpe; def erasure = ClassTag.Boolean.erasure; private def readResolve() = ConcreteTypeTag.Boolean } + val Unit : ConcreteTypeTag[scala.Unit] = new ConcreteTypeTag[scala.Unit]{ def tpe = UnitTpe; def erasure = ClassTag.Unit.erasure; private def readResolve() = ConcreteTypeTag.Unit } + val Any : ConcreteTypeTag[scala.Any] = new ConcreteTypeTag[scala.Any]{ def tpe = AnyTpe; def erasure = ClassTag.Any.erasure; private def readResolve() = ConcreteTypeTag.Any } + val Object : ConcreteTypeTag[java.lang.Object] = new ConcreteTypeTag[java.lang.Object]{ def tpe = ObjectTpe; def erasure = ClassTag.Object.erasure; private def readResolve() = ConcreteTypeTag.Object } + val AnyVal : ConcreteTypeTag[scala.AnyVal] = new ConcreteTypeTag[scala.AnyVal]{ def tpe = AnyValTpe; def erasure = ClassTag.AnyVal.erasure; private def readResolve() = ConcreteTypeTag.AnyVal } + val AnyRef : ConcreteTypeTag[scala.AnyRef] = new ConcreteTypeTag[scala.AnyRef]{ def tpe = AnyRefTpe; def erasure = ClassTag.AnyRef.erasure; private def readResolve() = ConcreteTypeTag.AnyRef } + val Nothing : ConcreteTypeTag[scala.Nothing] = new ConcreteTypeTag[scala.Nothing]{ def tpe = NothingTpe; def erasure = ClassTag.Nothing.erasure; private def readResolve() = ConcreteTypeTag.Nothing } + val Null : ConcreteTypeTag[scala.Null] = new ConcreteTypeTag[scala.Null]{ def tpe = NullTpe; def erasure = ClassTag.Null.erasure; private def readResolve() = ConcreteTypeTag.Null } + val String : ConcreteTypeTag[java.lang.String] = new ConcreteTypeTag[java.lang.String]{ def tpe = StringTpe; def erasure = ClassTag.String.erasure; private def readResolve() = ConcreteTypeTag.String } + + // todo. uncomment after I redo the starr + // def apply[T](tpe1: Type, erasure1: jClass[_]): ConcreteTypeTag[T] = + def apply[T](tpe1: Type, erasure1: jClass[_] = null): ConcreteTypeTag[T] = + tpe1 match { case ByteTpe => ConcreteTypeTag.Byte.asInstanceOf[ConcreteTypeTag[T]] case ShortTpe => ConcreteTypeTag.Short.asInstanceOf[ConcreteTypeTag[T]] case CharTpe => ConcreteTypeTag.Char.asInstanceOf[ConcreteTypeTag[T]] @@ -170,69 +239,10 @@ trait TypeTags { self: Universe => case NothingTpe => ConcreteTypeTag.Nothing.asInstanceOf[ConcreteTypeTag[T]] case NullTpe => ConcreteTypeTag.Null.asInstanceOf[ConcreteTypeTag[T]] case StringTpe => ConcreteTypeTag.String.asInstanceOf[ConcreteTypeTag[T]] - case _ => new ConcreteTypeTag[T](tpe, erasure) {} + case _ => new ConcreteTypeTag[T]{ def tpe = tpe1; def erasure = erasure1 } } def unapply[T](ttag: TypeTag[T]): Option[Type] = if (ttag.isConcrete) Some(ttag.tpe) else None - - implicit def toClassTag[T](ttag: rm.ConcreteTypeTag[T]): ClassTag[T] = ClassTag[T](ttag) - - implicit def toDeprecatedManifestApis[T](ttag: rm.ConcreteTypeTag[T]): DeprecatedManifestApis[T] = new DeprecatedManifestApis[T](ttag) - - // this class should not be used directly in client code - class DeprecatedManifestApis[T](ttag: rm.ConcreteTypeTag[T]) extends ClassTag.DeprecatedClassManifestApis[T](toClassTag(ttag)) { - @deprecated("Use `tpe` to analyze the underlying type", "2.10.0") - def <:<(that: Manifest[_]): Boolean = ttag.tpe <:< that.tpe - - @deprecated("Use `tpe` to analyze the underlying type", "2.10.0") - def >:>(that: Manifest[_]): Boolean = that <:< ttag - - @deprecated("Use `tpe` to analyze the type arguments", "2.10.0") - override def typeArguments: List[Manifest[_]] = ttag.tpe.typeArguments map (targ => rm.ConcreteTypeTag(targ)) - } - - /** Manifest for the singleton type `value.type'. */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def singleType[T <: AnyRef](value: AnyRef): Manifest[T] = Manifest[T](???, value.getClass) - - /** Manifest for the class type `clazz[args]', where `clazz' is - * a top-level or static class. - * @note This no-prefix, no-arguments case is separate because we - * it's called from ScalaRunTime.boxArray itself. If we - * pass varargs as arrays into this, we get an infinitely recursive call - * to boxArray. (Besides, having a separate case is more efficient) - */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def classType[T](clazz: Predef.Class[_]): Manifest[T] = Manifest[T](???, clazz) - - /** Manifest for the class type `clazz', where `clazz' is - * a top-level or static class and args are its type arguments. */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def classType[T](clazz: Predef.Class[T], arg1: Manifest[_], args: Manifest[_]*): Manifest[T] = Manifest[T](???, clazz) - - /** Manifest for the class type `clazz[args]', where `clazz' is - * a class with non-package prefix type `prefix` and type arguments `args`. - */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def classType[T](prefix: Manifest[_], clazz: Predef.Class[_], args: Manifest[_]*): Manifest[T] = Manifest[T](???, clazz) - - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def arrayType[T](arg: Manifest[_]): Manifest[Array[T]] = Manifest[Array[T]](???, arg.asInstanceOf[Manifest[T]].arrayManifest.erasure) - - /** Manifest for the abstract type `prefix # name'. `upperBound' is not - * strictly necessary as it could be obtained by reflection. It was - * added so that erasure can be calculated without reflection. */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def abstractType[T](prefix: Manifest[_], name: String, clazz: Predef.Class[_], args: Manifest[_]*): Manifest[T] = Manifest[T](???, clazz) - - /** Manifest for the unknown type `_ >: L <: U' in an existential. - */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def wildcardType[T](lowerBound: Manifest[_], upperBound: Manifest[_]): Manifest[T] = Manifest[T](???, upperBound.erasure) - - /** Manifest for the intersection type `parents_0 with ... with parents_n'. */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def intersectionType[T](parents: Manifest[_]*): Manifest[T] = Manifest[T](???, parents.head.erasure) } // incantations for summoning diff --git a/src/library/scala/reflect/api/Universe.scala b/src/library/scala/reflect/api/Universe.scala index 2b22839d39..2a7445c41c 100755 --- a/src/library/scala/reflect/api/Universe.scala +++ b/src/library/scala/reflect/api/Universe.scala @@ -1,5 +1,6 @@ package scala.reflect package api + import language.experimental.macros abstract class Universe extends Symbols @@ -65,25 +66,7 @@ abstract class Universe extends Symbols object Universe { def reify[T](cc: scala.reflect.makro.Context{ type PrefixType = Universe })(expr: cc.Expr[T]): cc.Expr[cc.prefix.value.Expr[T]] = { import cc.mirror._ - try cc.reifyTree(cc.prefix, expr) - catch { - case ex: Throwable => - // [Eugene] cannot pattern match on an abstract type, so had to do this - val ex1 = ex - if (ex.getClass.toString.endsWith("$ReificationError")) { - ex match { - case cc.ReificationError(pos, msg) => - cc.error(pos, msg) - EmptyTree - } - } else if (ex.getClass.toString.endsWith("$UnexpectedReificationError")) { - ex match { - case cc.UnexpectedReificationError(pos, err, cause) => - if (cause != null) throw cause else throw ex - } - } else { - throw ex - } - } + import scala.reflect.makro.internal._ + cc.materializeExpr(cc.prefix, expr) } } diff --git a/src/library/scala/reflect/makro/Context.scala b/src/library/scala/reflect/makro/Context.scala index b304d98a5a..668d239087 100644 --- a/src/library/scala/reflect/makro/Context.scala +++ b/src/library/scala/reflect/makro/Context.scala @@ -34,28 +34,11 @@ trait Context extends Aliases object Context { def reify[T](cc: Context{ type PrefixType = Context })(expr: cc.Expr[T]): cc.Expr[cc.prefix.value.Expr[T]] = { import cc.mirror._ + import scala.reflect.makro.internal._ // [Eugene] how do I typecheck this without undergoing this tiresome (and, in general, incorrect) procedure? val prefix: Tree = Select(cc.prefix, newTermName("mirror")) val prefixTpe = cc.typeCheck(TypeApply(Select(prefix, newTermName("asInstanceOf")), List(SingletonTypeTree(prefix)))).tpe prefix setType prefixTpe - try cc.reifyTree(prefix, expr) - catch { - case ex: Throwable => - // [Eugene] cannot pattern match on an abstract type, so had to do this - if (ex.getClass.toString.endsWith("$ReificationError")) { - ex match { - case cc.ReificationError(pos, msg) => - cc.error(pos, msg) - EmptyTree - } - } else if (ex.getClass.toString.endsWith("$UnexpectedReificationError")) { - ex match { - case cc.UnexpectedReificationError(pos, err, cause) => - if (cause != null) throw cause else throw ex - } - } else { - throw ex - } - } + cc.materializeExpr(prefix, expr) } } diff --git a/src/library/scala/reflect/makro/Reifiers.scala b/src/library/scala/reflect/makro/Reifiers.scala index b9e82e0387..ae6669946c 100644 --- a/src/library/scala/reflect/makro/Reifiers.scala +++ b/src/library/scala/reflect/makro/Reifiers.scala @@ -46,11 +46,12 @@ trait Reifiers { * The produced tree will be bound to the mirror specified by ``prefix'' (also see ``reflectMirrorPrefix''). * For more information and examples see the documentation for ``Context.reifyTree'' and ``Universe.reify''. */ - def reifyType(prefix: Tree, tpe: Type, dontSpliceAtTopLevel: Boolean = false, requireConcreteTypeTag: Boolean = false): Tree + def reifyType(prefix: Tree, tpe: Type, dontSpliceAtTopLevel: Boolean = false, concrete: Boolean = false): Tree /** Given a type, generate a tree that when compiled and executed produces the erasure of the original type. + * If ``concrete'' is true, then this function will bail on types, whose erasure includes abstract types (like `ClassTag` does). */ - def reifyErasure(tpe: Type): Tree + def reifyErasure(tpe: Type, concrete: Boolean = true): Tree /** Undoes reification of a tree. * @@ -67,20 +68,10 @@ trait Reifiers { * 3) compileAndEval(unreifyTree(reifyTree(tree))) ~ compileAndEval(tree) // at runtime original and unreified trees are behaviorally equivalent */ def unreifyTree(tree: Tree): Tree +} - /** Represents an error during reification - */ - type ReificationError <: Throwable - val ReificationError: ReificationErrorExtractor - abstract class ReificationErrorExtractor { - def unapply(error: ReificationError): Option[(Position, String)] - } +// made these guys non path-dependent, otherwise exception handling quickly becomes a mess - /** Wraps an unexpected error during reification - */ - type UnexpectedReificationError <: Throwable - val UnexpectedReificationError: UnexpectedReificationErrorExtractor - abstract class UnexpectedReificationErrorExtractor { - def unapply(error: UnexpectedReificationError): Option[(Position, String, Throwable)] - } -} +case class ReificationError(var pos: reflect.api.Position, val msg: String) extends Throwable(msg) + +case class UnexpectedReificationError(val pos: reflect.api.Position, val msg: String, val cause: Throwable = null) extends Throwable(msg) \ No newline at end of file diff --git a/src/library/scala/reflect/makro/internal/Utils.scala b/src/library/scala/reflect/makro/internal/Utils.scala index 604bba10b6..a8a2c98715 100644 --- a/src/library/scala/reflect/makro/internal/Utils.scala +++ b/src/library/scala/reflect/makro/internal/Utils.scala @@ -6,6 +6,20 @@ import language.experimental.macros /** This package is required by the compiler and should not be used in client code. */ package object internal { + /** This method is required by the compiler and should not be used in client code. */ + def materializeArrayTag[T](u: Universe): ArrayTag[T] = macro materializeArrayTag_impl[T] + + /** This method is required by the compiler and should not be used in client code. */ + def materializeArrayTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[ArrayTag[T]] = + c.Expr[Nothing](c.materializeArrayTag(u.tree, implicitly[c.TypeTag[T]].tpe))(c.TypeTag.Nothing) + + /** This method is required by the compiler and should not be used in client code. */ + def materializeErasureTag[T](u: Universe): ErasureTag[T] = macro materializeErasureTag_impl[T] + + /** This method is required by the compiler and should not be used in client code. */ + def materializeErasureTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[ErasureTag[T]] = + c.Expr[Nothing](c.materializeErasureTag(u.tree, implicitly[c.TypeTag[T]].tpe, concrete = false))(c.TypeTag.Nothing) + /** This method is required by the compiler and should not be used in client code. */ def materializeClassTag[T](u: Universe): ClassTag[T] = macro materializeClassTag_impl[T] @@ -18,14 +32,14 @@ package object internal { /** This method is required by the compiler and should not be used in client code. */ def materializeTypeTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[u.value.TypeTag[T]] = - c.Expr[Nothing](c.materializeTypeTag(u.tree, implicitly[c.TypeTag[T]].tpe, requireConcreteTypeTag = false))(c.TypeTag.Nothing) + c.Expr[Nothing](c.materializeTypeTag(u.tree, implicitly[c.TypeTag[T]].tpe, concrete = false))(c.TypeTag.Nothing) /** This method is required by the compiler and should not be used in client code. */ def materializeConcreteTypeTag[T](u: Universe): u.ConcreteTypeTag[T] = macro materializeConcreteTypeTag_impl[T] /** This method is required by the compiler and should not be used in client code. */ def materializeConcreteTypeTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[u.value.ConcreteTypeTag[T]] = - c.Expr[Nothing](c.materializeTypeTag(u.tree, implicitly[c.TypeTag[T]].tpe, requireConcreteTypeTag = true))(c.TypeTag.Nothing) + c.Expr[Nothing](c.materializeTypeTag(u.tree, implicitly[c.TypeTag[T]].tpe, concrete = true))(c.TypeTag.Nothing) /** This method is required by the compiler and should not be used in client code. */ private[scala] implicit def context2utils(c0: Context) : Utils { val c: c0.type } = new { val c: c0.type = c0 } with Utils @@ -53,14 +67,27 @@ package internal { AnyValClass.asType -> newTermName("AnyVal"), AnyRefClass.asType -> newTermName("AnyRef"), NothingClass.asType -> newTermName("Nothing"), - NullClass.asType -> newTermName("Null")) + NullClass.asType -> newTermName("Null"), + StringClass.asType -> newTermName("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 materializeErasureTag(prefix: Tree, tpe: Type, concrete: Boolean): Tree = + if (concrete) materializeClassTag(prefix, tpe) else materializeTypeTag(prefix, tpe, concrete = false) def materializeClassTag(prefix: Tree, tpe: Type): Tree = - materializeTag(prefix, tpe, ClassTagModule, c.reifyErasure(tpe)) + materializeTag(prefix, tpe, ClassTagModule, { + val erasure = c.reifyErasure(tpe, concrete = true) + val factory = TypeApply(Select(Ident(ClassTagModule), "apply"), List(TypeTree(tpe))) + Apply(factory, List(erasure)) + }) - def materializeTypeTag(prefix: Tree, tpe: Type, requireConcreteTypeTag: Boolean): Tree = { - val tagModule = if (requireConcreteTypeTag) ConcreteTypeTagModule else TypeTagModule - materializeTag(prefix, tpe, tagModule, c.reifyType(prefix, tpe, dontSpliceAtTopLevel = true, requireConcreteTypeTag = requireConcreteTypeTag)) + def materializeTypeTag(prefix: Tree, tpe: Type, concrete: Boolean): Tree = { + val tagModule = if (concrete) ConcreteTypeTagModule else TypeTagModule + materializeTag(prefix, tpe, tagModule, c.reifyType(prefix, tpe, dontSpliceAtTopLevel = true, concrete = concrete)) } private def materializeTag(prefix: Tree, tpe: Type, tagModule: Symbol, materializer: => Tree): Tree = { @@ -70,32 +97,30 @@ package internal { val ref = if (tagModule.owner.isPackageClass) Ident(tagModule) else Select(prefix, tagModule.name) Select(ref, coreTags(coreTpe)) case _ => - try materializer - catch { - case ex: Throwable => - // [Eugene] cannot pattern match on an abstract type, so had to do this - val ex1 = ex - if (ex.getClass.toString.endsWith("$ReificationError")) { - ex match { - case c.ReificationError(pos, msg) => - c.error(pos, msg) - EmptyTree - } - } else if (ex.getClass.toString.endsWith("$UnexpectedReificationError")) { - ex match { - case c.UnexpectedReificationError(pos, err, cause) => - if (cause != null) throw cause else throw ex - } - } else { - throw ex - } - } + translatingReificationErrors(materializer) } try c.typeCheck(result) - catch { case terr @ c.TypeError(pos, msg) => fail(terr) } + catch { case terr @ c.TypeError(pos, msg) => failTag(terr) } + } + + def materializeExpr(prefix: Tree, expr: Tree): Tree = { + val result = translatingReificationErrors(c.reifyTree(prefix, expr)) + try c.typeCheck(result) + catch { case terr @ c.TypeError(pos, msg) => failExpr(terr) } + } + + private def translatingReificationErrors(materializer: => Tree): Tree = { + try materializer + catch { + case ReificationError(pos, msg) => + c.error(pos.asInstanceOf[c.Position], msg) // this cast is a very small price for the sanity of exception handling + EmptyTree + case UnexpectedReificationError(pos, err, cause) if cause != null => + throw cause + } } - private def fail(reason: Any): Nothing = { + private def failTag(reason: Any): Nothing = { val Apply(TypeApply(fun, List(tpeTree)), _) = c.macroApplication val tpe = tpeTree.tpe val PolyType(_, MethodType(_, tagTpe)) = fun.tpe @@ -104,5 +129,8 @@ package internal { c.echo(c.enclosingPosition, "cannot materialize " + tagModule.name + "[" + tpe + "] because:\n" + reason) c.abort(c.enclosingPosition, "No %s available for %s".format(tagModule.name, tpe)) } + + private def failExpr(reason: Any): Nothing = + c.abort(c.enclosingPosition, "Cannot materialize Expr because:\n" + reason) } } diff --git a/src/library/scala/reflect/package.scala b/src/library/scala/reflect/package.scala index 0958f2ce9a..640cad6c21 100644 --- a/src/library/scala/reflect/package.scala +++ b/src/library/scala/reflect/package.scala @@ -65,8 +65,11 @@ package object reflect { @deprecated("Use `@scala.reflect.ConcreteTypeTag` instead", "2.10.0") lazy val Manifest = ConcreteTypeTag @deprecated("NoManifest is no longer supported, and using it may lead to incorrect results, Use `@scala.reflect.TypeTag` instead", "2.10.0") - object NoManifest extends OptManifest[Nothing](scala.reflect.mirror.TypeTag.Nothing.tpe) + lazy val NoManifest = TypeTag.Nothing + // ArrayTag trait is defined separately from the mirror + // ErasureTag trait is defined separately from the mirror + // ConcreteErasureTag trait is defined separately from the mirror // ClassTag class is defined separately from the mirror type TypeTag[T] = scala.reflect.mirror.TypeTag[T] type ConcreteTypeTag[T] = scala.reflect.mirror.ConcreteTypeTag[T] diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index d2adc26d66..9d67644d61 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -47,12 +47,29 @@ object ScalaRunTime { names.toSet } + /** Return the class object representing an array with element class `clazz`. + */ + def arrayClass(clazz: Class[_]): Class[_] = { + // newInstance throws an exception if the erasure is Void.TYPE. see SI-5680 + if (clazz == java.lang.Void.TYPE) classOf[Array[Unit]] + else java.lang.reflect.Array.newInstance(clazz, 0).getClass + } + + /** Return the class object representing elements in arrays described by a given schematic. + */ + def arrayElementClass(schematic: Any): Class[_] = schematic match { + case cls: Class[_] => cls.getComponentType + case tag: ClassTag[_] => tag.erasure + case tag: ArrayTag[_] => tag.newArray(0).getClass.getComponentType + case _ => throw new UnsupportedOperationException("unsupported schematic %s (%s)".format(schematic, if (schematic == null) "null" else schematic.getClass)) + } + /** Return the class object representing an unboxed value type, * e.g. classOf[int], not classOf[java.lang.Integer]. The compiler * rewrites expressions like 5.getClass to come here. */ - def anyValClass[T <: AnyVal : ClassManifest](value: T): Class[T] = - classManifest[T].erasure.asInstanceOf[Class[T]] + def anyValClass[T <: AnyVal : ClassTag](value: T): Class[T] = + classTag[T].erasure.asInstanceOf[Class[T]] /** Retrieve generic array element */ def array_apply(xs: AnyRef, idx: Int): Any = xs match { diff --git a/src/library/scala/util/Marshal.scala b/src/library/scala/util/Marshal.scala index c2269cde45..6eb58e8570 100644 --- a/src/library/scala/util/Marshal.scala +++ b/src/library/scala/util/Marshal.scala @@ -11,19 +11,19 @@ package scala.util /** - * Marshalling of Scala objects using Scala manifests. + * Marshalling of Scala objects using Scala tags. * * @author Stephane Micheloud * @version 1.0 */ object Marshal { import java.io._ - import scala.reflect.ClassManifest + import scala.reflect.ClassTag - def dump[A](o: A)(implicit m: ClassManifest[A]): Array[Byte] = { + def dump[A](o: A)(implicit t: ClassTag[A]): Array[Byte] = { val ba = new ByteArrayOutputStream(512) val out = new ObjectOutputStream(ba) - out.writeObject(m) + out.writeObject(t) out.writeObject(o) out.close() ba.toByteArray() @@ -32,20 +32,20 @@ object Marshal { @throws(classOf[IOException]) @throws(classOf[ClassCastException]) @throws(classOf[ClassNotFoundException]) - def load[A](buffer: Array[Byte])(implicit expected: ClassManifest[A]): A = { + def load[A](buffer: Array[Byte])(implicit expected: ClassTag[A]): A = { val in = new ObjectInputStream(new ByteArrayInputStream(buffer)) - val found = in.readObject.asInstanceOf[ClassManifest[_]] - // todo. [Eugene] needs review, since ClassManifests no longer capture typeArguments - if (found.tpe <:< expected.tpe) { - val o = in.readObject.asInstanceOf[A] - in.close() - o - } else { - in.close() - throw new ClassCastException("type mismatch;"+ - "\n found : "+found+ - "\n required: "+expected) + val found = in.readObject.asInstanceOf[ClassTag[_]] + try { + // [Eugene] needs review + // previously was: found <:< expected + found.erasure.asSubclass(expected.erasure) + in.readObject.asInstanceOf[A] + } catch { + case _: ClassCastException => + in.close() + throw new ClassCastException("type mismatch;"+ + "\n found : "+found+ + "\n required: "+expected) } } - -} +} \ No newline at end of file diff --git a/test/files/neg/classtags_contextbound_a.check b/test/files/neg/classtags_contextbound_a.check index f4b6ff5af1..a4fd37506d 100644 --- a/test/files/neg/classtags_contextbound_a.check +++ b/test/files/neg/classtags_contextbound_a.check @@ -1,4 +1,4 @@ -classtags_contextbound_a.scala:2: error: No ClassTag available for T +classtags_contextbound_a.scala:2: error: No ArrayTag available for T def foo[T] = Array[T]() ^ one error found diff --git a/test/files/neg/classtags_contextbound_c.check b/test/files/neg/classtags_contextbound_c.check index 54f630862a..a1c5eddfe1 100644 --- a/test/files/neg/classtags_contextbound_c.check +++ b/test/files/neg/classtags_contextbound_c.check @@ -1,4 +1,4 @@ -classtags_contextbound_c.scala:2: error: No ClassTag available for T +classtags_contextbound_c.scala:2: error: No ArrayTag available for T def mkArray[T] = Array[T]() ^ one error found diff --git a/test/files/neg/classtags_dont_use_typetags.check b/test/files/neg/classtags_dont_use_typetags.check new file mode 100644 index 0000000000..c7d2fba35b --- /dev/null +++ b/test/files/neg/classtags_dont_use_typetags.check @@ -0,0 +1,4 @@ +classtags_dont_use_typetags.scala:2: error: No ArrayTag available for T + def foo[T: TypeTag] = Array[T]() + ^ +one error found diff --git a/test/files/neg/classtags_dont_use_typetags.scala b/test/files/neg/classtags_dont_use_typetags.scala new file mode 100644 index 0000000000..0f675f71aa --- /dev/null +++ b/test/files/neg/classtags_dont_use_typetags.scala @@ -0,0 +1,3 @@ +object Test extends App { + def foo[T: TypeTag] = Array[T]() +} \ No newline at end of file diff --git a/test/files/neg/macro-invalidret-nontree.check b/test/files/neg/macro-invalidret-nontree.check index 7fcc396463..0b793cf421 100644 --- a/test/files/neg/macro-invalidret-nontree.check +++ b/test/files/neg/macro-invalidret-nontree.check @@ -1,7 +1,7 @@ -Macros_Test_2.scala:2: error: macro implementation has wrong shape: - required: (c: scala.reflect.makro.Context): c.Expr[Any] - found : (c: scala.reflect.makro.Context): Int -type mismatch for return type : c.Expr[Any] does not conform to Int - def foo = macro Impls.foo - ^ -one error found +Macros_Test_2.scala:2: error: macro implementation has wrong shape: + required: (c: scala.reflect.makro.Context): c.Expr[Any] + found : (c: scala.reflect.makro.Context): Int +type mismatch for return type: Int does not conform to c.Expr[Any] + def foo = macro Impls.foo + ^ +one error found diff --git a/test/files/neg/macro-invalidret-nonuniversetree.check b/test/files/neg/macro-invalidret-nonuniversetree.check index a97d6daaa9..4fc06b5ceb 100644 --- a/test/files/neg/macro-invalidret-nonuniversetree.check +++ b/test/files/neg/macro-invalidret-nonuniversetree.check @@ -1,7 +1,7 @@ -Macros_Test_2.scala:2: error: macro implementation has wrong shape: - required: (c: scala.reflect.makro.Context): c.Expr[Any] - found : (c: scala.reflect.makro.Context): reflect.mirror.Literal -type mismatch for return type : c.Expr[Any] does not conform to reflect.mirror.Literal - def foo = macro Impls.foo - ^ -one error found +Macros_Test_2.scala:2: error: macro implementation has wrong shape: + required: (c: scala.reflect.makro.Context): c.Expr[Any] + found : (c: scala.reflect.makro.Context): reflect.mirror.Literal +type mismatch for return type: reflect.mirror.Literal does not conform to c.Expr[Any] + def foo = macro Impls.foo + ^ +one error found diff --git a/test/files/neg/t5689.check b/test/files/neg/t5689.check index f286d08cfa..6abc4c13f6 100644 --- a/test/files/neg/t5689.check +++ b/test/files/neg/t5689.check @@ -1,7 +1,7 @@ t5689.scala:4: error: macro implementation has wrong shape: required: (c: scala.reflect.makro.Context)(i: c.Expr[Double]): c.Expr[String] found : (c: scala.reflect.makro.Context)(i: c.Expr[Double]): c.Expr[Int] -type mismatch for return type : c.Expr[String] does not conform to c.Expr[Int] +type mismatch for return type: c.Expr[Int] does not conform to c.Expr[String] def returnsString(i: Double): String = macro returnsIntImpl ^ one error found diff --git a/test/files/run/arraytags_basic.check b/test/files/run/arraytags_basic.check new file mode 100644 index 0000000000..92816b91bd --- /dev/null +++ b/test/files/run/arraytags_basic.check @@ -0,0 +1,36 @@ +class [I +class [[I +class [[[I +class [Lscala.collection.immutable.List; +class [[Lscala.collection.immutable.List; +class [[[Lscala.collection.immutable.List; +class [Lscala.collection.immutable.List; +class [[Lscala.collection.immutable.List; +class [[[Lscala.collection.immutable.List; +class [Lscala.collection.immutable.Map; +class [[Lscala.collection.immutable.Map; +class [[[Lscala.collection.immutable.Map; +class [[I +class [[[I +class [[[[I +class [[Lscala.collection.immutable.List; +class [[[Lscala.collection.immutable.List; +class [[[[Lscala.collection.immutable.List; +class [[Lscala.collection.immutable.List; +class [[[Lscala.collection.immutable.List; +class [[[[Lscala.collection.immutable.List; +class [[Lscala.collection.immutable.Map; +class [[[Lscala.collection.immutable.Map; +class [[[[Lscala.collection.immutable.Map; +class [[[I +class [[[[I +class [[[[[I +class [[[Lscala.collection.immutable.List; +class [[[[Lscala.collection.immutable.List; +class [[[[[Lscala.collection.immutable.List; +class [[[Lscala.collection.immutable.List; +class [[[[Lscala.collection.immutable.List; +class [[[[[Lscala.collection.immutable.List; +class [[[Lscala.collection.immutable.Map; +class [[[[Lscala.collection.immutable.Map; +class [[[[[Lscala.collection.immutable.Map; diff --git a/test/files/run/arraytags_basic.scala b/test/files/run/arraytags_basic.scala new file mode 100644 index 0000000000..edc20e9bc1 --- /dev/null +++ b/test/files/run/arraytags_basic.scala @@ -0,0 +1,22 @@ +object Test extends App { + def test[T: ArrayTag] = { + println(implicitly[ArrayTag[T]].newArray(10).getClass) + println(implicitly[ArrayTag[T]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Array[T]]].wrap.newArray(10).getClass) + } + + test[Int] + test[List[Int]] + test[List[String]] + test[Map[Int, String]] + + test[Array[Int]] + test[Array[List[Int]]] + test[Array[List[String]]] + test[Array[Map[Int, String]]] + + test[Array[Array[Int]]] + test[Array[Array[List[Int]]]] + test[Array[Array[List[String]]]] + test[Array[Array[Map[Int, String]]]] +} \ No newline at end of file diff --git a/test/files/run/arraytags_core.check b/test/files/run/arraytags_core.check new file mode 100644 index 0000000000..82ed84ad78 --- /dev/null +++ b/test/files/run/arraytags_core.check @@ -0,0 +1,48 @@ +class [B +class [[B +class [[[B +class [S +class [[S +class [[[S +class [C +class [[C +class [[[C +class [I +class [[I +class [[[I +class [J +class [[J +class [[[J +class [F +class [[F +class [[[F +class [D +class [[D +class [[[D +class [Z +class [[Z +class [[[Z +class [Lscala.runtime.BoxedUnit; +class [[Lscala.runtime.BoxedUnit; +class [[[Lscala.runtime.BoxedUnit; +class [Ljava.lang.Object; +class [[Ljava.lang.Object; +class [[[Ljava.lang.Object; +class [Ljava.lang.Object; +class [[Ljava.lang.Object; +class [[[Ljava.lang.Object; +class [Ljava.lang.Object; +class [[Ljava.lang.Object; +class [[[Ljava.lang.Object; +class [Ljava.lang.Object; +class [[Ljava.lang.Object; +class [[[Ljava.lang.Object; +class [Lscala.runtime.Null$; +class [[Lscala.runtime.Null$; +class [[[Lscala.runtime.Null$; +class [Lscala.runtime.Nothing$; +class [[Lscala.runtime.Nothing$; +class [[[Lscala.runtime.Nothing$; +class [Ljava.lang.String; +class [[Ljava.lang.String; +class [[[Ljava.lang.String; diff --git a/test/files/run/arraytags_core.scala b/test/files/run/arraytags_core.scala new file mode 100644 index 0000000000..a59ae24f30 --- /dev/null +++ b/test/files/run/arraytags_core.scala @@ -0,0 +1,50 @@ +object Test extends App { + println(implicitly[ArrayTag[Byte]].newArray(10).getClass) + println(implicitly[ArrayTag[Byte]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Array[Byte]]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Short]].newArray(10).getClass) + println(implicitly[ArrayTag[Short]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Array[Short]]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Char]].newArray(10).getClass) + println(implicitly[ArrayTag[Char]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Array[Char]]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Int]].newArray(10).getClass) + println(implicitly[ArrayTag[Int]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Array[Int]]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Long]].newArray(10).getClass) + println(implicitly[ArrayTag[Long]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Array[Long]]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Float]].newArray(10).getClass) + println(implicitly[ArrayTag[Float]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Array[Float]]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Double]].newArray(10).getClass) + println(implicitly[ArrayTag[Double]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Array[Double]]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Boolean]].newArray(10).getClass) + println(implicitly[ArrayTag[Boolean]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Array[Boolean]]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Unit]].newArray(10).getClass) + println(implicitly[ArrayTag[Unit]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Array[Unit]]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Any]].newArray(10).getClass) + println(implicitly[ArrayTag[Any]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Array[Any]]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Object]].newArray(10).getClass) + println(implicitly[ArrayTag[Object]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Array[Object]]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[AnyVal]].newArray(10).getClass) + println(implicitly[ArrayTag[AnyVal]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Array[AnyVal]]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[AnyRef]].newArray(10).getClass) + println(implicitly[ArrayTag[AnyRef]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Array[AnyRef]]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Null]].newArray(10).getClass) + println(implicitly[ArrayTag[Null]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Array[Null]]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Nothing]].newArray(10).getClass) + println(implicitly[ArrayTag[Nothing]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Array[Nothing]]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[String]].newArray(10).getClass) + println(implicitly[ArrayTag[String]].wrap.newArray(10).getClass) + println(implicitly[ArrayTag[Array[String]]].wrap.newArray(10).getClass) +} \ No newline at end of file diff --git a/test/files/run/arraytags_usage.check b/test/files/run/arraytags_usage.check new file mode 100644 index 0000000000..b1d02b7bfe --- /dev/null +++ b/test/files/run/arraytags_usage.check @@ -0,0 +1,3 @@ +class [I +class [I +class [I diff --git a/test/files/run/arraytags_usage.scala b/test/files/run/arraytags_usage.scala new file mode 100644 index 0000000000..60b0a8f218 --- /dev/null +++ b/test/files/run/arraytags_usage.scala @@ -0,0 +1,15 @@ +object Test extends App { + def foo[T] = { + class MyArrayTag extends ArrayTag[T] { + def wrap: ArrayTag[Array[T]] = ??? + def newArray(len: Int): Array[T] = new Array[Int](len).asInstanceOf[Array[T]] + } + + implicit val tag = new MyArrayTag() + println(Array[T]().getClass) + } + + foo[Int] + foo[String] + foo[Array[String]] +} \ No newline at end of file diff --git a/test/files/run/classtags_core.check b/test/files/run/classtags_core.check index ce5a893b08..ebccfcd54c 100644 --- a/test/files/run/classtags_core.check +++ b/test/files/run/classtags_core.check @@ -1,30 +1,32 @@ -true -ClassTag(byte) -true -ClassTag(short) -true -ClassTag(char) -true -ClassTag(int) -true -ClassTag(long) -true -ClassTag(float) -true -ClassTag(double) -true -ClassTag(boolean) -true -ClassTag(void) -true -ClassTag(class java.lang.Object) -true -ClassTag(class java.lang.Object) -true -ClassTag(class java.lang.Object) -true -ClassTag(class java.lang.Object) -true -ClassTag(class java.lang.Object) -true -ClassTag(class java.lang.Object) +true +ClassTag[byte] +true +ClassTag[short] +true +ClassTag[char] +true +ClassTag[int] +true +ClassTag[long] +true +ClassTag[float] +true +ClassTag[double] +true +ClassTag[boolean] +true +ClassTag[void] +true +ClassTag[class java.lang.Object] +true +ClassTag[class java.lang.Object] +true +ClassTag[class java.lang.Object] +true +ClassTag[class java.lang.Object] +true +ClassTag[class scala.runtime.Null$] +true +ClassTag[class scala.runtime.Nothing$] +true +ClassTag[class java.lang.String] diff --git a/test/files/run/classtags_core.scala b/test/files/run/classtags_core.scala index 45c54b1fe0..9f2031377d 100644 --- a/test/files/run/classtags_core.scala +++ b/test/files/run/classtags_core.scala @@ -29,4 +29,6 @@ object Test extends App { println(implicitly[ClassTag[Null]]) println(implicitly[ClassTag[Nothing]] eq ClassTag.Nothing) println(implicitly[ClassTag[Nothing]]) + println(implicitly[ClassTag[String]] eq ClassTag.String) + println(implicitly[ClassTag[String]]) } \ No newline at end of file diff --git a/test/files/run/classtags_multi.check b/test/files/run/classtags_multi.check new file mode 100644 index 0000000000..3a7f16c3a0 --- /dev/null +++ b/test/files/run/classtags_multi.check @@ -0,0 +1,5 @@ +ClassTag[int] +ClassTag[class [I] +ClassTag[class [[I] +ClassTag[class [[[I] +ClassTag[class [[[[I] diff --git a/test/files/run/classtags_multi.scala b/test/files/run/classtags_multi.scala new file mode 100644 index 0000000000..5aafb55223 --- /dev/null +++ b/test/files/run/classtags_multi.scala @@ -0,0 +1,7 @@ +object Test extends App { + println(classTag[Int]) + println(classTag[Array[Int]]) + println(classTag[Array[Array[Int]]]) + println(classTag[Array[Array[Array[Int]]]]) + println(classTag[Array[Array[Array[Array[Int]]]]]) +} \ No newline at end of file diff --git a/test/files/run/classtags_use_concretetypetags.scala b/test/files/run/classtags_use_concretetypetags.scala new file mode 100644 index 0000000000..57e7085cec --- /dev/null +++ b/test/files/run/classtags_use_concretetypetags.scala @@ -0,0 +1,3 @@ +object Test extends App { + def foo[T: ConcreteTypeTag] = Array[T]() +} \ No newline at end of file diff --git a/test/files/run/concretetypetags_core.check b/test/files/run/concretetypetags_core.check new file mode 100644 index 0000000000..f124aa6a35 --- /dev/null +++ b/test/files/run/concretetypetags_core.check @@ -0,0 +1,32 @@ +true +ConcreteTypeTag[Byte] +true +ConcreteTypeTag[Short] +true +ConcreteTypeTag[Char] +true +ConcreteTypeTag[Int] +true +ConcreteTypeTag[Long] +true +ConcreteTypeTag[Float] +true +ConcreteTypeTag[Double] +true +ConcreteTypeTag[Boolean] +true +ConcreteTypeTag[Unit] +true +ConcreteTypeTag[Any] +true +ConcreteTypeTag[Object] +true +ConcreteTypeTag[AnyVal] +true +ConcreteTypeTag[AnyRef] +true +ConcreteTypeTag[Null] +true +ConcreteTypeTag[Nothing] +true +ConcreteTypeTag[String] diff --git a/test/files/run/concretetypetags_core.scala b/test/files/run/concretetypetags_core.scala new file mode 100644 index 0000000000..b6cfea3895 --- /dev/null +++ b/test/files/run/concretetypetags_core.scala @@ -0,0 +1,34 @@ +object Test extends App { + println(implicitly[ConcreteTypeTag[Byte]] eq ConcreteTypeTag.Byte) + println(implicitly[ConcreteTypeTag[Byte]]) + println(implicitly[ConcreteTypeTag[Short]] eq ConcreteTypeTag.Short) + println(implicitly[ConcreteTypeTag[Short]]) + println(implicitly[ConcreteTypeTag[Char]] eq ConcreteTypeTag.Char) + println(implicitly[ConcreteTypeTag[Char]]) + println(implicitly[ConcreteTypeTag[Int]] eq ConcreteTypeTag.Int) + println(implicitly[ConcreteTypeTag[Int]]) + println(implicitly[ConcreteTypeTag[Long]] eq ConcreteTypeTag.Long) + println(implicitly[ConcreteTypeTag[Long]]) + println(implicitly[ConcreteTypeTag[Float]] eq ConcreteTypeTag.Float) + println(implicitly[ConcreteTypeTag[Float]]) + println(implicitly[ConcreteTypeTag[Double]] eq ConcreteTypeTag.Double) + println(implicitly[ConcreteTypeTag[Double]]) + println(implicitly[ConcreteTypeTag[Boolean]] eq ConcreteTypeTag.Boolean) + println(implicitly[ConcreteTypeTag[Boolean]]) + println(implicitly[ConcreteTypeTag[Unit]] eq ConcreteTypeTag.Unit) + println(implicitly[ConcreteTypeTag[Unit]]) + println(implicitly[ConcreteTypeTag[Any]] eq ConcreteTypeTag.Any) + println(implicitly[ConcreteTypeTag[Any]]) + println(implicitly[ConcreteTypeTag[Object]] eq ConcreteTypeTag.Object) + println(implicitly[ConcreteTypeTag[Object]]) + println(implicitly[ConcreteTypeTag[AnyVal]] eq ConcreteTypeTag.AnyVal) + println(implicitly[ConcreteTypeTag[AnyVal]]) + println(implicitly[ConcreteTypeTag[AnyRef]] eq ConcreteTypeTag.AnyRef) + println(implicitly[ConcreteTypeTag[AnyRef]]) + println(implicitly[ConcreteTypeTag[Null]] eq ConcreteTypeTag.Null) + println(implicitly[ConcreteTypeTag[Null]]) + println(implicitly[ConcreteTypeTag[Nothing]] eq ConcreteTypeTag.Nothing) + println(implicitly[ConcreteTypeTag[Nothing]]) + println(implicitly[ConcreteTypeTag[String]] eq ConcreteTypeTag.String) + println(implicitly[ConcreteTypeTag[String]]) +} \ No newline at end of file diff --git a/test/files/run/concretetypetags_multi.check b/test/files/run/concretetypetags_multi.check new file mode 100644 index 0000000000..613106985c --- /dev/null +++ b/test/files/run/concretetypetags_multi.check @@ -0,0 +1,5 @@ +ConcreteTypeTag[Int] +ConcreteTypeTag[Array[Int]] +ConcreteTypeTag[Array[Array[Int]]] +ConcreteTypeTag[Array[Array[Array[Int]]]] +ConcreteTypeTag[Array[Array[Array[Array[Int]]]]] diff --git a/test/files/run/concretetypetags_multi.scala b/test/files/run/concretetypetags_multi.scala new file mode 100644 index 0000000000..7e19d7db34 --- /dev/null +++ b/test/files/run/concretetypetags_multi.scala @@ -0,0 +1,7 @@ +object Test extends App { + println(concreteTypeTag[Int]) + println(concreteTypeTag[Array[Int]]) + println(concreteTypeTag[Array[Array[Int]]]) + println(concreteTypeTag[Array[Array[Array[Int]]]]) + println(concreteTypeTag[Array[Array[Array[Array[Int]]]]]) +} \ No newline at end of file diff --git a/test/files/run/erasuretags_abstract.check b/test/files/run/erasuretags_abstract.check new file mode 100644 index 0000000000..17e7204664 --- /dev/null +++ b/test/files/run/erasuretags_abstract.check @@ -0,0 +1,4 @@ +class java.lang.Object +class java.lang.Object +class java.lang.Object +int diff --git a/test/files/run/erasuretags_abstract.scala b/test/files/run/erasuretags_abstract.scala new file mode 100644 index 0000000000..8e4ad0d090 --- /dev/null +++ b/test/files/run/erasuretags_abstract.scala @@ -0,0 +1,9 @@ +object Test extends App { + def foo1[T] = erasureTag[T] + println(foo1[Int].erasure) + println(foo1[String].erasure) + println(foo1[Array[Int]].erasure) + + def foo2[T <: Int] = erasureTag[T] + println(foo2[Int].erasure) +} \ No newline at end of file diff --git a/test/files/run/erasuretags_basic.check b/test/files/run/erasuretags_basic.check new file mode 100644 index 0000000000..c02a4d32af --- /dev/null +++ b/test/files/run/erasuretags_basic.check @@ -0,0 +1,24 @@ +int +class [I +class scala.collection.immutable.List +class [Lscala.collection.immutable.List; +class scala.collection.immutable.List +class [Lscala.collection.immutable.List; +interface scala.collection.immutable.Map +class [Lscala.collection.immutable.Map; +class [I +class [[I +class [Lscala.collection.immutable.List; +class [[Lscala.collection.immutable.List; +class [Lscala.collection.immutable.List; +class [[Lscala.collection.immutable.List; +class [Lscala.collection.immutable.Map; +class [[Lscala.collection.immutable.Map; +class [[I +class [[[I +class [[Lscala.collection.immutable.List; +class [[[Lscala.collection.immutable.List; +class [[Lscala.collection.immutable.List; +class [[[Lscala.collection.immutable.List; +class [[Lscala.collection.immutable.Map; +class [[[Lscala.collection.immutable.Map; diff --git a/test/files/run/erasuretags_basic.scala b/test/files/run/erasuretags_basic.scala new file mode 100644 index 0000000000..d894fdf2e9 --- /dev/null +++ b/test/files/run/erasuretags_basic.scala @@ -0,0 +1,21 @@ +object Test extends App { + def test[T: ErasureTag] = { + println(implicitly[ErasureTag[T]].erasure) + println(implicitly[ErasureTag[Array[T]]].erasure) + } + + test[Int] + test[List[Int]] + test[List[String]] + test[Map[Int, String]] + + test[Array[Int]] + test[Array[List[Int]]] + test[Array[List[String]]] + test[Array[Map[Int, String]]] + + test[Array[Array[Int]]] + test[Array[Array[List[Int]]]] + test[Array[Array[List[String]]]] + test[Array[Array[Map[Int, String]]]] +} \ No newline at end of file diff --git a/test/files/run/erasuretags_core.check b/test/files/run/erasuretags_core.check new file mode 100644 index 0000000000..2c544678d1 --- /dev/null +++ b/test/files/run/erasuretags_core.check @@ -0,0 +1,32 @@ +byte +class [B +short +class [S +char +class [C +int +class [I +long +class [J +float +class [F +double +class [D +boolean +class [Z +void +class [Lscala.runtime.BoxedUnit; +class java.lang.Object +class [Ljava.lang.Object; +class java.lang.Object +class [Ljava.lang.Object; +class java.lang.Object +class [Ljava.lang.Object; +class java.lang.Object +class [Ljava.lang.Object; +class scala.runtime.Null$ +class [Lscala.runtime.Null$; +class scala.runtime.Nothing$ +class [Lscala.runtime.Nothing$; +class java.lang.String +class [Ljava.lang.String; diff --git a/test/files/run/erasuretags_core.scala b/test/files/run/erasuretags_core.scala new file mode 100644 index 0000000000..5ed06dcd31 --- /dev/null +++ b/test/files/run/erasuretags_core.scala @@ -0,0 +1,34 @@ +object Test extends App { + println(implicitly[ErasureTag[Byte]].erasure) + println(implicitly[ErasureTag[Array[Byte]]].erasure) + println(implicitly[ErasureTag[Short]].erasure) + println(implicitly[ErasureTag[Array[Short]]].erasure) + println(implicitly[ErasureTag[Char]].erasure) + println(implicitly[ErasureTag[Array[Char]]].erasure) + println(implicitly[ErasureTag[Int]].erasure) + println(implicitly[ErasureTag[Array[Int]]].erasure) + println(implicitly[ErasureTag[Long]].erasure) + println(implicitly[ErasureTag[Array[Long]]].erasure) + println(implicitly[ErasureTag[Float]].erasure) + println(implicitly[ErasureTag[Array[Float]]].erasure) + println(implicitly[ErasureTag[Double]].erasure) + println(implicitly[ErasureTag[Array[Double]]].erasure) + println(implicitly[ErasureTag[Boolean]].erasure) + println(implicitly[ErasureTag[Array[Boolean]]].erasure) + println(implicitly[ErasureTag[Unit]].erasure) + println(implicitly[ErasureTag[Array[Unit]]].erasure) + println(implicitly[ErasureTag[Any]].erasure) + println(implicitly[ErasureTag[Array[Any]]].erasure) + println(implicitly[ErasureTag[Object]].erasure) + println(implicitly[ErasureTag[Array[Object]]].erasure) + println(implicitly[ErasureTag[AnyVal]].erasure) + println(implicitly[ErasureTag[Array[AnyVal]]].erasure) + println(implicitly[ErasureTag[AnyRef]].erasure) + println(implicitly[ErasureTag[Array[AnyRef]]].erasure) + println(implicitly[ErasureTag[Null]].erasure) + println(implicitly[ErasureTag[Array[Null]]].erasure) + println(implicitly[ErasureTag[Nothing]].erasure) + println(implicitly[ErasureTag[Array[Nothing]]].erasure) + println(implicitly[ErasureTag[String]].erasure) + println(implicitly[ErasureTag[Array[String]]].erasure) +} \ No newline at end of file diff --git a/test/files/run/erasuretags_usage.scala b/test/files/run/erasuretags_usage.scala new file mode 100644 index 0000000000..16e53af071 --- /dev/null +++ b/test/files/run/erasuretags_usage.scala @@ -0,0 +1,12 @@ +object Test extends App { + def foo[T] = { + class MyErasureTag(_erasure: Class[_]) extends ErasureTag[T] { + def erasure: Class[T] = _erasure.asInstanceOf[Class[T]] + } + + implicit val tag = new MyErasureTag(classOf[Int]) + println(typeTag[T]) + println(typeTag[T].tpe) + println(typeTag[T].erasure) + } +} \ No newline at end of file diff --git a/test/files/run/groundtypetags_core.check b/test/files/run/groundtypetags_core.check deleted file mode 100644 index 62fcb481ae..0000000000 --- a/test/files/run/groundtypetags_core.check +++ /dev/null @@ -1,30 +0,0 @@ -true -ConcreteTypeTag[Byte] -true -ConcreteTypeTag[Short] -true -ConcreteTypeTag[Char] -true -ConcreteTypeTag[Int] -true -ConcreteTypeTag[Long] -true -ConcreteTypeTag[Float] -true -ConcreteTypeTag[Double] -true -ConcreteTypeTag[Boolean] -true -ConcreteTypeTag[Unit] -true -ConcreteTypeTag[Any] -true -ConcreteTypeTag[Object] -true -ConcreteTypeTag[AnyVal] -true -ConcreteTypeTag[AnyRef] -true -ConcreteTypeTag[Null] -true -ConcreteTypeTag[Nothing] diff --git a/test/files/run/groundtypetags_core.scala b/test/files/run/groundtypetags_core.scala deleted file mode 100644 index 8b81a0c795..0000000000 --- a/test/files/run/groundtypetags_core.scala +++ /dev/null @@ -1,32 +0,0 @@ -object Test extends App { - println(implicitly[ConcreteTypeTag[Byte]] eq ConcreteTypeTag.Byte) - println(implicitly[ConcreteTypeTag[Byte]]) - println(implicitly[ConcreteTypeTag[Short]] eq ConcreteTypeTag.Short) - println(implicitly[ConcreteTypeTag[Short]]) - println(implicitly[ConcreteTypeTag[Char]] eq ConcreteTypeTag.Char) - println(implicitly[ConcreteTypeTag[Char]]) - println(implicitly[ConcreteTypeTag[Int]] eq ConcreteTypeTag.Int) - println(implicitly[ConcreteTypeTag[Int]]) - println(implicitly[ConcreteTypeTag[Long]] eq ConcreteTypeTag.Long) - println(implicitly[ConcreteTypeTag[Long]]) - println(implicitly[ConcreteTypeTag[Float]] eq ConcreteTypeTag.Float) - println(implicitly[ConcreteTypeTag[Float]]) - println(implicitly[ConcreteTypeTag[Double]] eq ConcreteTypeTag.Double) - println(implicitly[ConcreteTypeTag[Double]]) - println(implicitly[ConcreteTypeTag[Boolean]] eq ConcreteTypeTag.Boolean) - println(implicitly[ConcreteTypeTag[Boolean]]) - println(implicitly[ConcreteTypeTag[Unit]] eq ConcreteTypeTag.Unit) - println(implicitly[ConcreteTypeTag[Unit]]) - println(implicitly[ConcreteTypeTag[Any]] eq ConcreteTypeTag.Any) - println(implicitly[ConcreteTypeTag[Any]]) - println(implicitly[ConcreteTypeTag[Object]] eq ConcreteTypeTag.Object) - println(implicitly[ConcreteTypeTag[Object]]) - println(implicitly[ConcreteTypeTag[AnyVal]] eq ConcreteTypeTag.AnyVal) - println(implicitly[ConcreteTypeTag[AnyVal]]) - println(implicitly[ConcreteTypeTag[AnyRef]] eq ConcreteTypeTag.AnyRef) - println(implicitly[ConcreteTypeTag[AnyRef]]) - println(implicitly[ConcreteTypeTag[Null]] eq ConcreteTypeTag.Null) - println(implicitly[ConcreteTypeTag[Null]]) - println(implicitly[ConcreteTypeTag[Nothing]] eq ConcreteTypeTag.Nothing) - println(implicitly[ConcreteTypeTag[Nothing]]) -} \ No newline at end of file diff --git a/test/files/run/macro-typecheck-macrosdisabled/Impls_Macros_1.scala b/test/files/run/macro-typecheck-macrosdisabled/Impls_Macros_1.scala index a1f124f790..3de9367994 100644 --- a/test/files/run/macro-typecheck-macrosdisabled/Impls_Macros_1.scala +++ b/test/files/run/macro-typecheck-macrosdisabled/Impls_Macros_1.scala @@ -4,13 +4,6 @@ object Macros { def impl_with_macros_enabled(c: Context) = { import c.mirror._ - // todo. doesn't work. why? - //val mrPkg = staticModule("scala.reflect.package") - //val mrSym = selectTerm(mrPkg, "mirror") - //val NullaryMethodType(mrTpe) = mrSym.typeSignature - //val mr = newFreeTerm("mr", mrTpe, scala.reflect.mirror) - //val tree1 = Apply(Select(Ident(mr), newTermName("reify")), List(Literal(Constant(2)))) - val mr = Select(Select(Select(Ident(newTermName("scala")), newTermName("reflect")), newTermName("package")), newTermName("mirror")) val tree1 = Apply(Select(mr, newTermName("reify")), List(Literal(Constant(2)))) val ttree1 = c.typeCheck(tree1, withMacrosDisabled = false) diff --git a/test/files/run/macro-typecheck-macrosdisabled2.check b/test/files/run/macro-typecheck-macrosdisabled2.check new file mode 100644 index 0000000000..02da6ad0c7 --- /dev/null +++ b/test/files/run/macro-typecheck-macrosdisabled2.check @@ -0,0 +1,5 @@ +{ + val $mr: reflect.mirror.type = scala.reflect.`package`.mirror; + $mr.Expr.apply[Array[Int]]($mr.Apply.apply($mr.Select.apply($mr.Select.apply($mr.Ident($mr.staticModule("scala")), $mr.newTermName("Array")), $mr.newTermName("apply")), scala.collection.immutable.List.apply[$mr.Literal]($mr.Literal.apply($mr.Constant.apply(2)))))($mr.ConcreteTypeTag.apply[Array[Int]]($mr.TypeRef.apply($mr.thisModuleType("scala"), $mr.staticClass("scala.Array"), scala.collection.immutable.List.apply[$mr.Type]($mr.staticClass("scala.Int").asTypeConstructor)), ScalaRunTime.this.arrayClass(classOf[scala.Int]))) +} +mr.reify[Array[Int]](scala.Array.apply(2)) diff --git a/test/files/run/macro-typecheck-macrosdisabled2.flags b/test/files/run/macro-typecheck-macrosdisabled2.flags new file mode 100644 index 0000000000..cd66464f2f --- /dev/null +++ b/test/files/run/macro-typecheck-macrosdisabled2.flags @@ -0,0 +1 @@ +-language:experimental.macros \ No newline at end of file diff --git a/test/files/run/macro-typecheck-macrosdisabled2/Impls_Macros_1.scala b/test/files/run/macro-typecheck-macrosdisabled2/Impls_Macros_1.scala new file mode 100644 index 0000000000..1b840a6204 --- /dev/null +++ b/test/files/run/macro-typecheck-macrosdisabled2/Impls_Macros_1.scala @@ -0,0 +1,29 @@ +import scala.reflect.makro.Context + +object Macros { + def impl_with_macros_enabled(c: Context) = { + import c.mirror._ + + val mr = Select(Select(Select(Ident(newTermName("scala")), newTermName("reflect")), newTermName("package")), newTermName("mirror")) + val tree1 = Apply(Select(mr, newTermName("reify")), List(Apply(Select(Ident(newTermName("scala")), newTermName("Array")), List(Literal(Constant(2)))))) + val ttree1 = c.typeCheck(tree1, withMacrosDisabled = false) + c.literal(ttree1.toString) + } + + def foo_with_macros_enabled = macro impl_with_macros_enabled + + def impl_with_macros_disabled(c: Context) = { + import c.mirror._ + + val mrPkg = staticModule("scala.reflect.package") + val mrSym = selectTerm(mrPkg, "mirror") + val NullaryMethodType(mrTpe) = mrSym.typeSignature + val mr = newFreeTerm("mr", mrTpe, scala.reflect.mirror) + + val tree2 = Apply(Select(Ident(mr), newTermName("reify")), List(Apply(Select(Ident(newTermName("scala")), newTermName("Array")), List(Literal(Constant(2)))))) + val ttree2 = c.typeCheck(tree2, withMacrosDisabled = true) + c.literal(ttree2.toString) + } + + def foo_with_macros_disabled = macro impl_with_macros_disabled +} \ No newline at end of file diff --git a/test/files/run/macro-typecheck-macrosdisabled2/Test_2.scala b/test/files/run/macro-typecheck-macrosdisabled2/Test_2.scala new file mode 100644 index 0000000000..bdba39195b --- /dev/null +++ b/test/files/run/macro-typecheck-macrosdisabled2/Test_2.scala @@ -0,0 +1,4 @@ +object Test extends App { + println(Macros.foo_with_macros_enabled) + println(Macros.foo_with_macros_disabled) +} \ No newline at end of file diff --git a/test/files/run/toolbox_typecheck_macrosdisabled2.check b/test/files/run/toolbox_typecheck_macrosdisabled2.check new file mode 100644 index 0000000000..271139b031 --- /dev/null +++ b/test/files/run/toolbox_typecheck_macrosdisabled2.check @@ -0,0 +1,5 @@ +{ + val $mr: mr.type = mr; + $mr.Expr.apply[Array[Int]]($mr.Apply.apply($mr.Select.apply($mr.Select.apply($mr.Ident($mr.staticModule("scala")), $mr.newTermName("Array")), $mr.newTermName("apply")), scala.collection.immutable.List.apply[$mr.Literal]($mr.Literal.apply($mr.Constant.apply(2)))))($mr.ConcreteTypeTag.apply[Array[Int]]($mr.TypeRef.apply($mr.thisModuleType("scala"), $mr.staticClass("scala.Array"), scala.collection.immutable.List.apply[$mr.Type]($mr.staticClass("scala.Int").asTypeConstructor)), ScalaRunTime.this.arrayClass(classOf[scala.Int]))) +} +mr.reify[Array[Int]](scala.Array.apply(2)) diff --git a/test/files/run/toolbox_typecheck_macrosdisabled2.scala b/test/files/run/toolbox_typecheck_macrosdisabled2.scala new file mode 100644 index 0000000000..b4c76d0600 --- /dev/null +++ b/test/files/run/toolbox_typecheck_macrosdisabled2.scala @@ -0,0 +1,17 @@ +import scala.reflect.mirror._ + +object Test extends App { + val toolbox = mkToolBox() + val mrPkg = staticModule("scala.reflect.package") + val mrSym = selectTerm(mrPkg, "mirror") + val NullaryMethodType(mrTpe) = mrSym.typeSignature + val mr = newFreeTerm("mr", mrTpe, scala.reflect.mirror) + + val tree1 = Apply(Select(Ident(mr), newTermName("reify")), List(Apply(Select(Ident(newTermName("scala")), newTermName("Array")), List(Literal(Constant(2)))))) + val ttree1 = toolbox.typeCheck(tree1, withMacrosDisabled = false) + println(ttree1) + + val tree2 = Apply(Select(Ident(mr), newTermName("reify")), List(Apply(Select(Ident(newTermName("scala")), newTermName("Array")), List(Literal(Constant(2)))))) + val ttree2 = toolbox.typeCheck(tree2, withMacrosDisabled = true) + println(ttree2) +} diff --git a/test/files/run/typetags_core.check b/test/files/run/typetags_core.check index 62fcb481ae..f124aa6a35 100644 --- a/test/files/run/typetags_core.check +++ b/test/files/run/typetags_core.check @@ -1,30 +1,32 @@ -true -ConcreteTypeTag[Byte] -true -ConcreteTypeTag[Short] -true -ConcreteTypeTag[Char] -true -ConcreteTypeTag[Int] -true -ConcreteTypeTag[Long] -true -ConcreteTypeTag[Float] -true -ConcreteTypeTag[Double] -true -ConcreteTypeTag[Boolean] -true -ConcreteTypeTag[Unit] -true -ConcreteTypeTag[Any] -true -ConcreteTypeTag[Object] -true -ConcreteTypeTag[AnyVal] -true -ConcreteTypeTag[AnyRef] -true -ConcreteTypeTag[Null] -true -ConcreteTypeTag[Nothing] +true +ConcreteTypeTag[Byte] +true +ConcreteTypeTag[Short] +true +ConcreteTypeTag[Char] +true +ConcreteTypeTag[Int] +true +ConcreteTypeTag[Long] +true +ConcreteTypeTag[Float] +true +ConcreteTypeTag[Double] +true +ConcreteTypeTag[Boolean] +true +ConcreteTypeTag[Unit] +true +ConcreteTypeTag[Any] +true +ConcreteTypeTag[Object] +true +ConcreteTypeTag[AnyVal] +true +ConcreteTypeTag[AnyRef] +true +ConcreteTypeTag[Null] +true +ConcreteTypeTag[Nothing] +true +ConcreteTypeTag[String] diff --git a/test/files/run/typetags_core.scala b/test/files/run/typetags_core.scala index 883c54b9a8..7d6be16379 100644 --- a/test/files/run/typetags_core.scala +++ b/test/files/run/typetags_core.scala @@ -29,4 +29,6 @@ object Test extends App { println(implicitly[TypeTag[Null]]) println(implicitly[TypeTag[Nothing]] eq TypeTag.Nothing) println(implicitly[TypeTag[Nothing]]) + println(implicitly[TypeTag[String]] eq TypeTag.String) + println(implicitly[TypeTag[String]]) } \ No newline at end of file diff --git a/test/files/run/typetags_multi.check b/test/files/run/typetags_multi.check new file mode 100644 index 0000000000..613106985c --- /dev/null +++ b/test/files/run/typetags_multi.check @@ -0,0 +1,5 @@ +ConcreteTypeTag[Int] +ConcreteTypeTag[Array[Int]] +ConcreteTypeTag[Array[Array[Int]]] +ConcreteTypeTag[Array[Array[Array[Int]]]] +ConcreteTypeTag[Array[Array[Array[Array[Int]]]]] diff --git a/test/files/run/typetags_multi.scala b/test/files/run/typetags_multi.scala new file mode 100644 index 0000000000..868edc2b2a --- /dev/null +++ b/test/files/run/typetags_multi.scala @@ -0,0 +1,7 @@ +object Test extends App { + println(typeTag[Int]) + println(typeTag[Array[Int]]) + println(typeTag[Array[Array[Int]]]) + println(typeTag[Array[Array[Array[Int]]]]) + println(typeTag[Array[Array[Array[Array[Int]]]]]) +} \ No newline at end of file diff --git a/test/files/speclib/instrumented.jar.desired.sha1 b/test/files/speclib/instrumented.jar.desired.sha1 index 2d4cd04a92..a7da67429e 100644 --- a/test/files/speclib/instrumented.jar.desired.sha1 +++ b/test/files/speclib/instrumented.jar.desired.sha1 @@ -1 +1 @@ -d83c6bf3765ab1378943020a8d9cda8851604ffa ?instrumented.jar +15f200d9f0f25f9fd871bad2ebb4ba5cfc671db4 ?instrumented.jar diff --git a/test/instrumented/boxes.patch b/test/instrumented/boxes.patch index 11c5b37aa8..6c5ff23f9f 100644 --- a/test/instrumented/boxes.patch +++ b/test/instrumented/boxes.patch @@ -1,7 +1,8 @@ -9a10,11 +9c9 +< +--- > /* INSTRUMENTED VERSION */ -> -50a53,61 +51a52,59 > public static int booleanBoxCount = 0; > public static int characterBoxCount = 0; > public static int byteBoxCount = 0; @@ -10,20 +11,19 @@ > public static int longBoxCount = 0; > public static int floatBoxCount = 0; > public static int doubleBoxCount = 0; -> -51a63 -> booleanBoxCount++; -55a68 -> characterBoxCount++; -59a73 -> byteBoxCount++; -63a78 -> shortBoxCount++; -67a83 -> integerBoxCount++; -71a88 -> longBoxCount++; -75a93 -> floatBoxCount++; -79a98 -> doubleBoxCount++; +53a62 +> booleanBoxCount += 1; +57a67 +> characterBoxCount += 1; +61a72 +> byteBoxCount += 1; +65a77 +> shortBoxCount += 1; +69a82 +> integerBoxCount += 1; +73a87 +> longBoxCount += 1; +77a92 +> floatBoxCount += 1; +83a99 +> doubleBoxCount += 1; diff --git a/test/instrumented/library/scala/runtime/BoxesRunTime.java b/test/instrumented/library/scala/runtime/BoxesRunTime.java index f06f86f2f2..172ed8ee14 100644 --- a/test/instrumented/library/scala/runtime/BoxesRunTime.java +++ b/test/instrumented/library/scala/runtime/BoxesRunTime.java @@ -6,10 +6,8 @@ ** |/ ** \* */ - /* INSTRUMENTED VERSION */ - package scala.runtime; import java.io.*; @@ -33,14 +31,16 @@ public final class BoxesRunTime { private static final int CHAR = 0, BYTE = 1, SHORT = 2, INT = 3, LONG = 4, FLOAT = 5, DOUBLE = 6, OTHER = 7; + /** We don't need to return BYTE and SHORT, as everything which might + * care widens to INT. + */ private static int typeCode(Object a) { if (a instanceof java.lang.Integer) return INT; - if (a instanceof java.lang.Byte) return BYTE; - if (a instanceof java.lang.Character) return CHAR; - if (a instanceof java.lang.Long) return LONG; if (a instanceof java.lang.Double) return DOUBLE; - if (a instanceof java.lang.Short) return SHORT; + if (a instanceof java.lang.Long) return LONG; + if (a instanceof java.lang.Character) return CHAR; if (a instanceof java.lang.Float) return FLOAT; + if ((a instanceof java.lang.Byte) || (a instanceof java.lang.Short)) return INT; return OTHER; } @@ -49,7 +49,6 @@ public final class BoxesRunTime } /* BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING */ - public static int booleanBoxCount = 0; public static int characterBoxCount = 0; public static int byteBoxCount = 0; @@ -58,46 +57,46 @@ public final class BoxesRunTime public static int longBoxCount = 0; public static int floatBoxCount = 0; public static int doubleBoxCount = 0; - + public static java.lang.Boolean boxToBoolean(boolean b) { - booleanBoxCount++; + booleanBoxCount += 1; return java.lang.Boolean.valueOf(b); } public static java.lang.Character boxToCharacter(char c) { - characterBoxCount++; + characterBoxCount += 1; return java.lang.Character.valueOf(c); } public static java.lang.Byte boxToByte(byte b) { - byteBoxCount++; + byteBoxCount += 1; return java.lang.Byte.valueOf(b); } public static java.lang.Short boxToShort(short s) { - shortBoxCount++; + shortBoxCount += 1; return java.lang.Short.valueOf(s); } public static java.lang.Integer boxToInteger(int i) { - integerBoxCount++; + integerBoxCount += 1; return java.lang.Integer.valueOf(i); } public static java.lang.Long boxToLong(long l) { - longBoxCount++; + longBoxCount += 1; return java.lang.Long.valueOf(l); } public static java.lang.Float boxToFloat(float f) { - floatBoxCount++; + floatBoxCount += 1; return java.lang.Float.valueOf(f); } public static java.lang.Double boxToDouble(double d) { - doubleBoxCount++; // System.out.println("box " + d); // (new Throwable()).printStackTrace(); + doubleBoxCount += 1; return java.lang.Double.valueOf(d); } @@ -138,15 +137,6 @@ public final class BoxesRunTime /* COMPARISON ... COMPARISON ... COMPARISON ... COMPARISON ... COMPARISON ... COMPARISON */ - private static int eqTypeCode(Number a) { - if ((a instanceof java.lang.Integer) || (a instanceof java.lang.Byte)) return INT; - if (a instanceof java.lang.Long) return LONG; - if (a instanceof java.lang.Double) return DOUBLE; - if (a instanceof java.lang.Short) return INT; - if (a instanceof java.lang.Float) return FLOAT; - return OTHER; - } - public static boolean equals(Object x, Object y) { if (x == y) return true; return equals2(x, y); @@ -178,8 +168,8 @@ public final class BoxesRunTime } public static boolean equalsNumNum(java.lang.Number xn, java.lang.Number yn) { - int xcode = eqTypeCode(xn); - int ycode = eqTypeCode(yn); + int xcode = typeCode(xn); + int ycode = typeCode(yn); switch (ycode > xcode ? ycode : xcode) { case INT: return xn.intValue() == yn.intValue(); @@ -211,8 +201,11 @@ public final class BoxesRunTime } private static boolean equalsNumChar(java.lang.Number xn, java.lang.Character yc) { + if (yc == null) + return xn == null; + char ch = yc.charValue(); - switch (eqTypeCode(xn)) { + switch (typeCode(xn)) { case INT: return xn.intValue() == ch; case LONG: @@ -222,9 +215,6 @@ public final class BoxesRunTime case DOUBLE: return xn.doubleValue() == ch; default: - if (xn == null) - return yc == null; - return xn.equals(yc); } } @@ -290,6 +280,31 @@ public final class BoxesRunTime else return a.hashCode(); } + private static int unboxCharOrInt(Object arg1, int code) { + if (code == CHAR) + return ((java.lang.Character) arg1).charValue(); + else + return ((java.lang.Number) arg1).intValue(); + } + private static long unboxCharOrLong(Object arg1, int code) { + if (code == CHAR) + return ((java.lang.Character) arg1).charValue(); + else + return ((java.lang.Number) arg1).longValue(); + } + private static float unboxCharOrFloat(Object arg1, int code) { + if (code == CHAR) + return ((java.lang.Character) arg1).charValue(); + else + return ((java.lang.Number) arg1).floatValue(); + } + private static double unboxCharOrDouble(Object arg1, int code) { + if (code == CHAR) + return ((java.lang.Character) arg1).charValue(); + else + return ((java.lang.Number) arg1).doubleValue(); + } + /* OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS */ /** arg1 + arg2 */ @@ -298,24 +313,16 @@ public final class BoxesRunTime int code2 = typeCode(arg2); int maxcode = (code1 < code2) ? code2 : code1; if (maxcode <= INT) { - int val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).intValue(); - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); - return boxToInteger(val1 + val2); + return boxToInteger(unboxCharOrInt(arg1, code1) + unboxCharOrInt(arg2, code2)); } if (maxcode <= LONG) { - long val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).longValue(); - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); - return boxToLong(val1 + val2); + return boxToLong(unboxCharOrLong(arg1, code1) + unboxCharOrLong(arg2, code2)); } if (maxcode <= FLOAT) { - float val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).floatValue(); - float val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).floatValue(); - return boxToFloat(val1 + val2); + return boxToFloat(unboxCharOrFloat(arg1, code1) + unboxCharOrFloat(arg2, code2)); } if (maxcode <= DOUBLE) { - double val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).doubleValue(); - double val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).doubleValue(); - return boxToDouble(val1 + val2); + return boxToDouble(unboxCharOrDouble(arg1, code1) + unboxCharOrDouble(arg2, code2)); } throw new NoSuchMethodException(); } @@ -326,24 +333,16 @@ public final class BoxesRunTime int code2 = typeCode(arg2); int maxcode = (code1 < code2) ? code2 : code1; if (maxcode <= INT) { - int val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).intValue(); - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); - return boxToInteger(val1 - val2); + return boxToInteger(unboxCharOrInt(arg1, code1) - unboxCharOrInt(arg2, code2)); } if (maxcode <= LONG) { - long val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).longValue(); - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); - return boxToLong(val1 - val2); + return boxToLong(unboxCharOrLong(arg1, code1) - unboxCharOrLong(arg2, code2)); } if (maxcode <= FLOAT) { - float val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).floatValue(); - float val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).floatValue(); - return boxToFloat(val1 - val2); + return boxToFloat(unboxCharOrFloat(arg1, code1) - unboxCharOrFloat(arg2, code2)); } if (maxcode <= DOUBLE) { - double val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).doubleValue(); - double val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).doubleValue(); - return boxToDouble(val1 - val2); + return boxToDouble(unboxCharOrDouble(arg1, code1) - unboxCharOrDouble(arg2, code2)); } throw new NoSuchMethodException(); } @@ -354,24 +353,16 @@ public final class BoxesRunTime int code2 = typeCode(arg2); int maxcode = (code1 < code2) ? code2 : code1; if (maxcode <= INT) { - int val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).intValue(); - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); - return boxToInteger(val1 * val2); + return boxToInteger(unboxCharOrInt(arg1, code1) * unboxCharOrInt(arg2, code2)); } if (maxcode <= LONG) { - long val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).longValue(); - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); - return boxToLong(val1 * val2); + return boxToLong(unboxCharOrLong(arg1, code1) * unboxCharOrLong(arg2, code2)); } if (maxcode <= FLOAT) { - float val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).floatValue(); - float val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).floatValue(); - return boxToFloat(val1 * val2); + return boxToFloat(unboxCharOrFloat(arg1, code1) * unboxCharOrFloat(arg2, code2)); } if (maxcode <= DOUBLE) { - double val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).doubleValue(); - double val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).doubleValue(); - return boxToDouble(val1 * val2); + return boxToDouble(unboxCharOrDouble(arg1, code1) * unboxCharOrDouble(arg2, code2)); } throw new NoSuchMethodException(); } @@ -381,26 +372,16 @@ public final class BoxesRunTime int code1 = typeCode(arg1); int code2 = typeCode(arg2); int maxcode = (code1 < code2) ? code2 : code1; - if (maxcode <= INT) { - int val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).intValue(); - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); - return boxToInteger(val1 / val2); - } - if (maxcode <= LONG) { - long val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).longValue(); - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); - return boxToLong(val1 / val2); - } - if (maxcode <= FLOAT) { - float val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).floatValue(); - float val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).floatValue(); - return boxToFloat(val1 / val2); - } - if (maxcode <= DOUBLE) { - double val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).doubleValue(); - double val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).doubleValue(); - return boxToDouble(val1 / val2); - } + + if (maxcode <= INT) + return boxToInteger(unboxCharOrInt(arg1, code1) / unboxCharOrInt(arg2, code2)); + if (maxcode <= LONG) + return boxToLong(unboxCharOrLong(arg1, code1) / unboxCharOrLong(arg2, code2)); + if (maxcode <= FLOAT) + return boxToFloat(unboxCharOrFloat(arg1, code1) / unboxCharOrFloat(arg2, code2)); + if (maxcode <= DOUBLE) + return boxToDouble(unboxCharOrDouble(arg1, code1) / unboxCharOrDouble(arg2, code2)); + throw new NoSuchMethodException(); } @@ -409,26 +390,16 @@ public final class BoxesRunTime int code1 = typeCode(arg1); int code2 = typeCode(arg2); int maxcode = (code1 < code2) ? code2 : code1; - if (maxcode <= INT) { - int val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).intValue(); - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); - return boxToInteger(val1 % val2); - } - if (maxcode <= LONG) { - long val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).longValue(); - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); - return boxToLong(val1 % val2); - } - if (maxcode <= FLOAT) { - float val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).floatValue(); - float val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).floatValue(); - return boxToFloat(val1 % val2); - } - if (maxcode <= DOUBLE) { - double val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).doubleValue(); - double val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).doubleValue(); - return boxToDouble(val1 % val2); - } + + if (maxcode <= INT) + return boxToInteger(unboxCharOrInt(arg1, code1) % unboxCharOrInt(arg2, code2)); + if (maxcode <= LONG) + return boxToLong(unboxCharOrLong(arg1, code1) % unboxCharOrLong(arg2, code2)); + if (maxcode <= FLOAT) + return boxToFloat(unboxCharOrFloat(arg1, code1) % unboxCharOrFloat(arg2, code2)); + if (maxcode <= DOUBLE) + return boxToDouble(unboxCharOrDouble(arg1, code1) % unboxCharOrDouble(arg2, code2)); + throw new NoSuchMethodException(); } @@ -437,24 +408,24 @@ public final class BoxesRunTime int code1 = typeCode(arg1); int code2 = typeCode(arg2); if (code1 <= INT) { - int val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).intValue(); + int val1 = unboxCharOrInt(arg1, code1); if (code2 <= INT) { - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); + int val2 = unboxCharOrInt(arg2, code2); return boxToInteger(val1 >> val2); } if (code2 <= LONG) { - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); + long val2 = unboxCharOrLong(arg2, code2); return boxToInteger(val1 >> val2); } } if (code1 <= LONG) { - long val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).longValue(); + long val1 = unboxCharOrLong(arg1, code1); if (code2 <= INT) { - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); + int val2 = unboxCharOrInt(arg2, code2); return boxToLong(val1 >> val2); } if (code2 <= LONG) { - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); + long val2 = unboxCharOrLong(arg2, code2); return boxToLong(val1 >> val2); } } @@ -466,24 +437,24 @@ public final class BoxesRunTime int code1 = typeCode(arg1); int code2 = typeCode(arg2); if (code1 <= INT) { - int val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).intValue(); + int val1 = unboxCharOrInt(arg1, code1); if (code2 <= INT) { - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); + int val2 = unboxCharOrInt(arg2, code2); return boxToInteger(val1 << val2); } if (code2 <= LONG) { - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); + long val2 = unboxCharOrLong(arg2, code2); return boxToInteger(val1 << val2); } } if (code1 <= LONG) { - long val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).longValue(); + long val1 = unboxCharOrLong(arg1, code1); if (code2 <= INT) { - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); + int val2 = unboxCharOrInt(arg2, code2); return boxToLong(val1 << val2); } if (code2 <= LONG) { - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); + long val2 = unboxCharOrLong(arg2, code2); return boxToLong(val1 << val2); } } @@ -495,24 +466,24 @@ public final class BoxesRunTime int code1 = typeCode(arg1); int code2 = typeCode(arg2); if (code1 <= INT) { - int val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).intValue(); + int val1 = unboxCharOrInt(arg1, code1); if (code2 <= INT) { - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); + int val2 = unboxCharOrInt(arg2, code2); return boxToInteger(val1 >>> val2); } if (code2 <= LONG) { - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); + long val2 = unboxCharOrLong(arg2, code2); return boxToInteger(val1 >>> val2); } } if (code1 <= LONG) { - long val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).longValue(); + long val1 = unboxCharOrLong(arg1, code1); if (code2 <= INT) { - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); + int val2 = unboxCharOrInt(arg2, code2); return boxToLong(val1 >>> val2); } if (code2 <= LONG) { - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); + long val2 = unboxCharOrLong(arg2, code2); return boxToLong(val1 >>> val2); } } @@ -523,19 +494,19 @@ public final class BoxesRunTime public static Object negate(Object arg) throws NoSuchMethodException { int code = typeCode(arg); if (code <= INT) { - int val = (code == CHAR) ? ((java.lang.Character) arg).charValue() : ((java.lang.Number) arg).intValue(); + int val = unboxCharOrInt(arg, code); return boxToInteger(-val); } if (code <= LONG) { - long val = (code == CHAR) ? ((java.lang.Character) arg).charValue() : ((java.lang.Number) arg).longValue(); + long val = unboxCharOrLong(arg, code); return boxToLong(-val); } if (code <= FLOAT) { - float val = (code == CHAR) ? ((java.lang.Character) arg).charValue() : ((java.lang.Number) arg).floatValue(); + float val = unboxCharOrFloat(arg, code); return boxToFloat(-val); } if (code <= DOUBLE) { - double val = (code == CHAR) ? ((java.lang.Character) arg).charValue() : ((java.lang.Number) arg).doubleValue(); + double val = unboxCharOrDouble(arg, code); return boxToDouble(-val); } throw new NoSuchMethodException(); @@ -545,20 +516,16 @@ public final class BoxesRunTime public static Object positive(Object arg) throws NoSuchMethodException { int code = typeCode(arg); if (code <= INT) { - int val = (code == CHAR) ? ((java.lang.Character) arg).charValue() : ((java.lang.Number) arg).intValue(); - return boxToInteger(+val); + return boxToInteger(+unboxCharOrInt(arg, code)); } if (code <= LONG) { - long val = (code == CHAR) ? ((java.lang.Character) arg).charValue() : ((java.lang.Number) arg).longValue(); - return boxToLong(+val); + return boxToLong(+unboxCharOrLong(arg, code)); } if (code <= FLOAT) { - float val = (code == CHAR) ? ((java.lang.Character) arg).charValue() : ((java.lang.Number) arg).floatValue(); - return boxToFloat(+val); + return boxToFloat(+unboxCharOrFloat(arg, code)); } if (code <= DOUBLE) { - double val = (code == CHAR) ? ((java.lang.Character) arg).charValue() : ((java.lang.Number) arg).doubleValue(); - return boxToDouble(+val); + return boxToDouble(+unboxCharOrDouble(arg, code)); } throw new NoSuchMethodException(); } @@ -566,72 +533,60 @@ public final class BoxesRunTime /** arg1 & arg2 */ public static Object takeAnd(Object arg1, Object arg2) throws NoSuchMethodException { if ((arg1 instanceof Boolean) || (arg2 instanceof Boolean)) { - if (!((arg1 instanceof Boolean) && (arg2 instanceof Boolean))) { + if ((arg1 instanceof Boolean) && (arg2 instanceof Boolean)) + return boxToBoolean(((java.lang.Boolean) arg1).booleanValue() & ((java.lang.Boolean) arg2).booleanValue()); + else throw new NoSuchMethodException(); - } - return boxToBoolean(((java.lang.Boolean) arg1).booleanValue() & ((java.lang.Boolean) arg2).booleanValue()); } int code1 = typeCode(arg1); int code2 = typeCode(arg2); int maxcode = (code1 < code2) ? code2 : code1; - if (maxcode <= INT) { - int val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).intValue(); - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); - return boxToInteger(val1 & val2); - } - if (maxcode <= LONG) { - long val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).longValue(); - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); - return boxToLong(val1 & val2); - } + + if (maxcode <= INT) + return boxToInteger(unboxCharOrInt(arg1, code1) & unboxCharOrInt(arg2, code2)); + if (maxcode <= LONG) + return boxToLong(unboxCharOrLong(arg1, code1) & unboxCharOrLong(arg2, code2)); + throw new NoSuchMethodException(); } /** arg1 | arg2 */ public static Object takeOr(Object arg1, Object arg2) throws NoSuchMethodException { if ((arg1 instanceof Boolean) || (arg2 instanceof Boolean)) { - if (!((arg1 instanceof Boolean) && (arg2 instanceof Boolean))) { + if ((arg1 instanceof Boolean) && (arg2 instanceof Boolean)) + return boxToBoolean(((java.lang.Boolean) arg1).booleanValue() | ((java.lang.Boolean) arg2).booleanValue()); + else throw new NoSuchMethodException(); - } - return boxToBoolean(((java.lang.Boolean) arg1).booleanValue() | ((java.lang.Boolean) arg2).booleanValue()); } int code1 = typeCode(arg1); int code2 = typeCode(arg2); int maxcode = (code1 < code2) ? code2 : code1; - if (maxcode <= INT) { - int val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).intValue(); - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); - return boxToInteger(val1 | val2); - } - if (maxcode <= LONG) { - long val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).longValue(); - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); - return boxToLong(val1 | val2); - } + + if (maxcode <= INT) + return boxToInteger(unboxCharOrInt(arg1, code1) | unboxCharOrInt(arg2, code2)); + if (maxcode <= LONG) + return boxToLong(unboxCharOrLong(arg1, code1) | unboxCharOrLong(arg2, code2)); + throw new NoSuchMethodException(); } /** arg1 ^ arg2 */ public static Object takeXor(Object arg1, Object arg2) throws NoSuchMethodException { if ((arg1 instanceof Boolean) || (arg2 instanceof Boolean)) { - if (!((arg1 instanceof Boolean) && (arg2 instanceof Boolean))) { + if ((arg1 instanceof Boolean) && (arg2 instanceof Boolean)) + return boxToBoolean(((java.lang.Boolean) arg1).booleanValue() ^ ((java.lang.Boolean) arg2).booleanValue()); + else throw new NoSuchMethodException(); - } - return boxToBoolean(((java.lang.Boolean) arg1).booleanValue() ^ ((java.lang.Boolean) arg2).booleanValue()); } int code1 = typeCode(arg1); int code2 = typeCode(arg2); int maxcode = (code1 < code2) ? code2 : code1; - if (maxcode <= INT) { - int val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).intValue(); - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); - return boxToInteger(val1 ^ val2); - } - if (maxcode <= LONG) { - long val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).longValue(); - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); - return boxToLong(val1 ^ val2); - } + + if (maxcode <= INT) + return boxToInteger(unboxCharOrInt(arg1, code1) ^ unboxCharOrInt(arg2, code2)); + if (maxcode <= LONG) + return boxToLong(unboxCharOrLong(arg1, code1) ^ unboxCharOrLong(arg2, code2)); + throw new NoSuchMethodException(); } @@ -655,12 +610,10 @@ public final class BoxesRunTime public static Object complement(Object arg) throws NoSuchMethodException { int code = typeCode(arg); if (code <= INT) { - int val = (code == CHAR) ? ((java.lang.Character) arg).charValue() : ((java.lang.Number) arg).intValue(); - return boxToInteger(~val); + return boxToInteger(~unboxCharOrInt(arg, code)); } if (code <= LONG) { - long val = (code == CHAR) ? ((java.lang.Character) arg).charValue() : ((java.lang.Number) arg).longValue(); - return boxToLong(~val); + return boxToLong(~unboxCharOrLong(arg, code)); } throw new NoSuchMethodException(); } @@ -686,23 +639,23 @@ public final class BoxesRunTime int code2 = typeCode(arg2); int maxcode = (code1 < code2) ? code2 : code1; if (maxcode <= INT) { - int val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).intValue(); - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); + int val1 = unboxCharOrInt(arg1, code1); + int val2 = unboxCharOrInt(arg2, code2); return boxToBoolean(val1 < val2); } if (maxcode <= LONG) { - long val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).longValue(); - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); + long val1 = unboxCharOrLong(arg1, code1); + long val2 = unboxCharOrLong(arg2, code2); return boxToBoolean(val1 < val2); } if (maxcode <= FLOAT) { - float val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).floatValue(); - float val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).floatValue(); + float val1 = unboxCharOrFloat(arg1, code1); + float val2 = unboxCharOrFloat(arg2, code2); return boxToBoolean(val1 < val2); } if (maxcode <= DOUBLE) { - double val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).doubleValue(); - double val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).doubleValue(); + double val1 = unboxCharOrDouble(arg1, code1); + double val2 = unboxCharOrDouble(arg2, code2); return boxToBoolean(val1 < val2); } throw new NoSuchMethodException(); @@ -713,23 +666,23 @@ public final class BoxesRunTime int code2 = typeCode(arg2); int maxcode = (code1 < code2) ? code2 : code1; if (maxcode <= INT) { - int val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).intValue(); - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); + int val1 = unboxCharOrInt(arg1, code1); + int val2 = unboxCharOrInt(arg2, code2); return boxToBoolean(val1 <= val2); } if (maxcode <= LONG) { - long val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).longValue(); - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); + long val1 = unboxCharOrLong(arg1, code1); + long val2 = unboxCharOrLong(arg2, code2); return boxToBoolean(val1 <= val2); } if (maxcode <= FLOAT) { - float val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).floatValue(); - float val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).floatValue(); + float val1 = unboxCharOrFloat(arg1, code1); + float val2 = unboxCharOrFloat(arg2, code2); return boxToBoolean(val1 <= val2); } if (maxcode <= DOUBLE) { - double val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).doubleValue(); - double val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).doubleValue(); + double val1 = unboxCharOrDouble(arg1, code1); + double val2 = unboxCharOrDouble(arg2, code2); return boxToBoolean(val1 <= val2); } throw new NoSuchMethodException(); @@ -740,23 +693,23 @@ public final class BoxesRunTime int code2 = typeCode(arg2); int maxcode = (code1 < code2) ? code2 : code1; if (maxcode <= INT) { - int val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).intValue(); - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); + int val1 = unboxCharOrInt(arg1, code1); + int val2 = unboxCharOrInt(arg2, code2); return boxToBoolean(val1 >= val2); } if (maxcode <= LONG) { - long val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).longValue(); - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); + long val1 = unboxCharOrLong(arg1, code1); + long val2 = unboxCharOrLong(arg2, code2); return boxToBoolean(val1 >= val2); } if (maxcode <= FLOAT) { - float val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).floatValue(); - float val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).floatValue(); + float val1 = unboxCharOrFloat(arg1, code1); + float val2 = unboxCharOrFloat(arg2, code2); return boxToBoolean(val1 >= val2); } if (maxcode <= DOUBLE) { - double val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).doubleValue(); - double val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).doubleValue(); + double val1 = unboxCharOrDouble(arg1, code1); + double val2 = unboxCharOrDouble(arg2, code2); return boxToBoolean(val1 >= val2); } throw new NoSuchMethodException(); @@ -767,33 +720,30 @@ public final class BoxesRunTime int code2 = typeCode(arg2); int maxcode = (code1 < code2) ? code2 : code1; if (maxcode <= INT) { - int val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).intValue(); - int val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).intValue(); + int val1 = unboxCharOrInt(arg1, code1); + int val2 = unboxCharOrInt(arg2, code2); return boxToBoolean(val1 > val2); } if (maxcode <= LONG) { - long val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).longValue(); - long val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).longValue(); + long val1 = unboxCharOrLong(arg1, code1); + long val2 = unboxCharOrLong(arg2, code2); return boxToBoolean(val1 > val2); } if (maxcode <= FLOAT) { - float val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).floatValue(); - float val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).floatValue(); + float val1 = unboxCharOrFloat(arg1, code1); + float val2 = unboxCharOrFloat(arg2, code2); return boxToBoolean(val1 > val2); } if (maxcode <= DOUBLE) { - double val1 = (code1 == CHAR) ? ((java.lang.Character) arg1).charValue() : ((java.lang.Number) arg1).doubleValue(); - double val2 = (code2 == CHAR) ? ((java.lang.Character) arg2).charValue() : ((java.lang.Number) arg2).doubleValue(); + double val1 = unboxCharOrDouble(arg1, code1); + double val2 = unboxCharOrDouble(arg2, code2); return boxToBoolean(val1 > val2); } throw new NoSuchMethodException(); } - + public static boolean isBoxedNumberOrBoolean(Object arg) { - if (arg instanceof java.lang.Boolean) - return true; - else - return isBoxedNumber(arg); + return (arg instanceof java.lang.Boolean) || isBoxedNumber(arg); } public static boolean isBoxedNumber(Object arg) { return ( diff --git a/test/instrumented/library/scala/runtime/ScalaRunTime.scala b/test/instrumented/library/scala/runtime/ScalaRunTime.scala index 9eb93a418d..63908fcc29 100644 --- a/test/instrumented/library/scala/runtime/ScalaRunTime.scala +++ b/test/instrumented/library/scala/runtime/ScalaRunTime.scala @@ -6,9 +6,9 @@ ** |/ ** \* */ -package scala.runtime /* INSTRUMENTED VERSION */ +package scala.runtime import scala.collection.{ Seq, IndexedSeq, TraversableView, AbstractIterator } import scala.collection.mutable.WrappedArray @@ -33,10 +33,7 @@ object ScalaRunTime { clazz.isArray && (atLevel == 1 || isArrayClass(clazz.getComponentType, atLevel - 1)) def isValueClass(clazz: Class[_]) = clazz.isPrimitive() - var arrayApplyCount = 0 - var arrayUpdateCount = 0 - - def isTuple(x: Any) = tupleNames(x.getClass.getName) + def isTuple(x: Any) = x != null && tupleNames(x.getClass.getName) def isAnyVal(x: Any) = x match { case _: Byte | _: Short | _: Char | _: Int | _: Long | _: Float | _: Double | _: Boolean | _: Unit => true case _ => false @@ -52,56 +49,68 @@ object ScalaRunTime { names.toSet } + /** Return the class object representing an array with element class `clazz`. + */ + def arrayClass(clazz: Class[_]): Class[_] = { + // newInstance throws an exception if the erasure is Void.TYPE. see SI-5680 + if (clazz == java.lang.Void.TYPE) classOf[Array[Unit]] + else java.lang.reflect.Array.newInstance(clazz, 0).getClass + } + + /** Return the class object representing elements in arrays described by a given schematic. + */ + def arrayElementClass(schematic: Any): Class[_] = schematic match { + case cls: Class[_] => cls.getComponentType + case tag: ClassTag[_] => tag.erasure + case tag: ArrayTag[_] => tag.newArray(0).getClass.getComponentType + case _ => throw new UnsupportedOperationException("unsupported schematic %s (%s)".format(schematic, if (schematic == null) "null" else schematic.getClass)) + } + /** Return the class object representing an unboxed value type, * e.g. classOf[int], not classOf[java.lang.Integer]. The compiler * rewrites expressions like 5.getClass to come here. */ - def anyValClass[T <: AnyVal](value: T): Class[T] = (value match { - case x: Byte => java.lang.Byte.TYPE - case x: Short => java.lang.Short.TYPE - case x: Char => java.lang.Character.TYPE - case x: Int => java.lang.Integer.TYPE - case x: Long => java.lang.Long.TYPE - case x: Float => java.lang.Float.TYPE - case x: Double => java.lang.Double.TYPE - case x: Boolean => java.lang.Boolean.TYPE - case x: Unit => java.lang.Void.TYPE - }).asInstanceOf[Class[T]] + def anyValClass[T <: AnyVal : ClassTag](value: T): Class[T] = + classTag[T].erasure.asInstanceOf[Class[T]] + + var arrayApplyCount = 0 /** Retrieve generic array element */ def array_apply(xs: AnyRef, idx: Int): Any = { arrayApplyCount += 1 xs match { - case x: Array[AnyRef] => x(idx).asInstanceOf[Any] - case x: Array[Int] => x(idx).asInstanceOf[Any] - case x: Array[Double] => x(idx).asInstanceOf[Any] - case x: Array[Long] => x(idx).asInstanceOf[Any] - case x: Array[Float] => x(idx).asInstanceOf[Any] - case x: Array[Char] => x(idx).asInstanceOf[Any] - case x: Array[Byte] => x(idx).asInstanceOf[Any] - case x: Array[Short] => x(idx).asInstanceOf[Any] - case x: Array[Boolean] => x(idx).asInstanceOf[Any] - case x: Array[Unit] => x(idx).asInstanceOf[Any] - case null => throw new NullPointerException - } + case x: Array[AnyRef] => x(idx).asInstanceOf[Any] + case x: Array[Int] => x(idx).asInstanceOf[Any] + case x: Array[Double] => x(idx).asInstanceOf[Any] + case x: Array[Long] => x(idx).asInstanceOf[Any] + case x: Array[Float] => x(idx).asInstanceOf[Any] + case x: Array[Char] => x(idx).asInstanceOf[Any] + case x: Array[Byte] => x(idx).asInstanceOf[Any] + case x: Array[Short] => x(idx).asInstanceOf[Any] + case x: Array[Boolean] => x(idx).asInstanceOf[Any] + case x: Array[Unit] => x(idx).asInstanceOf[Any] + case null => throw new NullPointerException + } } + var arrayUpdateCount = 0 + /** update generic array element */ def array_update(xs: AnyRef, idx: Int, value: Any): Unit = { arrayUpdateCount += 1 xs match { - case x: Array[AnyRef] => x(idx) = value.asInstanceOf[AnyRef] - case x: Array[Int] => x(idx) = value.asInstanceOf[Int] - case x: Array[Double] => x(idx) = value.asInstanceOf[Double] - case x: Array[Long] => x(idx) = value.asInstanceOf[Long] - case x: Array[Float] => x(idx) = value.asInstanceOf[Float] - case x: Array[Char] => x(idx) = value.asInstanceOf[Char] - case x: Array[Byte] => x(idx) = value.asInstanceOf[Byte] - case x: Array[Short] => x(idx) = value.asInstanceOf[Short] - case x: Array[Boolean] => x(idx) = value.asInstanceOf[Boolean] - case x: Array[Unit] => x(idx) = value.asInstanceOf[Unit] - case null => throw new NullPointerException - } + case x: Array[AnyRef] => x(idx) = value.asInstanceOf[AnyRef] + case x: Array[Int] => x(idx) = value.asInstanceOf[Int] + case x: Array[Double] => x(idx) = value.asInstanceOf[Double] + case x: Array[Long] => x(idx) = value.asInstanceOf[Long] + case x: Array[Float] => x(idx) = value.asInstanceOf[Float] + case x: Array[Char] => x(idx) = value.asInstanceOf[Char] + case x: Array[Byte] => x(idx) = value.asInstanceOf[Byte] + case x: Array[Short] => x(idx) = value.asInstanceOf[Short] + case x: Array[Boolean] => x(idx) = value.asInstanceOf[Boolean] + case x: Array[Unit] => x(idx) = value.asInstanceOf[Unit] + case null => throw new NullPointerException + } } /** Get generic array length */ @@ -340,14 +349,14 @@ object ScalaRunTime { case null => "null" case "" => "\"\"" case x: String => if (x.head.isWhitespace || x.last.isWhitespace) "\"" + x + "\"" else x - case x if useOwnToString(x) => x toString + case x if useOwnToString(x) => x.toString case x: AnyRef if isArray(x) => arrayToString(x) case x: collection.Map[_, _] => x.iterator take maxElements map mapInner mkString (x.stringPrefix + "(", ", ", ")") case x: Iterable[_] => x.iterator take maxElements map inner mkString (x.stringPrefix + "(", ", ", ")") case x: Traversable[_] => x take maxElements map inner mkString (x.stringPrefix + "(", ", ", ")") case x: Product1[_] if isTuple(x) => "(" + inner(x._1) + ",)" // that special trailing comma case x: Product if isTuple(x) => x.productIterator map inner mkString ("(", ",", ")") - case x => x toString + case x => x.toString } // The try/catch is defense against iterables which aren't actually designed diff --git a/test/instrumented/srt.patch b/test/instrumented/srt.patch index 2f472ff1c0..8d08550165 100644 --- a/test/instrumented/srt.patch +++ b/test/instrumented/srt.patch @@ -1,23 +1,26 @@ 9a10,11 > /* INSTRUMENTED VERSION */ -> -33a36,38 +> +43c45,48 +< def isTuple(x: Any) = x != null && tupleNames(x.getClass.getName) +--- > var arrayApplyCount = 0 > var arrayUpdateCount = 0 -> -35c40,42 +> +> def isTuple(x: Any) = tupleNames(x.getClass.getName) +75c80,82 < def array_apply(xs: AnyRef, idx: Int): Any = xs match { --- > def array_apply(xs: AnyRef, idx: Int): Any = { > arrayApplyCount += 1 > xs match { -47a55 +87a95 > } -50c58,60 +90c98,100 < def array_update(xs: AnyRef, idx: Int, value: Any): Unit = xs match { --- > def array_update(xs: AnyRef, idx: Int, value: Any): Unit = { > arrayUpdateCount += 1 > xs match { -62a73 +101a112 > } -- cgit v1.2.3