summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2012-02-13 00:02:39 +0100
committerMartin Odersky <odersky@gmail.com>2012-02-13 00:02:39 +0100
commit52c99f57ef41c436719818b8e3860e3bfbf023e2 (patch)
treec5146f24872b6bc70b65f2d64170d09450673ec5 /src/compiler
parent7bcb1f2fc98eb870fcd52d3b01b3381e5ce0f8d1 (diff)
downloadscala-52c99f57ef41c436719818b8e3860e3bfbf023e2.tar.gz
scala-52c99f57ef41c436719818b8e3860e3bfbf023e2.tar.bz2
scala-52c99f57ef41c436719818b8e3860e3bfbf023e2.zip
All steps of value class proposal implemented. Most restrictions are now enforced. Super calls and specialized still missing.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/reflect/internal/Symbols.scala87
-rw-r--r--src/compiler/scala/reflect/internal/transform/Erasure.scala25
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala24
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeInfo.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala113
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala108
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala32
8 files changed, 258 insertions, 140 deletions
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala
index e448ef86f6..89af10283b 100644
--- a/src/compiler/scala/reflect/internal/Symbols.scala
+++ b/src/compiler/scala/reflect/internal/Symbols.scala
@@ -17,7 +17,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
import definitions._
protected var ids = 0
-
+
val emptySymbolArray = new Array[Symbol](0)
def symbolCount = ids // statistics
@@ -38,14 +38,14 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
nextexid += 1
newTypeName("_" + nextexid + suffix)
}
-
+
// Set the fields which point companions at one another. Returns the module.
def connectModuleToClass(m: ModuleSymbol, moduleClass: ClassSymbol): ModuleSymbol = {
moduleClass.sourceModule = m
m setModuleClass moduleClass
m
}
-
+
/** Create a new free variable. Its owner is NoSymbol.
*/
def newFreeVar(name: TermName, tpe: Type, value: Any, newFlags: Long = 0L): FreeVar =
@@ -67,7 +67,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def selfType: Type = typeOfThis
def typeSignature: Type = info
def typeSignatureIn(site: Type): Type = site memberInfo this
-
+
def asType: Type = tpe
def asTypeIn(site: Type): Type = site.memberType(this)
def asTypeConstructor: Type = typeConstructor
@@ -89,19 +89,19 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
private[this] var _rawowner = initOwner // Syncnote: need not be protected, as only assignment happens in owner_=, which is not exposed to api
private[this] var _rawname = initName
private[this] var _rawflags = 0L
-
+
def rawowner = _rawowner
def rawname = _rawname
def rawflags = _rawflags
-
+
protected def rawflags_=(x: FlagsType) { _rawflags = x }
-
+
private var rawpos = initPos
-
+
val id = nextId() // identity displayed when -uniqid
private[this] var _validTo: Period = NoPeriod
-
+
def validTo = _validTo
def validTo_=(x: Period) { _validTo = x}
@@ -179,10 +179,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
def newTermSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol =
new TermSymbol(this, pos, name) initFlags newFlags
-
+
def newAbstractTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AbstractTypeSymbol =
new AbstractTypeSymbol(this, pos, name) initFlags newFlags
-
+
def newAliasTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AliasTypeSymbol =
new AliasTypeSymbol(this, pos, name) initFlags newFlags
@@ -194,10 +194,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def newClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ClassSymbol =
new ClassSymbol(this, pos, name) initFlags newFlags
-
+
def newModuleClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleClassSymbol =
new ModuleClassSymbol(this, pos, name) initFlags newFlags
-
+
/** Derive whether it is an abstract type from the flags; after creation
* the DEFERRED flag will be ignored.
*/
@@ -206,7 +206,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
newAliasTypeSymbol(name, pos, newFlags)
else
newAbstractTypeSymbol(name, pos, newFlags)
-
+
def newTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position = NoPosition, newFlags: Long = 0L): TypeSkolem =
if ((newFlags & DEFERRED) == 0L)
new TypeSkolem(this, pos, name, origin) initFlags newFlags
@@ -243,7 +243,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
final def newAliasType(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol =
newAliasTypeSymbol(name, pos, newFlags)
-
+
/** Symbol of an abstract type type T >: ... <: ...
*/
final def newAbstractType(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol =
@@ -261,7 +261,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def freshName() = { cnt += 1; nme.syntheticParamName(cnt) }
mmap(argtypess)(tp => newValueParameter(freshName(), focusPos(owner.pos), SYNTHETIC) setInfo tp)
}
-
+
def newSyntheticTypeParam(): Symbol = newSyntheticTypeParam("T0", 0L)
def newSyntheticTypeParam(name: String, newFlags: Long): Symbol = newTypeParameter(newTypeName(name), NoPosition, newFlags) setInfo TypeBounds.empty
def newSyntheticTypeParams(num: Int): List[Symbol] = (0 until num).toList map (n => newSyntheticTypeParam("T" + n, 0L))
@@ -302,7 +302,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def newClass(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L) =
newClassSymbol(name, pos, newFlags)
-
+
/** A new class with its info set to a ClassInfoType with given scope and parents. */
def newClassWithInfo(name: TypeName, parents: List[Type], scope: Scope, pos: Position = NoPosition, newFlags: Long = 0L) = {
val clazz = newClass(name, pos, newFlags)
@@ -354,9 +354,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def newAliasType(pos: Position, name: TypeName): Symbol = newAliasType(name, pos)
@deprecated("Use the other signature", "2.10.0")
def newAbstractType(pos: Position, name: TypeName): Symbol = newAbstractType(name, pos)
- @deprecated("Use the other signature", "2.10.0")
+ @deprecated("Use the other signature", "2.10.0")
def newExistential(pos: Position, name: TypeName): Symbol = newExistential(name, pos)
- @deprecated("Use the other signature", "2.10.0")
+ @deprecated("Use the other signature", "2.10.0")
def newMethod(pos: Position, name: TermName): MethodSymbol = newMethod(name, pos)
// ----- locking and unlocking ------------------------------------------------------
@@ -499,11 +499,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// class C extends D( { class E { ... } ... } ). Here, E is a class local to a constructor
final def isClassLocalToConstructor = isClass && hasFlag(INCONSTRUCTOR)
- final def isInlineClass =
+ final def isInlineClass =
isClass && info.parents.headOption.getOrElse(AnyClass.tpe).typeSymbol == AnyValClass &&
!isPrimitiveValueClass
-
- final def isMethodWithExtension =
+
+ final def isMethodWithExtension =
isMethod && owner.isInlineClass && !isParamAccessor && !isConstructor
final def isAnonymousClass = isClass && (name containsName tpnme.ANON_CLASS_NAME)
@@ -845,7 +845,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
private def addModuleSuffix(n: Name): Name =
if (needsModuleSuffix) n append nme.MODULE_SUFFIX_STRING else n
-
+
def moduleSuffix: String = (
if (needsModuleSuffix) nme.MODULE_SUFFIX_STRING
else ""
@@ -853,7 +853,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** Whether this symbol needs nme.MODULE_SUFFIX_STRING (aka $) appended on the java platform.
*/
def needsModuleSuffix = (
- hasModuleFlag
+ hasModuleFlag
&& !isMethod
&& !isImplClass
&& !isJavaDefined
@@ -880,7 +880,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
else if (owner.isEffectiveRoot) name
else effectiveOwner.enclClass.fullNameAsName(separator) append separator append name
)
-
+
def fullNameAsName(separator: Char): Name = nme.dropLocalSuffix(fullNameInternal(separator))
/** The encoded full path name of this symbol, where outer names and inner names
@@ -1032,7 +1032,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** Substitute second list of symbols for first in current info. */
def substInfo(syms0: List[Symbol], syms1: List[Symbol]) = modifyInfo(_.substSym(syms0, syms1))
def setInfoOwnerAdjusted(info: Type): this.type = setInfo(info atOwner this)
-
+
/** Set the info and enter this symbol into the owner's scope. */
def setInfoAndEnter(info: Type): this.type = {
setInfo(info)
@@ -1341,7 +1341,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
final def isNestedIn(that: Symbol): Boolean =
owner == that || owner != NoSymbol && (owner isNestedIn that)
-
+
/** Is this class symbol a subclass of that symbol,
* and is this class symbol also different from Null or Nothing? */
def isNonBottomSubClass(that: Symbol): Boolean = false
@@ -1818,7 +1818,12 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
base.info.decl(sname) filter (_.hasAccessorFlag)
}
- /** The case module corresponding to this case class
+ /** Return the accessor method of the first parameter of this class.
+ * or NoSymbol if it does not exist.
+ */
+ def firstParamAccessor: Symbol = NoSymbol
+
+ /** The case module corresponding to this case class
* @pre case class is a member of some other class or package
*/
final def caseModule: Symbol = {
@@ -1859,7 +1864,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** Remove any access boundary and clear flags PROTECTED | PRIVATE.
*/
def makePublic = this setPrivateWithin NoSymbol resetFlag AccessFlags
-
+
/** The first parameter to the first argument list of this method,
* or NoSymbol if inapplicable.
*/
@@ -2141,7 +2146,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def referenced: Symbol = _referenced
def referenced_=(x: Symbol) { _referenced = x }
-
+
def existentialBound = singletonBounds(this.tpe)
def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol =
@@ -2235,7 +2240,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
if (!isMethod && needsFlatClasses) {
if (flatname eq null)
flatname = nme.flattenedName(rawowner.name, rawname)
-
+
flatname
}
else rawname.toTermName
@@ -2271,7 +2276,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
res
}
}
-
+
class AliasTypeSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName)
extends TypeSymbol(initOwner, initPos, initName) {
// Temporary programmatic help tracking down who might do such a thing
@@ -2286,13 +2291,13 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def cloneSymbolImpl(owner: Symbol, newFlags: Long): AliasTypeSymbol =
owner.newAliasTypeSymbol(name, pos, newFlags)
}
-
+
class AbstractTypeSymbol(initOwner: Symbol, initPos: Position, initName: TypeName)
extends TypeSymbol(initOwner, initPos, initName) with AbstractTypeMixin {
override def cloneSymbolImpl(owner: Symbol, newFlags: Long): AbstractTypeSymbol =
owner.newAbstractTypeSymbol(name, pos, newFlags)
}
-
+
/** Might be mixed into TypeSymbol or TypeSkolem.
*/
trait AbstractTypeMixin extends TypeSymbol {
@@ -2490,7 +2495,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final override def isNonClassType = false
final override def isAbstractType = false
final override def isAliasType = false
-
+
override def existentialBound = GenPolyType(this.typeParams, TypeBounds.upper(this.classBound))
override def sourceFile =
@@ -2518,19 +2523,19 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
thisTypeCache
}
-
+
override def owner: Symbol =
if (needsFlatClasses) rawowner.owner else rawowner
override def name: TypeName = (
if (needsFlatClasses) {
if (flatname eq null)
flatname = nme.flattenedName(rawowner.name, rawname).toTypeName
-
+
flatname
}
else rawname.toTypeName
)
-
+
/** A symbol carrying the self type of the class as its type */
override def thisSym: Symbol = thissym
@@ -2566,6 +2571,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def sourceModule =
if (isModuleClass) companionModule else NoSymbol
+ override def firstParamAccessor =
+ info.decls.find(m => (m hasFlag PARAMACCESSOR) && m.isMethod) getOrElse NoSymbol
+
+
private[this] var childSet: Set[Symbol] = Set()
override def children = childSet
override def addChild(sym: Symbol) { childSet = childSet + sym }
@@ -2713,7 +2722,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
val syms1 = cloneSymbolsAtOwner(syms, owner)
creator(syms1, tpe.substSym(syms, syms1))
}
-
+
/** A deep map on a symbol's paramss.
*/
def mapParamss[T](sym: Symbol)(f: Symbol => T): List[List[T]] = mmap(sym.info.paramss)(f)
diff --git a/src/compiler/scala/reflect/internal/transform/Erasure.scala b/src/compiler/scala/reflect/internal/transform/Erasure.scala
index f0981d7141..f8dfd66fbe 100644
--- a/src/compiler/scala/reflect/internal/transform/Erasure.scala
+++ b/src/compiler/scala/reflect/internal/transform/Erasure.scala
@@ -65,19 +65,16 @@ trait Erasure {
if (cls.owner.isClass) cls.owner.tpe else pre // why not cls.isNestedClass?
}
- protected def valueClassErasure(clazz: Symbol): Type =
+ def valueClassErasure(clazz: Symbol): Type =
clazz.primaryConstructor.info.params.head.tpe
-
+
protected def eraseInlineClassRef(clazz: Symbol): Type =
scalaErasure(valueClassErasure(clazz))
-
- protected def underlyingParamAccessor(clazz: Symbol) =
- clazz.info.decls.find(_ hasFlag PARAMACCESSOR).get
-
+
abstract class ErasureMap extends TypeMap {
def mergeParents(parents: List[Type]): Type
- def eraseNormalClassRef(pre: Type, clazz: Symbol): Type =
+ def eraseNormalClassRef(pre: Type, clazz: Symbol): Type =
typeRef(apply(rebindInnerClass(pre, clazz)), clazz, List()) // #2585
def apply(tp: Type): Type = {
@@ -95,7 +92,7 @@ trait Erasure {
else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass)
else if (sym.isRefinementClass) apply(mergeParents(tp.parents))
else if (sym.isInlineClass) eraseInlineClassRef(sym)
- else if (sym.isClass) eraseNormalClassRef(pre, sym)
+ else if (sym.isClass) eraseNormalClassRef(pre, sym)
else apply(sym.info) // alias type or abstract type
case PolyType(tparams, restpe) =>
apply(restpe)
@@ -162,13 +159,11 @@ trait Erasure {
log("Identified divergence between java/scala erasure:\n scala: " + old + "\n java: " + res)
}
res
- } else if (sym.isMethodWithExtension || sym.isConstructor && sym.owner.isInlineClass)
+ } else if (sym.isTerm && sym.owner.isInlineClass)
scalaErasureAvoiding(sym.owner, tp)
- else if (sym.isValue && sym.owner.isMethodWithExtension)
- scala.tools.nsc.util.trace("avoid unboxed: "+sym+"/"+sym.owner.owner+"/"+tp) {
- scalaErasureAvoiding(sym.owner.owner, tp)
- }
- else
+ else if (sym.isValue && sym.owner.isMethodWithExtension)
+ scalaErasureAvoiding(sym.owner.owner, tp)
+ else
scalaErasure(tp)
}
@@ -191,7 +186,7 @@ trait Erasure {
def mergeParents(parents: List[Type]): Type =
intersectionDominator(parents)
}
-
+
def scalaErasureAvoiding(clazz: Symbol, tpe: Type): Type = {
tpe match {
case PolyType(tparams, restpe) =>
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 281a2eb49b..3f6a0f8f73 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -154,7 +154,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
/** Register top level class (called on entering the class)
*/
def registerTopLevelSym(sym: Symbol) {}
-
+
// ------------------ Reporting -------------------------------------
// not deprecated yet, but a method called "error" imported into
@@ -500,6 +500,13 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
val runsRightAfter = Some("explicitouter")
} with Erasure
+ // phaseName = "posterasure"
+ object postErasure extends {
+ val global: Global.this.type = Global.this
+ val runsAfter = List("erasure")
+ val runsRightAfter = Some("erasure")
+ } with PostErasure
+
// phaseName = "lazyvals"
object lazyVals extends {
final val FLAGS_PER_WORD = 32
@@ -659,6 +666,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
specializeTypes -> "@specialized-driven class and method specialization",
explicitOuter -> "this refs to outer pointers, translate patterns",
erasure -> "erase types, add interfaces for traits",
+ postErasure -> "clean up erased inline classes",
lazyVals -> "allocate bitmaps, translate lazy vals into lazified defs",
lambdaLift -> "move nested functions to top level",
constructors -> "move field definitions into constructors",
@@ -703,18 +711,18 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
private lazy val unitTimings = mutable.HashMap[CompilationUnit, Long]() withDefaultValue 0L // tracking time spent per unit
private def unitTimingsFormatted(): String = {
def toMillis(nanos: Long) = "%.3f" format nanos / 1000000d
-
+
val formatter = new util.TableDef[(String, String)] {
>> ("ms" -> (_._1)) >+ " "
<< ("path" -> (_._2))
}
"" + (
- new formatter.Table(unitTimings.toList sortBy (-_._2) map {
+ new formatter.Table(unitTimings.toList sortBy (-_._2) map {
case (unit, nanos) => (toMillis(nanos), unit.source.path)
})
)
}
-
+
protected def addToPhasesSet(sub: SubComponent, descr: String) {
phasesSet += sub
phasesDescMap(sub) = descr
@@ -861,7 +869,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
/** Counts for certain classes of warnings during this run. */
var deprecationWarnings: List[(Position, String)] = Nil
var uncheckedWarnings: List[(Position, String)] = Nil
-
+
/** A flag whether macro expansions failed */
var macroExpansionFailed = false
@@ -1008,7 +1016,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
}
def cancel() { reporter.cancelled = true }
-
+
private def currentProgress = (phasec * size) + unitc
private def totalProgress = (phaseDescriptors.size - 1) * size // -1: drops terminal phase
private def refreshProgress() = if (size > 0) progress(currentProgress, totalProgress)
@@ -1175,12 +1183,12 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
*/
def compileUnits(units: List[CompilationUnit], fromPhase: Phase) {
try compileUnitsInternal(units, fromPhase)
- catch { case ex =>
+ catch { case ex =>
globalError(supplementErrorMessage("uncaught exception during compilation: " + ex.getClass.getName))
throw ex
}
}
-
+
private def compileUnitsInternal(units: List[CompilationUnit], fromPhase: Phase) {
units foreach addUnit
if (opt.profileAll) {
diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
index 81a6659b3c..9f361e5bcc 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
@@ -42,11 +42,11 @@ abstract class TreeInfo extends reflect.internal.TreeInfo {
case ClassDef(_, `name`, _, _) :: Nil => true
case _ => super.firstDefinesClassOrObject(trees, name)
}
-
- def isInterface(mods: HasFlags, body: List[Tree]) =
+
+ def isInterface(mods: HasFlags, body: List[Tree]) =
mods.hasTraitFlag && (body forall isInterfaceMember)
- def isAllowedInAnyTrait(stat: Tree): Boolean = stat match {
+ def isAllowedInUniversalTrait(stat: Tree): Boolean = stat match {
case _: ValDef => false
case Import(_, _) | EmptyTree => true
case _: DefTree => true
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index fa64fbf48b..debf2e4b97 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -336,7 +336,7 @@ abstract class Erasure extends AddInterfaces
class UnknownSig extends Exception
override def eraseInlineClassRef(clazz: Symbol): Type = ErasedInlineType(clazz)
-
+
/** The symbol's erased info. This is the type's erasure, except for the following symbols:
*
@@ -372,29 +372,47 @@ abstract class Erasure extends AddInterfaces
override def newTyper(context: Context) = new Eraser(context)
- /** An extractor object for boxed expressions
+ private def safeToRemoveUnbox(cls: Symbol): Boolean =
+ (cls == definitions.NullClass) || isBoxedValueClass(cls)
+
+ /** An extractor object for unboxed expressions (maybe subsumed by posterasure?) */
+ object Unboxed {
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ case Apply(fn, List(arg)) if isUnbox(fn.symbol) && safeToRemoveUnbox(arg.tpe.typeSymbol) =>
+ Some(arg)
+ case Apply(
+ TypeApply(
+ cast @ Select(
+ Apply(
+ sel @ Select(arg, acc),
+ List()),
+ asinstanceof),
+ List(tpt)),
+ List())
+ if cast.symbol == Object_asInstanceOf &&
+ tpt.tpe.typeSymbol.isInlineClass &&
+ sel.symbol == tpt.tpe.typeSymbol.firstParamAccessor =>
+ Some(arg)
+ case _ =>
+ None
+ }
+ }
+
+ /** An extractor object for boxed expressions (maybe subsumed by posterasure?) */
object Boxed {
def unapply(tree: Tree): Option[Tree] = tree match {
+ case Apply(Select(New(tpt), nme.CONSTRUCTOR), List(arg)) if (tpt.tpe.typeSymbol.isInlineClass) =>
+ Some(arg)
case LabelDef(name, params, Boxed(rhs)) =>
Some(treeCopy.LabelDef(tree, name, params, rhs) setType rhs.tpe)
- case Select(_, _) if tree.symbol == BoxedUnit_UNIT =>
- Some(Literal(Constant()) setPos tree.pos setType UnitClass.tpe)
- case Block(List(unboxed), ret @ Select(_, _)) if ret.symbol == BoxedUnit_UNIT =>
- Some(if (unboxed.tpe.typeSymbol == UnitClass) tree
- else Block(List(unboxed), Literal(Constant()) setPos tree.pos setType UnitClass.tpe))
- case Apply(fn, List(unboxed)) if isBox(fn.symbol) =>
- Some(unboxed)
case _ =>
None
}
}
- */
/** The modifier typer which retypes with erased types. */
class Eraser(_context: Context) extends Typer(_context) {
- private def safeToRemoveUnbox(cls: Symbol): Boolean =
- (cls == definitions.NullClass) || isBoxedValueClass(cls)
-
+
private def isUnboxedType(tpe: Type) = tpe match {
case ErasedInlineType(_) => true
case _ => isPrimitiveValueClass(tpe.typeSymbol)
@@ -403,24 +421,33 @@ abstract class Erasure extends AddInterfaces
private def isUnboxedValueMember(sym: Symbol) =
sym != NoSymbol && isPrimitiveValueClass(sym.owner)
+ private def box(tree: Tree, target: => String): Tree = {
+ val result = box1(tree)
+ log("boxing "+tree+":"+tree.tpe+" to "+target+" = "+result+":"+result.tpe)
+ result
+ }
+
/** Box `tree` of unboxed type */
- private def box(tree: Tree): Tree = tree match {
+ private def box1(tree: Tree): Tree = tree match {
case LabelDef(name, params, rhs) =>
- val rhs1 = box(rhs)
+ val rhs1 = box1(rhs)
treeCopy.LabelDef(tree, name, params, rhs1) setType rhs1.tpe
case _ =>
val tree1 = tree.tpe match {
case ErasedInlineType(clazz) =>
- util.trace("converting "+tree.tpe+" to "+valueClassErasure(clazz)+":")(
- New(clazz, cast(tree, valueClassErasure(clazz)))
- )
+ tree match {
+ case Unboxed(arg) if arg.tpe.typeSymbol == clazz =>
+ log("shortcircuiting unbox -> box "+arg); arg
+ case _ =>
+ New(clazz, cast(tree, valueClassErasure(clazz)))
+ }
case _ =>
tree.tpe.typeSymbol match {
case UnitClass =>
if (treeInfo isExprSafeToInline tree) REF(BoxedUnit_UNIT)
else BLOCK(tree, REF(BoxedUnit_UNIT))
case NothingClass => tree // a non-terminating expression doesn't need boxing
- case x =>
+ case x =>
assert(x != ArrayClass)
tree match {
/** Can't always remove a Box(Unbox(x)) combination because the process of boxing x
@@ -440,13 +467,19 @@ abstract class Erasure extends AddInterfaces
typedPos(tree.pos)(tree1)
}
+ private def unbox(tree: Tree, pt: Type): Tree = {
+ val result = unbox1(tree, pt)
+ log("unboxing "+tree+":"+tree.tpe+" to "+pt+" = "+result+":"+result.tpe)
+ result
+ }
+
/** Unbox `tree` of boxed type to expected type `pt`.
*
* @param tree the given tree
* @param pt the expected type.
* @return the unboxed tree
*/
- private def unbox(tree: Tree, pt: Type): Tree = tree match {
+ private def unbox1(tree: Tree, pt: Type): Tree = tree match {
/*
case Boxed(unboxed) =>
println("unbox shorten: "+tree) // this never seems to kick in during build and test; therefore disabled.
@@ -458,8 +491,15 @@ abstract class Erasure extends AddInterfaces
case _ =>
val tree1 = pt match {
case ErasedInlineType(clazz) =>
- val tree0 = adaptToType(tree, valueClassErasure(clazz))
- cast(Apply(Select(tree0, underlyingParamAccessor(clazz)), List()), pt)
+ tree match {
+ case Boxed(arg) if arg.tpe.isInstanceOf[ErasedInlineType] =>
+ log("shortcircuiting box -> unbox "+arg)
+ arg
+ case _ =>
+ log("not boxed: "+tree)
+ val tree0 = adaptToType(tree, clazz.tpe)
+ cast(Apply(Select(tree0, clazz.firstParamAccessor), List()), pt)
+ }
case _ =>
pt.typeSymbol match {
case UnitClass =>
@@ -498,9 +538,7 @@ abstract class Erasure extends AddInterfaces
if (tree.tpe <:< pt)
tree
else if (isUnboxedType(tree.tpe) && !isUnboxedType(pt)) {
- val tree1 = util.trace("boxing "+tree.tpe+" to "+pt+" = ")(box(tree))
- println(tree1.tpe)
- adaptToType(tree1, 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)
@@ -512,10 +550,6 @@ abstract class Erasure extends AddInterfaces
cast(tree, pt)
}
- // @PP 1/25/2011: This is less inaccurate than it was (I removed
- // BoxedAnyArray, asInstanceOf$erased, and other long ago eliminated symbols)
- // but I do not think it yet describes the code beneath it.
-
/** Replace member references as follows:
*
* - `x == y` for == in class Any becomes `x equals y` with equals in class Object.
@@ -532,7 +566,8 @@ abstract class Erasure extends AddInterfaces
private def adaptMember(tree: Tree): Tree = {
//Console.println("adaptMember: " + tree);
tree match {
- case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List()) if tree.symbol == Any_asInstanceOf =>
+ case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List())
+ if tree.symbol == Any_asInstanceOf || tree.symbol == Object_asInstanceOf =>
val qual1 = typedQualifier(qual, NOmode, ObjectClass.tpe) // need to have an expected type, see #3037
val qualClass = qual1.tpe.typeSymbol
/*
@@ -545,10 +580,11 @@ abstract class Erasure extends AddInterfaces
*/
if (isUnboxedType(targ.tpe)) unbox(qual1, targ.tpe)
else tree
- case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List()) if tree.symbol == Any_isInstanceOf =>
+ case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List())
+ if tree.symbol == Any_isInstanceOf || tree.symbol == Object_asInstanceOf =>
targ.tpe match {
case ErasedInlineType(clazz) => targ.setType(scalaErasure(clazz.tpe))
- case _ =>
+ case _ =>
}
tree
case Select(qual, name) =>
@@ -565,13 +601,12 @@ abstract class Erasure extends AddInterfaces
adaptMember(atPos(tree.pos)(Select(qual, getMember(ObjectClass, name))))
else {
var qual1 = typedQualifier(qual)
- if ((isPrimitiveValueClass(qual1.tpe.typeSymbol) && !isUnboxedValueMember(tree.symbol))) {
- println("boxing "+qual1.tpe+" to member "+tree.symbol)
- qual1 = box(qual1)
- } else if (!isPrimitiveValueClass(qual1.tpe.typeSymbol) && isUnboxedValueMember(tree.symbol))
+ if ((isUnboxedType(qual1.tpe) && !isUnboxedValueMember(tree.symbol)))
+ qual1 = box(qual1, "owner "+tree.symbol.owner)
+ else if (!isUnboxedType(qual1.tpe) && isUnboxedValueMember(tree.symbol))
qual1 = unbox(qual1, tree.symbol.owner.tpe)
- if (isPrimitiveValueClass(tree.symbol.owner) && !isPrimitiveValueClass(qual1.tpe.typeSymbol))
+ if (isUnboxedValueMember(tree.symbol) && !isUnboxedType(qual1.tpe))
tree.symbol = NoSymbol
else if (qual1.tpe.isInstanceOf[MethodType] && qual1.tpe.params.isEmpty) {
assert(qual1.symbol.isStable, qual1.symbol);
@@ -998,7 +1033,7 @@ abstract class Erasure extends AddInterfaces
} else {
tree
}
-
+
case Select(qual, name) =>
val owner = tree.symbol.owner
// println("preXform: "+ (tree, tree.symbol, tree.symbol.owner, tree.symbol.owner.isRefinementClass))
@@ -1065,7 +1100,7 @@ abstract class Erasure extends AddInterfaces
*/
override def transform(tree: Tree): Tree = {
val tree1 = preTransformer.transform(tree)
- println("tree after pretransform: "+tree1)
+ log("tree after pretransform: "+tree1)
atPhase(phase.next) {
val tree2 = mixinTransformer.transform(tree1)
debuglog("tree after addinterfaces: \n" + tree2)
diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
index 114ec721d8..e5f2d49d52 100644
--- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
@@ -65,7 +65,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
matching.head
}
- private def normalize(stpe: Type, clazz: Symbol): Type = stpe match {
+ private def normalize(stpe: Type, clazz: Symbol): Type = stpe match {
case PolyType(tparams, restpe) =>
GenPolyType(tparams dropRight clazz.typeParams.length, normalize(restpe, clazz))
case MethodType(tparams, restpe) =>
@@ -123,7 +123,6 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
def thisParamRef = gen.mkAttributedIdent(extensionMeth.info.params.head setPos extensionMeth.pos)
val GenPolyType(extensionTpeParams, extensionMono) = extensionMeth.info
val origTpeParams = origMeth.typeParams ::: currentOwner.typeParams
- println("expanding "+tree+"/"+allParams(extensionMono)+"/"+extensionMeth.info)
val extensionBody = rhs
.substTreeSyms(origTpeParams, extensionTpeParams)
.substTreeSyms(vparamss.flatten map (_.symbol), allParams(extensionMono).tail)
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 3ee5bf601d..e0b4072fa1 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -39,6 +39,7 @@ trait SyntheticMethods extends ast.TreeDSL {
/** Add the synthetic methods to case classes.
*/
def addSyntheticMethods(templ: Template, clazz0: Symbol, context: Context): Template = {
+
if (phase.erasedTypes)
return templ
@@ -47,8 +48,8 @@ trait SyntheticMethods extends ast.TreeDSL {
newTyper( if (reporter.hasErrors) context makeSilent false else context )
)
import synthesizer._
-
- if (clazz0 isSubClass AnyValClass) return {
+
+ if (clazz0 == AnyValClass || isPrimitiveValueClass(clazz0)) return {
if (clazz0.info member nme.getClass_ isDeferred) {
val getClassMethod = createMethod(nme.getClass_, getClassReturnType(clazz.tpe)) { sym =>
// XXX dummy implementation for now
@@ -96,8 +97,8 @@ trait SyntheticMethods extends ast.TreeDSL {
def hasOverridingImplementation(meth: Symbol) = {
val sym = clazz.info nonPrivateMember meth.name
- sym.alternatives filterNot (_ eq meth) exists { m0 =>
- !m0.isDeferred && !m0.isSynthetic && (typeInClazz(m0) matches typeInClazz(meth))
+ sym.alternatives exists { m0 =>
+ (m0 ne meth) && !m0.isDeferred && !m0.isSynthetic && (m0.owner != AnyValClass) && (typeInClazz(m0) matches typeInClazz(meth))
}
}
def readConstantValue[T](name: String, default: T = null.asInstanceOf[T]): T = {
@@ -122,13 +123,49 @@ trait SyntheticMethods extends ast.TreeDSL {
// def productElementNameMethod = perElementMethod(nme.productElementName, StringClass.tpe)(x => LIT(x.name.toString))
+ var syntheticCanEqual = false
+
/** The canEqual method for case classes.
* def canEqual(that: Any) = that.isInstanceOf[This]
*/
- def canEqualMethod: Tree = (
- createMethod(nme.canEqual_, List(AnyClass.tpe), BooleanClass.tpe)(m =>
+ def canEqualMethod: Tree = {
+ syntheticCanEqual = true
+ createMethod(nme.canEqual_, List(AnyClass.tpe), BooleanClass.tpe)(m =>
Ident(m.firstParam) IS_OBJ typeCaseType(clazz))
- )
+ }
+
+ /** (that.isInstanceOf[this.C])
+ * where that is the given methods first parameter.
+ */
+ def thatTest(eqmeth: Symbol): Tree =
+ gen.mkIsInstanceOf(Ident(eqmeth.firstParam), typeCaseType(clazz), true, false)
+
+ /** (that.asInstanceOf[this.C])
+ * where that is the given methods first parameter.
+ */
+ def thatCast(eqmeth: Symbol): Tree =
+ gen.mkCast(Ident(eqmeth.firstParam), clazz.tpe)
+
+ /** The equality method core for case classes and inline clases.
+ * 1+ args:
+ * (that.isInstanceOf[this.C]) && {
+ * val x$1 = that.asInstanceOf[this.C]
+ * (this.arg_1 == x$1.arg_1) && (this.arg_2 == x$1.arg_2) && ... && (x$1 canEqual this)
+ * }
+ * Drop canBuildFrom part if class is final and canBuildFrom is synthesized
+ */
+ def equalsCore(eqmeth: Symbol, accessors: List[Symbol]) = {
+ val otherName = context.unit.freshTermName(clazz.name + "$")
+ val otherSym = eqmeth.newValue(otherName, eqmeth.pos, SYNTHETIC) setInfo clazz.tpe
+ val pairwise = accessors map (acc => fn(Select(This(clazz), acc), acc.tpe member nme.EQ, Select(Ident(otherSym), acc)))
+ val canEq = gen.mkMethodCall(otherSym, nme.canEqual_, Nil, List(This(clazz)))
+ val tests = if (clazz.isInlineClass || clazz.isFinal && syntheticCanEqual) pairwise else pairwise :+ canEq
+
+ thatTest(eqmeth) AND Block(
+ ValDef(otherSym, thatCast(eqmeth)),
+ AND(tests: _*)
+ )
+ }
/** The equality method for case classes.
* 0 args:
@@ -141,34 +178,36 @@ trait SyntheticMethods extends ast.TreeDSL {
* }
* }
*/
- def equalsClassMethod: Tree = createMethod(nme.equals_, List(AnyClass.tpe), BooleanClass.tpe) { m =>
- val arg0 = Ident(m.firstParam)
- val thatTest = gen.mkIsInstanceOf(arg0, typeCaseType(clazz), true, false)
- val thatCast = gen.mkCast(arg0, clazz.tpe)
-
- def argsBody: Tree = {
- val otherName = context.unit.freshTermName(clazz.name + "$")
- val otherSym = m.newValue(otherName, m.pos, SYNTHETIC) setInfo clazz.tpe
- val pairwise = accessors map (acc => fn(Select(This(clazz), acc), acc.tpe member nme.EQ, Select(Ident(otherSym), acc)))
- val canEq = gen.mkMethodCall(otherSym, nme.canEqual_, Nil, List(This(clazz)))
- def block = Block(ValDef(otherSym, thatCast), AND(pairwise :+ canEq: _*))
-
- (This(clazz) ANY_EQ arg0) OR {
- thatTest AND Block(
- ValDef(otherSym, thatCast),
- AND(pairwise :+ canEq: _*)
- )
- }
- }
+ def equalsCaseClassMethod: Tree = createMethod(nme.equals_, List(AnyClass.tpe), BooleanClass.tpe) { m =>
if (accessors.isEmpty)
- thatTest AND ((thatCast DOT nme.canEqual_)(This(clazz)))
+ if (clazz.isFinal) thatTest(m)
+ else thatTest(m) AND ((thatCast(m) DOT nme.canEqual_)(This(clazz)))
else
- argsBody
+ (This(clazz) ANY_EQ Ident(m.firstParam)) OR equalsCore(m, accessors)
+ }
+
+ /** The equality method for value classes
+ * def equals(that: Any) = (this.asInstanceOf[AnyRef]) eq that.asInstanceOf[AnyRef]) || {
+ * (that.isInstanceOf[this.C]) && {
+ * val x$1 = that.asInstanceOf[this.C]
+ * (this.underlying == that.underlying
+ */
+ def equalsInlineClassMethod: Tree = createMethod(nme.equals_, List(AnyClass.tpe), BooleanClass.tpe) { m =>
+ equalsCore(m, List(clazz.firstParamAccessor))
+ }
+
+ /** The hashcode method for value classes
+ * def hashCode(): Int = this.underlying.hashCode
+ */
+ def hashCodeInlineClassMethod: Tree = createMethod(nme.hashCode_, Nil, IntClass.tpe) { m =>
+ Select(
+ Select(This(clazz), clazz.firstParamAccessor),
+ nme.hashCode_)
}
/** The _1, _2, etc. methods to implement ProductN.
*/
- def productNMethods = {
+ def productNMethods = {
val accs = accessors.toIndexedSeq
1 to arity map (num => productProj(arity, num) -> (() => projectionMethod(accs(num - 1), num)))
}
@@ -190,7 +229,7 @@ trait SyntheticMethods extends ast.TreeDSL {
def caseClassMethods = productMethods ++ productNMethods ++ Seq(
Object_hashCode -> (() => forwardToRuntime(Object_hashCode)),
Object_toString -> (() => forwardToRuntime(Object_toString)),
- Object_equals -> (() => equalsClassMethod)
+ Object_equals -> (() => equalsCaseClassMethod)
)
def caseObjectMethods = productMethods ++ Seq(
@@ -200,6 +239,11 @@ trait SyntheticMethods extends ast.TreeDSL {
// Object_equals -> (() => createMethod(Object_equals)(m => This(clazz) ANY_EQ Ident(m.firstParam)))
)
+ def inlineClassMethods = List(
+ Any_hashCode -> (() => hashCodeInlineClassMethod),
+ Any_equals -> (() => equalsInlineClassMethod)
+ )
+
/** If you serialize a singleton and then deserialize it twice,
* you will have two instances of your singleton unless you implement
* readResolve. Here it is implemented for all objects which have
@@ -214,10 +258,12 @@ trait SyntheticMethods extends ast.TreeDSL {
def synthesize(): List[Tree] = {
val methods = (
- if (!clazz.isCase) Nil
+ if (clazz.isInlineClass) inlineClassMethods
+ else if (!clazz.isCase) Nil
else if (clazz.isModuleClass) caseObjectMethods
else caseClassMethods
)
+
def impls = for ((m, impl) <- methods ; if !hasOverridingImplementation(m)) yield impl()
def extras = (
if (needsReadResolve) {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index e6a3ddbe31..008a2e1764 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1193,6 +1193,27 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
}
+ private def validateInlineClass(clazz: Symbol, body: List[Tree]) = {
+ if (clazz.isTrait)
+ unit.error(clazz.pos, "Only classes (not traits) are allowed to extend AnyVal")
+ if (!clazz.isStatic)
+ unit.error(clazz.pos, "Value class may not be a "+
+ (if (clazz.owner.isTerm) "local class" else "member of another class"))
+ clazz.info.decls.toList.filter(acc => acc.isMethod && (acc hasFlag PARAMACCESSOR)) match {
+ case List(acc) =>
+ def isUnderlyingAcc(sym: Symbol) =
+ sym == acc || acc.hasAccessorFlag && sym == acc.accessed
+ if (acc.accessBoundary(clazz) != RootClass)
+ unit.error(acc.pos, "Value class needs to have a publicly accessible val parameter")
+ else
+ for (stat <- body)
+ if (!treeInfo.isAllowedInUniversalTrait(stat) && !isUnderlyingAcc(stat.symbol))
+ unit.error(stat.pos, "This statement is not allowed in value class: "+stat)
+ case x =>
+ unit.error(clazz.pos, "Value class needs to have exactly one public val parameter")
+ }
+ }
+
def parentTypes(templ: Template): List[Tree] =
if (templ.parents.isEmpty) List(TypeTree(AnyRefClass.tpe))
else try {
@@ -1209,7 +1230,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
supertpt = TypeTree(supertpt1.tpe.firstParent) setPos supertpt.pos.focus
}
}
- if (supertpt.tpe.typeSymbol == AnyClass && firstParent.isTrait && firstParent != AnyValClass)
+ if (supertpt.tpe.typeSymbol == AnyClass && firstParent.isTrait)
supertpt.tpe = AnyRefClass.tpe
// Determine
@@ -1300,7 +1321,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
else xs
)
}
-
+
fixDuplicates(supertpt :: mixins) mapConserve (tpt => checkNoEscaping.privates(clazz, tpt))
}
catch {
@@ -1418,7 +1439,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val impl2 = finishMethodSynthesis(impl1, clazz, context)
if (clazz.isTrait && clazz.info.parents.nonEmpty && clazz.info.firstParent.typeSymbol == AnyClass)
for (stat <- impl2.body)
- if (!treeInfo.isAllowedInAnyTrait(stat))
+ if (!treeInfo.isAllowedInUniversalTrait(stat))
unit.error(stat.pos, "this statement is not allowed in trait extending from class Any: "+stat)
if ((clazz != ClassfileAnnotationClass) &&
(clazz isNonBottomSubClass ClassfileAnnotationClass))
@@ -1536,6 +1557,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if ((clazz isSubClass ClassfileAnnotationClass) && !clazz.owner.isPackageClass)
unit.error(clazz.pos, "inner classes cannot be classfile annotations")
+
if (!phase.erasedTypes && !clazz.info.resultType.isError) // @S: prevent crash for duplicated type members
checkFinitary(clazz.info.resultType.asInstanceOf[ClassInfoType])
@@ -1544,6 +1566,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
else templ.body flatMap rewrappingWrapperTrees(namer.finishGetterSetter(Typer.this, _))
val body1 = typedStats(body, templ.symbol)
+
+ if (clazz.isInlineClass)
+ validateInlineClass(clazz, body1)
+
treeCopy.Template(templ, parents1, self1, body1) setType clazz.tpe
}