diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2012-04-23 17:51:28 +0200 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2012-04-23 17:54:19 +0200 |
commit | 2b09d8caf5497c4e016a3e1179e5f7e842766176 (patch) | |
tree | 27c872f82fb8290b8cba6fa626ecd0b0dd627229 /src/compiler/scala | |
parent | 14df5d74b58505e082d6f7c0e42b51249d35eec4 (diff) | |
download | scala-2b09d8caf5497c4e016a3e1179e5f7e842766176.tar.gz scala-2b09d8caf5497c4e016a3e1179e5f7e842766176.tar.bz2 scala-2b09d8caf5497c4e016a3e1179e5f7e842766176.zip |
rethinks tags
* introduces ArrayTag and ErasureTag
* all type tags now feature erasure
Diffstat (limited to 'src/compiler/scala')
19 files changed, 273 insertions, 250 deletions
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 |