summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2012-02-22 09:59:08 +0100
committerMartin Odersky <odersky@gmail.com>2012-02-22 09:59:08 +0100
commit93a326e160ea9ba822467377f87d798146925367 (patch)
treece5ef619271814c227c239127ffe9fd78e82e632 /src
parentab8cbeb6fc3966564de720e99bed3eec39c854df (diff)
downloadscala-93a326e160ea9ba822467377f87d798146925367.tar.gz
scala-93a326e160ea9ba822467377f87d798146925367.tar.bz2
scala-93a326e160ea9ba822467377f87d798146925367.zip
Changed erasure boxing/unboxing scheme to support value classes that wrap reference classes.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala20
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala48
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala5
3 files changed, 53 insertions, 20 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index 83b6252b26..733c5a6fb1 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -40,6 +40,12 @@ trait Trees extends reflect.internal.Trees { self: Global =>
case class SelectFromArray(qualifier: Tree, name: Name, erasure: Type)
extends TermTree with RefTree
+ /** Derived value class injection (equivalent to: new C(arg) after easure); only used during erasure
+ * The class C is stored as the symbol of the tree node.
+ */
+ case class InjectDerivedValue(arg: Tree)
+ extends SymTree
+
/** emitted by typer, eliminated by refchecks */
case class TypeTreeWithDeferredRefCheck()(val check: () => TypeTree) extends TypTree
@@ -159,6 +165,8 @@ trait Trees extends reflect.internal.Trees { self: Global =>
traverser.traverse(lhs); traverser.traverse(rhs)
case SelectFromArray(qualifier, selector, erasure) =>
traverser.traverse(qualifier)
+ case InjectDerivedValue(arg) =>
+ traverser.traverse(arg)
case ReferenceToBoxed(idt) =>
traverser.traverse(idt)
case TypeTreeWithDeferredRefCheck() =>
@@ -170,6 +178,7 @@ trait Trees extends reflect.internal.Trees { self: Global =>
def DocDef(tree: Tree, comment: DocComment, definition: Tree): DocDef
def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree): AssignOrNamedArg
def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type): SelectFromArray
+ def InjectDerivedValue(tree: Tree, arg: Tree): InjectDerivedValue
def ReferenceToBoxed(tree: Tree, idt: Ident): ReferenceToBoxed
def TypeTreeWithDeferredRefCheck(tree: Tree): TypeTreeWithDeferredRefCheck
}
@@ -184,6 +193,8 @@ trait Trees extends reflect.internal.Trees { self: Global =>
new AssignOrNamedArg(lhs, rhs).copyAttrs(tree)
def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type) =
new SelectFromArray(qualifier, selector, erasure).copyAttrs(tree)
+ def InjectDerivedValue(tree: Tree, arg: Tree) =
+ new InjectDerivedValue(arg)
def ReferenceToBoxed(tree: Tree, idt: Ident) =
new ReferenceToBoxed(idt).copyAttrs(tree)
def TypeTreeWithDeferredRefCheck(tree: Tree) = tree match {
@@ -207,6 +218,11 @@ trait Trees extends reflect.internal.Trees { self: Global =>
if (qualifier0 == qualifier) && (selector0 == selector) => t
case _ => this.treeCopy.SelectFromArray(tree, qualifier, selector, erasure)
}
+ def InjectDerivedValue(tree: Tree, arg: Tree) = tree match {
+ case t @ InjectDerivedValue(arg0)
+ if (arg0 == arg) => t
+ case _ => this.treeCopy.InjectDerivedValue(tree, arg)
+ }
def ReferenceToBoxed(tree: Tree, idt: Ident) = tree match {
case t @ ReferenceToBoxed(idt0)
if (idt0 == idt) => t
@@ -237,6 +253,9 @@ trait Trees extends reflect.internal.Trees { self: Global =>
case SelectFromArray(qualifier, selector, erasure) =>
transformer.treeCopy.SelectFromArray(
tree, transformer.transform(qualifier), selector, erasure)
+ case InjectDerivedValue(arg) =>
+ transformer.treeCopy.InjectDerivedValue(
+ tree, transformer.transform(arg))
case ReferenceToBoxed(idt) =>
transformer.treeCopy.ReferenceToBoxed(
tree, transformer.transform(idt) match { case idt1: Ident => idt1 })
@@ -336,6 +355,7 @@ trait Trees extends reflect.internal.Trees { self: Global =>
case AssignOrNamedArg(lhs, rhs) => (eliminated by typer)
case TypeTreeWithDeferredRefCheck() => (created and eliminated by typer)
case SelectFromArray(_, _, _) => (created and eliminated by erasure)
+ case InjectDerivedValue(_) => (created and eliminated by erasure)
*/
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 65b4890c8f..e0086dd81b 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -410,12 +410,14 @@ abstract class Erasure extends AddInterfaces
/** The modifier typer which retypes with erased types. */
class Eraser(_context: Context) extends Typer(_context) {
- private def isUnboxedType(tpe: Type) = tpe match {
- case ErasedValueType(_) => true
- case _ => isPrimitiveValueClass(tpe.typeSymbol)
- }
+ private def isPrimitiveValueType(tpe: Type) = isPrimitiveValueClass(tpe.typeSymbol)
+
+ private def isErasedValueType(tpe: Type) = tpe.isInstanceOf[ErasedValueType]
- private def isUnboxedValueMember(sym: Symbol) =
+ private def isDifferentErasedValueType(tpe: Type, other: Type) =
+ isErasedValueType(tpe) && (tpe ne other)
+
+ private def isPrimitiveValueMember(sym: Symbol) =
sym != NoSymbol && isPrimitiveValueClass(sym.owner)
private def box(tree: Tree, target: => String): Tree = {
@@ -534,14 +536,18 @@ abstract class Erasure extends AddInterfaces
log("adapting " + tree + ":" + tree.tpe + " : " + tree.tpe.parents + " to " + pt)//debug
if (tree.tpe <:< pt)
tree
- else if (isUnboxedType(tree.tpe) && !isUnboxedType(pt)) {
+ else if (isDifferentErasedValueType(tree.tpe, pt))
+ adaptToType(box(tree, pt.toString), pt)
+ else if (isDifferentErasedValueType(pt, tree.tpe))
+ adaptToType(unbox(tree, pt), pt)
+ else if (isPrimitiveValueType(tree.tpe) && !isPrimitiveValueType(pt)) {
adaptToType(box(tree, pt.toString), pt)
} else if (tree.tpe.isInstanceOf[MethodType] && tree.tpe.params.isEmpty) {
assert(tree.symbol.isStable, "adapt "+tree+":"+tree.tpe+" to "+pt)
adaptToType(Apply(tree, List()) setPos tree.pos setType tree.tpe.resultType, pt)
- } else if (pt <:< tree.tpe)
- cast(tree, pt)
- else if (isUnboxedType(pt) && !isUnboxedType(tree.tpe))
+// } else if (pt <:< tree.tpe)
+// cast(tree, pt)
+ } else if (isPrimitiveValueType(pt) && !isPrimitiveValueType(tree.tpe))
adaptToType(unbox(tree, pt), pt)
else
cast(tree, pt)
@@ -564,7 +570,7 @@ abstract class Erasure extends AddInterfaces
//Console.println("adaptMember: " + tree);
tree match {
case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List())
- if tree.symbol == Any_asInstanceOf || tree.symbol == Object_asInstanceOf =>
+ if tree.symbol == Any_asInstanceOf =>
val qual1 = typedQualifier(qual, NOmode, ObjectClass.tpe) // need to have an expected type, see #3037
val qualClass = qual1.tpe.typeSymbol
/*
@@ -575,10 +581,10 @@ abstract class Erasure extends AddInterfaces
atPos(tree.pos)(Apply(Select(qual1, "to" + targClass.name), List()))
else
*/
- if (isUnboxedType(targ.tpe)) unbox(qual1, targ.tpe)
+ if (isPrimitiveValueType(targ.tpe) || isErasedValueType(targ.tpe)) unbox(qual1, targ.tpe)
else tree
case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List())
- if tree.symbol == Any_isInstanceOf || tree.symbol == Object_asInstanceOf =>
+ if tree.symbol == Any_isInstanceOf =>
targ.tpe match {
case ErasedValueType(clazz) => targ.setType(clazz.tpe)
case _ =>
@@ -598,12 +604,13 @@ abstract class Erasure extends AddInterfaces
adaptMember(atPos(tree.pos)(Select(qual, getMember(ObjectClass, name))))
else {
var qual1 = typedQualifier(qual)
- if ((isUnboxedType(qual1.tpe) && !isUnboxedValueMember(tree.symbol)))
+ if ((isPrimitiveValueType(qual1.tpe) && !isPrimitiveValueMember(tree.symbol)) ||
+ isErasedValueType(qual1.tpe))
qual1 = box(qual1, "owner "+tree.symbol.owner)
- else if (!isUnboxedType(qual1.tpe) && isUnboxedValueMember(tree.symbol))
+ else if (!isPrimitiveValueType(qual1.tpe) && isPrimitiveValueMember(tree.symbol))
qual1 = unbox(qual1, tree.symbol.owner.tpe)
- if (isUnboxedValueMember(tree.symbol) && !isUnboxedType(qual1.tpe))
+ if (isPrimitiveValueMember(tree.symbol) && !isPrimitiveValueType(qual1.tpe))
tree.symbol = NoSymbol
else if (qual1.tpe.isInstanceOf[MethodType] && qual1.tpe.params.isEmpty) {
assert(qual1.symbol.isStable, qual1.symbol);
@@ -632,7 +639,14 @@ abstract class Erasure extends AddInterfaces
*/
override protected def typed1(tree: Tree, mode: Int, pt: Type): Tree = {
val tree1 = try {
- super.typed1(adaptMember(tree), mode, pt)
+ tree match {
+ case InjectDerivedValue(arg) =>
+ val clazz = tree.symbol
+ util.trace("transforming inject "+arg+":"+underlyingOfValueClass(clazz)+"/"+ErasedValueType(clazz))(
+ typed1(arg, mode, underlyingOfValueClass(clazz)) setType ErasedValueType(clazz))
+ case _ =>
+ super.typed1(adaptMember(tree), mode, pt)
+ }
} catch {
case er: TypeError =>
Console.println("exception when typing " + tree)
@@ -968,7 +982,7 @@ abstract class Erasure extends AddInterfaces
tree
case Apply(Select(New(tpt), nme.CONSTRUCTOR), List(arg)) if (tpt.tpe.typeSymbol.isDerivedValueClass) =>
- arg
+ InjectDerivedValue(arg) setSymbol tpt.tpe.typeSymbol
case Apply(fn, args) =>
def qualifier = fn match {
case Select(qual, _) => qual
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 02b7dae544..2b9880ff65 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1209,12 +1209,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
unit.error(acc.pos, "Type of parameter of value class may not be a type variable")
for (stat <- body)
if (!treeInfo.isAllowedInUniversalTrait(stat) && !isUnderlyingAcc(stat.symbol))
- unit.error(stat.pos,
+ unit.error(stat.pos,
if (stat.symbol hasFlag PARAMACCESSOR) "Illegal parameter for value class"
else "This statement is not allowed in value class: "+stat)
case x =>
- println(clazz.info.decls.toList)
- unit.error(clazz.pos, "Value class needs to have exactly one public val parameter, found: "+x.mkString(", "))
+ unit.error(clazz.pos, "Value class needs to have exactly one public val parameter")
}
for (tparam <- clazz.typeParams)
if (tparam hasAnnotation definitions.SpecializedClass)