summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala80
-rw-r--r--src/compiler/scala/tools/nsc/transform/PostErasure.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala4
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala10
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala19
-rw-r--r--src/reflect/scala/reflect/internal/transform/Erasure.scala51
7 files changed, 126 insertions, 47 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 327a864e3b..e378d71944 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -319,7 +319,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
def ccon = Class.forName(name).getConstructor(classOf[CharsetDecoder], classOf[Reporter])
try Some(ccon.newInstance(charset.newDecoder(), reporter).asInstanceOf[SourceReader])
- catch { case x: Exception =>
+ catch { case ex: Throwable =>
globalError("exception while trying to instantiate source reader '" + name + "'")
None
}
@@ -1546,7 +1546,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
def compileUnits(units: List[CompilationUnit], fromPhase: Phase) {
try compileUnitsInternal(units, fromPhase)
- catch { case ex =>
+ catch { case ex: Throwable =>
val shown = if (settings.verbose.value) {
val pw = new java.io.PrintWriter(new java.io.StringWriter)
ex.printStackTrace(pw)
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 1276d62995..5115c49c87 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -351,7 +351,7 @@ abstract class Erasure extends AddInterfaces
List())
if cast.symbol == Object_asInstanceOf &&
tpt.tpe.typeSymbol.isDerivedValueClass &&
- sel.symbol == tpt.tpe.typeSymbol.firstParamAccessor =>
+ sel.symbol == tpt.tpe.typeSymbol.derivedValueClassUnbox =>
Some(arg)
case _ =>
None
@@ -498,7 +498,8 @@ abstract class Erasure extends AddInterfaces
ldef setType ldef.rhs.tpe
case _ =>
val tree1 = tree.tpe match {
- case ErasedValueType(clazz) =>
+ case ErasedValueType(tref) =>
+ val clazz = tref.sym
tree match {
case Unboxed(arg) if arg.tpe.typeSymbol == clazz =>
log("shortcircuiting unbox -> box "+arg); arg
@@ -554,25 +555,26 @@ abstract class Erasure extends AddInterfaces
ldef setType ldef.rhs.tpe
case _ =>
val tree1 = pt match {
- case ErasedValueType(clazz) =>
+ case ErasedValueType(tref) =>
tree match {
case Boxed(arg) if arg.tpe.isInstanceOf[ErasedValueType] =>
log("shortcircuiting box -> unbox "+arg)
arg
case _ =>
+ val clazz = tref.sym
log("not boxed: "+tree)
val tree0 = adaptToType(tree, clazz.tpe)
- cast(Apply(Select(tree0, clazz.firstParamAccessor), List()), pt)
+ cast(Apply(Select(tree0, clazz.derivedValueClassUnbox), List()), pt)
}
case _ =>
pt.typeSymbol match {
- case UnitClass =>
- if (treeInfo isExprSafeToInline tree) UNIT
- else BLOCK(tree, UNIT)
- case x =>
- assert(x != ArrayClass)
- // don't `setType pt` the Apply tree, as the Apply's fun won't be typechecked if the Apply tree already has a type
- Apply(unboxMethod(pt.typeSymbol), tree)
+ case UnitClass =>
+ if (treeInfo isExprSafeToInline tree) UNIT
+ else BLOCK(tree, UNIT)
+ case x =>
+ assert(x != ArrayClass)
+ // don't `setType pt` the Apply tree, as the Apply's fun won't be typechecked if the Apply tree already has a type
+ Apply(unboxMethod(pt.typeSymbol), tree)
}
}
typedPos(tree.pos)(tree1)
@@ -601,7 +603,7 @@ abstract class Erasure extends AddInterfaces
* @return the adapted tree
*/
private def adaptToType(tree: Tree, pt: Type): Tree = {
- if (settings.debug.value && pt != WildcardType)
+ //if (settings.debug.value && pt != WildcardType)
log("adapting " + tree + ":" + tree.tpe + " : " + tree.tpe.parents + " to " + pt)//debug
if (tree.tpe <:< pt)
tree
@@ -629,7 +631,7 @@ abstract class Erasure extends AddInterfaces
* - `x != y` for != in class Any becomes `!(x equals y)` with equals in class Object.
* - x.asInstanceOf[T] becomes x.$asInstanceOf[T]
* - x.isInstanceOf[T] becomes x.$isInstanceOf[T]
- * - x.isInstanceOf[ErasedValueType(clazz)] becomes x.isInstanceOf[clazz.tpe]
+ * - x.isInstanceOf[ErasedValueType(tref)] becomes x.isInstanceOf[tref.sym.tpe]
* - x.m where m is some other member of Any becomes x.m where m is a member of class Object.
* - x.m where x has unboxed value type T and m is not a directly translated member of T becomes T.box(x).m
* - x.m where x is a reference type and m is a directly translated member of value type T becomes x.TValue().m
@@ -651,12 +653,33 @@ abstract class Erasure extends AddInterfaces
atPos(tree.pos)(Apply(Select(qual1, "to" + targClass.name), List()))
else
*/
- if (isPrimitiveValueType(targ.tpe) || isErasedValueType(targ.tpe)) unbox(qual1, targ.tpe)
- else tree
+ if (isPrimitiveValueType(targ.tpe) || isErasedValueType(targ.tpe)) {
+ val noNullCheckNeeded = targ.tpe match {
+ case ErasedValueType(tref) =>
+ atPhase(currentRun.erasurePhase) {
+ isPrimitiveValueClass(erasedValueClassArg(tref).typeSymbol)
+ }
+ case _ =>
+ true
+ }
+ if (noNullCheckNeeded) unbox(qual1, targ.tpe)
+ else {
+ def nullConst = Literal(Constant(null)) setType NullClass.tpe
+ val untyped =
+// util.trace("new asinstanceof test") {
+ gen.evalOnce(qual1, context.owner, context.unit) { qual =>
+ If(Apply(Select(qual(), nme.eq), List(Literal(Constant(null)) setType NullClass.tpe)),
+ Literal(Constant(null)) setType targ.tpe,
+ unbox(qual(), targ.tpe))
+ }
+// }
+ typed(untyped)
+ }
+ } else tree
case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List())
if tree.symbol == Any_isInstanceOf =>
targ.tpe match {
- case ErasedValueType(clazz) => targ.setType(clazz.tpe)
+ case ErasedValueType(tref) => targ.setType(tref.sym.tpe)
case _ =>
}
tree
@@ -711,17 +734,22 @@ abstract class Erasure extends AddInterfaces
val tree1 = try {
tree match {
case InjectDerivedValue(arg) =>
- val clazz = tree.symbol
- val result = typed1(arg, mode, underlyingOfValueClass(clazz)) setType ErasedValueType(clazz)
- log("transforming inject "+arg+":"+underlyingOfValueClass(clazz)+"/"+ErasedValueType(clazz)+" = "+result)
- return result
+ (tree.attachments.get[TypeRefAttachment]: @unchecked) match {
+ case Some(itype) =>
+ val tref = itype.tpe
+ val argPt = atPhase(currentRun.erasurePhase)(erasedValueClassArg(tref))
+ log(s"transforming inject $arg -> $tref/$argPt")
+ val result = typed(arg, mode, argPt)
+ log(s"transformed inject $arg -> $tref/$argPt = $result:${result.tpe}")
+ return result setType ErasedValueType(tref)
+ }
case _ =>
- super.typed1(adaptMember(tree), mode, pt)
+ super.typed1(adaptMember(tree), mode, pt)
}
} catch {
case er: TypeError =>
- Console.println("exception when typing " + tree)
+ Console.println("exception when typing " + tree+"/"+tree.getClass)
Console.println(er.msg + " in file " + context.owner.sourceFile)
er.printStackTrace
abort("unrecoverable error")
@@ -731,6 +759,7 @@ abstract class Erasure extends AddInterfaces
finally throw ex
throw ex
}
+
def adaptCase(cdef: CaseDef): CaseDef = {
val newCdef = deriveCaseDef(cdef)(adaptToType(_, tree1.tpe))
newCdef setType newCdef.body.tpe
@@ -970,8 +999,11 @@ abstract class Erasure extends AddInterfaces
else
tree
+
case Apply(Select(New(tpt), nme.CONSTRUCTOR), List(arg)) if (tpt.tpe.typeSymbol.isDerivedValueClass) =>
- InjectDerivedValue(arg) setSymbol tpt.tpe.typeSymbol
+// println("inject derived: "+arg+" "+tpt.tpe)
+ InjectDerivedValue(arg) addAttachment //@@@ setSymbol tpt.tpe.typeSymbol
+ new TypeRefAttachment(tree.tpe.asInstanceOf[TypeRef])
case Apply(fn, args) =>
def qualifier = fn match {
case Select(qual, _) => qual
@@ -1125,4 +1157,6 @@ abstract class Erasure extends AddInterfaces
}
}
}
+
+ private class TypeRefAttachment(val tpe: TypeRef)
}
diff --git a/src/compiler/scala/tools/nsc/transform/PostErasure.scala b/src/compiler/scala/tools/nsc/transform/PostErasure.scala
index ef158a71f6..999d00520d 100644
--- a/src/compiler/scala/tools/nsc/transform/PostErasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/PostErasure.scala
@@ -21,7 +21,8 @@ trait PostErasure extends InfoTransform with TypingTransformers {
object elimErasedValueType extends TypeMap {
def apply(tp: Type) = tp match {
- case ErasedValueType(clazz) => erasure.underlyingOfValueClass(clazz)
+ case ErasedValueType(tref) =>
+ atPhase(currentRun.erasurePhase)(erasure.erasedValueClassArg(tref))
case _ => mapOver(tp)
}
}
@@ -38,7 +39,7 @@ trait PostErasure extends InfoTransform with TypingTransformers {
acc), List())
if atPhase(currentRun.erasurePhase) {
tpt.tpe.typeSymbol.isDerivedValueClass &&
- sel.symbol == tpt.tpe.typeSymbol.firstParamAccessor
+ sel.symbol == tpt.tpe.typeSymbol.derivedValueClassUnbox
} =>
if (settings.debug.value) log("Removing "+tree+" -> "+arg)
arg
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index f01e095856..5465a3b47f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -196,14 +196,14 @@ trait SyntheticMethods extends ast.TreeDSL {
* (this.underlying == that.underlying
*/
def equalsDerivedValueClassMethod: Tree = createMethod(nme.equals_, List(AnyClass.tpe), BooleanClass.tpe) { m =>
- equalsCore(m, List(clazz.firstParamAccessor))
+ equalsCore(m, List(clazz.derivedValueClassUnbox))
}
/** The hashcode method for value classes
* def hashCode(): Int = this.underlying.hashCode
*/
def hashCodeDerivedValueClassMethod: Tree = createMethod(nme.hashCode_, Nil, IntClass.tpe) { m =>
- Select(mkThisSelect(clazz.firstParamAccessor), nme.hashCode_)
+ Select(mkThisSelect(clazz.derivedValueClassUnbox), nme.hashCode_)
}
/** The _1, _2, etc. methods to implement ProductN.
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 77c27126c5..94be7848bf 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -2239,10 +2239,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
base.info.decl(sname) filter (_.hasAccessorFlag)
}
- /** Return the accessor method of the first parameter of this class.
+ /** If this is a derived value class, return its unbox method
* or NoSymbol if it does not exist.
*/
- def firstParamAccessor: Symbol = NoSymbol
+ def derivedValueClassUnbox: Symbol = NoSymbol
/** The case module corresponding to this case class
* @pre case class is a member of some other class or package
@@ -3146,8 +3146,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
clone
}
- override def firstParamAccessor =
- info.decls.find(_ hasAllFlags PARAMACCESSOR | METHOD) getOrElse NoSymbol
+ override def derivedValueClassUnbox =
+ (info.decl(nme.unbox)) orElse
+ (info.decls.find(_ hasAllFlags PARAMACCESSOR | METHOD) getOrElse
+ NoSymbol)
private[this] var childSet: Set[Symbol] = Set()
override def children = childSet
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 56cc265e48..0b3e125053 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -66,7 +66,7 @@ import util.Statistics
// inst is the instantiation and constr is a list of bounds.
case DeBruijnIndex(level, index)
// for dependent method types: a type referring to a method parameter.
- case ErasedValueType(tp)
+ case ErasedValueType(clazz, underlying)
// only used during erasure of derived value classes.
*/
@@ -3305,16 +3305,21 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
- abstract case class ErasedValueType(sym: Symbol) extends Type {
- override def safeToString = sym.name+"$unboxed"
+ /** A temporary type representing the reasure of a user-defined value type.
+ * Created during phase reasure, elimintaed again in posterasure.
+ * @param sym The value class symbol
+ * @param underlying The underlying type before erasure
+ */
+ abstract case class ErasedValueType(original: TypeRef) extends Type {
+ override def safeToString = "ErasedValueType("+original+")"
}
- final class UniqueErasedValueType(sym: Symbol) extends ErasedValueType(sym) with UniqueType
+ final class UniqueErasedValueType(original: TypeRef) extends ErasedValueType(original) with UniqueType
object ErasedValueType {
- def apply(sym: Symbol): Type = {
- assert(sym ne NoSymbol, "ErasedValueType cannot be NoSymbol")
- unique(new UniqueErasedValueType(sym))
+ def apply(original: TypeRef): Type = {
+ assert(original.sym ne NoSymbol, "ErasedValueType over NoSymbol")
+ unique(new UniqueErasedValueType(original))
}
}
diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala
index 5beec70d62..368d55a59c 100644
--- a/src/reflect/scala/reflect/internal/transform/Erasure.scala
+++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala
@@ -2,7 +2,7 @@ package scala.reflect
package internal
package transform
-import Flags.PARAMACCESSOR
+import Flags.{PARAMACCESSOR, METHOD}
trait Erasure {
@@ -72,8 +72,37 @@ trait Erasure {
if (cls.owner.isClass) cls.owner.tpe else pre // why not cls.isNestedClass?
}
+ def unboxDerivedValueClassMethod(clazz: Symbol): Symbol =
+ (clazz.info.decl(nme.unbox)) orElse
+ (clazz.info.decls.find(_ hasAllFlags PARAMACCESSOR | METHOD) getOrElse
+ NoSymbol)
+
def underlyingOfValueClass(clazz: Symbol): Type =
- clazz.firstParamAccessor.tpe.resultType
+ clazz.derivedValueClassUnbox.tpe.resultType
+
+ /** The type of the argument of a value class reference after erasure
+ * This method needs to be called at a phase no later than erasurephase
+ */
+ def erasedValueClassArg(tref: TypeRef): Type = {
+ assert(!phase.erasedTypes)
+ val clazz = tref.sym
+ if (valueClassIsParametric(clazz)) {
+ val underlying = tref.memberType(clazz.derivedValueClassUnbox).resultType
+ boxingErasure(underlying)
+ } else {
+ scalaErasure(underlyingOfValueClass(clazz))
+ }
+ }
+
+ /** Does this vakue class have an underlying type that's a type parameter of
+ * the class itself?
+ * This method needs to be called at a phase no later than erasurephase
+ */
+ def valueClassIsParametric(clazz: Symbol): Boolean = {
+ assert(!phase.erasedTypes)
+ clazz.typeParams contains
+ clazz.derivedValueClassUnbox.tpe.resultType.normalize.typeSymbol
+ }
abstract class ErasureMap extends TypeMap {
private lazy val ObjectArray = arrayType(ObjectClass.tpe)
@@ -84,15 +113,14 @@ trait Erasure {
def eraseNormalClassRef(pre: Type, clazz: Symbol): Type =
typeRef(apply(rebindInnerClass(pre, clazz)), clazz, List()) // #2585
- protected def eraseDerivedValueClassRef(clazz: Symbol): Type =
- scalaErasure(underlyingOfValueClass(clazz))
+ protected def eraseDerivedValueClassRef(tref: TypeRef): Type = erasedValueClassArg(tref)
def apply(tp: Type): Type = tp match {
case ConstantType(_) =>
tp
case st: SubType =>
apply(st.supertype)
- case TypeRef(pre, sym, args) =>
+ case tref @ TypeRef(pre, sym, args) =>
if (sym == ArrayClass)
if (unboundedGenericArrayLevel(tp) == 1) ObjectClass.tpe
else if (args.head.typeSymbol.isBottomClass) ObjectArray
@@ -100,7 +128,7 @@ trait Erasure {
else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass || sym == NotNullClass) ErasedObject
else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass)
else if (sym.isRefinementClass) apply(mergeParents(tp.parents))
- else if (sym.isDerivedValueClass) eraseDerivedValueClassRef(sym)
+ else if (sym.isDerivedValueClass) eraseDerivedValueClassRef(tref)
else if (sym.isClass) eraseNormalClassRef(pre, sym)
else apply(sym.info) // alias type or abstract type
case PolyType(tparams, restpe) =>
@@ -236,7 +264,8 @@ trait Erasure {
* are then later converted to the underlying parameter type in phase posterasure.
*/
object specialScalaErasure extends ScalaErasureMap {
- override def eraseDerivedValueClassRef(clazz: Symbol): Type = ErasedValueType(clazz)
+ override def eraseDerivedValueClassRef(tref: TypeRef): Type =
+ ErasedValueType(tref)
}
object javaErasure extends JavaErasureMap
@@ -251,6 +280,14 @@ trait Erasure {
}
}
+ object boxingErasure extends ScalaErasureMap {
+ override def eraseNormalClassRef(pre: Type, clazz: Symbol) =
+ if (isPrimitiveValueClass(clazz)) boxedClass(clazz).tpe
+ else super.eraseNormalClassRef(pre, clazz)
+ override def eraseDerivedValueClassRef(tref: TypeRef) =
+ super.eraseNormalClassRef(tref.pre, tref.sym)
+ }
+
/** The intersection dominator (SLS 3.7) of a list of types is computed as follows.
*
* - If the list contains one or more occurrences of scala.Array with