summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-04-23 17:51:28 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-04-23 17:54:19 +0200
commit2b09d8caf5497c4e016a3e1179e5f7e842766176 (patch)
tree27c872f82fb8290b8cba6fa626ecd0b0dd627229 /src/compiler
parent14df5d74b58505e082d6f7c0e42b51249d35eec4 (diff)
downloadscala-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')
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala16
-rw-r--r--src/compiler/scala/reflect/internal/StdNames.scala42
-rw-r--r--src/compiler/scala/reflect/internal/TreeInfo.scala6
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala21
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Reifiers.scala123
-rw-r--r--src/compiler/scala/reflect/reify/Errors.scala8
-rw-r--r--src/compiler/scala/reflect/reify/Reifier.scala38
-rw-r--r--src/compiler/scala/reflect/reify/codegen/Symbols.scala2
-rw-r--r--src/compiler/scala/reflect/reify/codegen/Types.scala18
-rw-r--r--src/compiler/scala/reflect/reify/package.scala38
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/RichClass.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala10
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala18
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala52
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Taggings.scala71
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala50
-rw-r--r--src/compiler/scala/tools/reflect/package.scala3
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