summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala33
-rw-r--r--src/compiler/scala/reflect/internal/SymbolTable.scala6
-rw-r--r--src/compiler/scala/reflect/internal/Symbols.scala22
-rw-r--r--src/compiler/scala/reflect/internal/TreeGen.scala35
-rw-r--r--src/compiler/scala/reflect/internal/TreePrinters.scala10
-rw-r--r--src/compiler/scala/reflect/internal/Trees.scala26
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala42
-rw-r--r--src/compiler/scala/reflect/internal/pickling/UnPickler.scala1
-rw-r--r--src/compiler/scala/reflect/internal/transform/Erasure.scala201
-rw-r--r--src/compiler/scala/reflect/runtime/ScalaToJava.scala2
-rw-r--r--src/compiler/scala/reflect/runtime/Universe.scala6
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala25
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala35
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeInfo.scala6
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala20
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala59
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala2
-rw-r--r--src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/AddInterfaces.scala38
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala234
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala38
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/PostErasure.scala68
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala12
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala43
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala118
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala50
34 files changed, 746 insertions, 423 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala
index 9114eb4b67..1d53b83b75 100644
--- a/src/compiler/scala/reflect/internal/Definitions.scala
+++ b/src/compiler/scala/reflect/internal/Definitions.scala
@@ -230,7 +230,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
def Predef_AnyRef = AnyRefModule
lazy val AnyValClass = ScalaPackageClass.info member tpnme.AnyVal orElse {
- val anyval = enterNewClass(ScalaPackageClass, tpnme.AnyVal, List(AnyClass.tpe, NotNullClass.tpe), 0L)
+ val anyval = enterNewClass(ScalaPackageClass, tpnme.AnyVal, List(AnyClass.tpe, NotNullClass.tpe), ABSTRACT)
val av_constr = anyval.newClassConstructor(NoPosition)
anyval.info.decls enter av_constr
anyval
@@ -341,7 +341,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
lazy val TypeConstraintClass = getRequiredClass("scala.annotation.TypeConstraint")
lazy val SingletonClass = enterNewClass(ScalaPackageClass, tpnme.Singleton, anyparam, ABSTRACT | TRAIT | FINAL)
lazy val SerializableClass = getRequiredClass("scala.Serializable")
- lazy val JavaSerializableClass = getClass(sn.JavaSerializable)
+ lazy val JavaSerializableClass = getClass(sn.JavaSerializable) modifyInfo fixupAsAnyTrait
lazy val ComparableClass = getRequiredClass("java.lang.Comparable") modifyInfo fixupAsAnyTrait
lazy val JavaCloneableClass = getRequiredClass("java.lang.Cloneable")
lazy val RemoteInterfaceClass = getRequiredClass("java.rmi.Remote")
@@ -371,7 +371,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
}
def isPrimitiveArray(tp: Type) = tp match {
- case TypeRef(_, ArrayClass, arg :: Nil) => isValueClass(arg.typeSymbol)
+ case TypeRef(_, ArrayClass, arg :: Nil) => isPrimitiveValueClass(arg.typeSymbol)
case _ => false
}
def isArrayOfSymbol(tp: Type, elem: Symbol) = tp match {
@@ -717,7 +717,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
val sym = tp.typeSymbol
if (phase.erasedTypes) ClassClass.tpe
- else if (isValueClass(sym)) ClassType(tp.widen)
+ else if (isPrimitiveValueClass(sym)) ClassType(tp.widen)
else {
val eparams = typeParamsToExistentials(ClassClass, ClassClass.typeParams)
val upperBound = (
@@ -741,7 +741,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
/** Remove all but one reference to class Object from a list of parents. */
def removeRedundantObjects(tps: List[Type]): List[Type] = tps match {
case Nil => Nil
- case x :: xs =>
+ case x :: xs =>
if (x.typeSymbol == ObjectClass)
x :: xs.filterNot(_.typeSymbol == ObjectClass)
else
@@ -977,20 +977,14 @@ trait Definitions extends reflect.api.StandardDefinitions {
/** Is the symbol that of a parent which is added during parsing? */
lazy val isPossibleSyntheticParent = ProductClass.toSet[Symbol] + ProductRootClass + SerializableClass
- private lazy val scalaValueClassesSet = ScalaValueClasses.toSet
+ lazy val scalaValueClassesSet = ScalaValueClasses.toSet
private lazy val boxedValueClassesSet = boxedClass.values.toSet + BoxedUnitClass
- /** Now that AnyVal is unsealing we need less ambiguous names
- * for when we need to distinguish the Nine Original AnyVals
- * from the heathen masses.
- */
- def isPrimitiveValueClass(sym: Symbol) = scalaValueClassesSet(sym)
-
/** Is symbol a value class? */
- def isValueClass(sym: Symbol) = scalaValueClassesSet(sym)
- def isNonUnitValueClass(sym: Symbol) = isValueClass(sym) && (sym != UnitClass)
- def isSpecializableClass(sym: Symbol) = isValueClass(sym) || (sym == AnyRefClass)
- def isScalaValueType(tp: Type) = scalaValueClassesSet(tp.typeSymbol)
+ def isPrimitiveValueClass(sym: Symbol) = scalaValueClassesSet(sym)
+ def isNonUnitValueClass(sym: Symbol) = isPrimitiveValueClass(sym) && (sym != UnitClass)
+ def isSpecializableClass(sym: Symbol) = isPrimitiveValueClass(sym) || (sym == AnyRefClass)
+ def isScalaValueType(tp: Type) = scalaValueClassesSet(tp.typeSymbol)
/** Is symbol a boxed value class, e.g. java.lang.Integer? */
def isBoxedValueClass(sym: Symbol) = boxedValueClassesSet(sym)
@@ -999,7 +993,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
* value class. Otherwise, NoSymbol.
*/
def unboxedValueClass(sym: Symbol): Symbol =
- if (isValueClass(sym)) sym
+ if (isPrimitiveValueClass(sym)) sym
else if (sym == BoxedUnitClass) UnitClass
else boxedClass.map(_.swap).getOrElse(sym, NoSymbol)
@@ -1022,7 +1016,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
else flatNameString(sym.owner, separator) + nme.NAME_JOIN_STRING + sym.simpleName
def signature1(etp: Type): String = {
if (etp.typeSymbol == ArrayClass) "[" + signature1(erasure(etp.normalize.typeArgs.head))
- else if (isValueClass(etp.typeSymbol)) abbrvTag(etp.typeSymbol).toString()
+ else if (isPrimitiveValueClass(etp.typeSymbol)) abbrvTag(etp.typeSymbol).toString()
else "L" + flatNameString(etp.typeSymbol, '/') + ";"
}
val etp = erasure(tp)
@@ -1101,7 +1095,8 @@ trait Definitions extends reflect.api.StandardDefinitions {
Object_isInstanceOf,
Object_asInstanceOf,
String_+,
- ComparableClass
+ ComparableClass,
+ JavaSerializableClass
)
isInitialized = true
diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala
index 2a5f5c5394..b58a0ef7d5 100644
--- a/src/compiler/scala/reflect/internal/SymbolTable.scala
+++ b/src/compiler/scala/reflect/internal/SymbolTable.scala
@@ -128,6 +128,10 @@ abstract class SymbolTable extends api.Universe
final def period(rid: RunId, pid: Phase#Id): Period =
(rid << 8) + pid
+ /** Are we later than given phase in compilation? */
+ final def isAtPhaseAfter(p: Phase) =
+ p != NoPhase && phase.id > p.id
+
/** Perform given operation at given phase. */
@inline final def atPhase[T](ph: Phase)(op: => T): T = {
val saved = pushPhase(ph)
@@ -145,7 +149,7 @@ abstract class SymbolTable extends api.Universe
@inline final def beforePrevPhase[T](op: => T): T = atPhase(phase.prev)(op)
@inline final def atPhaseNotLaterThan[T](target: Phase)(op: => T): T =
- if (target != NoPhase && phase.id > target.id) atPhase(target)(op) else op
+ if (isAtPhaseAfter(target)) atPhase(target)(op) else op
final def isValid(period: Period): Boolean =
period != 0 && runId(period) == currentRunId && {
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala
index c171ecc702..febc2ef330 100644
--- a/src/compiler/scala/reflect/internal/Symbols.scala
+++ b/src/compiler/scala/reflect/internal/Symbols.scala
@@ -441,7 +441,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def isRefinementClass = isClass && name == tpnme.REFINE_CLASS_NAME
final def isSourceMethod = isMethod && !hasFlag(STABLE) // exclude all accessors!!!
final def isTypeParameter = isType && isParameter && !isSkolem
- final def isValueClass = definitions.isValueClass(this)
+ final def isPrimitiveValueClass = definitions.isPrimitiveValueClass(this)
final def isVarargsMethod = isMethod && hasFlag(VARARGS)
/** Package tests */
@@ -499,7 +499,12 @@ 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 = isClass && hasAnnotation(ScalaInlineClass)
+ final def isDerivedValueClass =
+ isClass && info.parents.headOption.getOrElse(AnyClass.tpe).typeSymbol == AnyValClass &&
+ !isPrimitiveValueClass
+
+ final def isMethodWithExtension =
+ isMethod && owner.isDerivedValueClass && !isParamAccessor && !isConstructor && !hasFlag(SUPERACCESSOR)
final def isAnonymousClass = isClass && (name containsName tpnme.ANON_CLASS_NAME)
final def isAnonymousFunction = isSynthetic && (name containsName tpnme.ANON_FUN_NAME)
@@ -1837,7 +1842,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 = {
@@ -2511,7 +2521,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 =
@@ -2587,6 +2597,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 }
diff --git a/src/compiler/scala/reflect/internal/TreeGen.scala b/src/compiler/scala/reflect/internal/TreeGen.scala
index 89585724f1..141ff12f8a 100644
--- a/src/compiler/scala/reflect/internal/TreeGen.scala
+++ b/src/compiler/scala/reflect/internal/TreeGen.scala
@@ -148,22 +148,6 @@ abstract class TreeGen {
None
}
- /** Cast `tree` to type `pt` */
- def mkCast(tree: Tree, pt: Type): Tree = {
- debuglog("casting " + tree + ":" + tree.tpe + " to " + pt + " at phase: " + phase)
- assert(!tree.tpe.isInstanceOf[MethodType], tree)
- assert(!pt.typeSymbol.isPackageClass && !pt.typeSymbol.isPackageObjectClass, pt)
- // called during (at least): typer, uncurry, explicitouter, cleanup.
- // TODO: figure out the truth table for any/wrapInApply
- // - the `any` flag seems to relate to erasure's adaptMember: "x.asInstanceOf[T] becomes x.$asInstanceOf[T]",
- // where asInstanceOf is Any_asInstanceOf and $asInstanceOf is Object_asInstanceOf
- // erasure will only unbox the value in a tree made by mkCast if `any && wrapInApply`
- // - the `wrapInApply` flag need not be true if the tree will be adapted to have the empty argument list added before it gets to erasure
- // in fact, I think it should be false for trees that will be type checked during typer
- assert(pt eq pt.normalize, tree +" : "+ debugString(pt) +" ~>"+ debugString(pt.normalize))
- atPos(tree.pos)(mkAsInstanceOf(tree, pt, any = false, wrapInApply = true))
- }
-
/** Builds a reference with stable type to given symbol */
def mkAttributedStableRef(pre: Type, sym: Symbol): Tree =
stabilize(mkAttributedRef(pre, sym))
@@ -267,25 +251,6 @@ abstract class TreeGen {
case _ => Constant(null)
}
- def mkZeroContravariantAfterTyper(tp: Type): Tree = {
- // contravariant -- for replacing an argument in a method call
- // must use subtyping, as otherwise we miss types like `Any with Int`
- val tree =
- if (NullClass.tpe <:< tp) Literal(Constant(null))
- else if (UnitClass.tpe <:< tp) Literal(Constant())
- else if (BooleanClass.tpe <:< tp) Literal(Constant(false))
- else if (FloatClass.tpe <:< tp) Literal(Constant(0.0f))
- else if (DoubleClass.tpe <:< tp) Literal(Constant(0.0d))
- else if (ByteClass.tpe <:< tp) Literal(Constant(0.toByte))
- else if (ShortClass.tpe <:< tp) Literal(Constant(0.toShort))
- else if (IntClass.tpe <:< tp) Literal(Constant(0))
- else if (LongClass.tpe <:< tp) Literal(Constant(0L))
- else if (CharClass.tpe <:< tp) Literal(Constant(0.toChar))
- else mkCast(Literal(Constant(null)), tp)
-
- tree
- }
-
/** Builds a tuple */
def mkTuple(elems: List[Tree]): Tree =
if (elems.isEmpty) Literal(Constant())
diff --git a/src/compiler/scala/reflect/internal/TreePrinters.scala b/src/compiler/scala/reflect/internal/TreePrinters.scala
index 5845eda5ca..f823110440 100644
--- a/src/compiler/scala/reflect/internal/TreePrinters.scala
+++ b/src/compiler/scala/reflect/internal/TreePrinters.scala
@@ -242,10 +242,10 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable =>
case Template(parents, self, body) =>
val currentOwner1 = currentOwner
if (tree.symbol != NoSymbol) currentOwner = tree.symbol.owner
- if (parents exists isReferenceToAnyVal) {
- print("AnyVal")
- }
- else {
+// if (parents exists isReferenceToAnyVal) {
+// print("AnyVal")
+// }
+// else {
printRow(parents, " with ")
if (!body.isEmpty) {
if (self.name != nme.WILDCARD) {
@@ -257,7 +257,7 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable =>
}
printColumn(body, "", ";", "}")
}
- }
+// }
currentOwner = currentOwner1
case Block(stats, expr) =>
diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala
index e576f09f56..77ea7392a8 100644
--- a/src/compiler/scala/reflect/internal/Trees.scala
+++ b/src/compiler/scala/reflect/internal/Trees.scala
@@ -133,7 +133,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
new ChangeOwnerTraverser(oldOwner, newOwner) apply t
}
}
-
+
def substTreeSyms(pairs: (Symbol, Symbol)*): Tree =
substTreeSyms(pairs.map(_._1).toList, pairs.map(_._2).toList)
@@ -318,10 +318,14 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
class ChangeOwnerTraverser(val oldowner: Symbol, val newowner: Symbol) extends Traverser {
- def changeOwner(tree: Tree) = {
- if ((tree.isDef || tree.isInstanceOf[Function]) &&
- tree.symbol != NoSymbol && tree.symbol.owner == oldowner)
- tree.symbol.owner = newowner
+ def changeOwner(tree: Tree) = tree match {
+ case Return(expr) =>
+ if (tree.symbol == oldowner)
+ tree.symbol = newowner
+ case _: DefTree | _: Function =>
+ if (tree.symbol != NoSymbol && tree.symbol.owner == oldowner)
+ tree.symbol.owner = newowner
+ case _ =>
}
override def traverse(tree: Tree) {
changeOwner(tree)
@@ -357,10 +361,16 @@ trait Trees extends api.Trees { self: SymbolTable =>
override def toString = substituterString("Symbol", "Tree", from, to)
}
+ /** Substitute clazz.this with `to`. `to` must be an attributed tree.
+ */
class ThisSubstituter(clazz: Symbol, to: => Tree) extends Transformer {
- override def transform(tree: Tree) = tree match {
- case This(_) if tree.symbol == clazz => to
- case _ => super.transform(tree)
+ val newtpe = to.tpe
+ override def transform(tree: Tree) = {
+ if (tree.tpe ne null) tree.tpe = tree.tpe.substThis(clazz, newtpe)
+ tree match {
+ case This(_) if tree.symbol == clazz => to
+ case _ => super.transform(tree)
+ }
}
}
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index ac4f404521..2382413a9a 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -65,8 +65,8 @@ 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 ErasedInlineType(tp)
- // only used during erasure of inline classes.
+ case ErasedValueType(tp)
+ // only used during erasure of derived value classes.
*/
trait Types extends api.Types { self: SymbolTable =>
@@ -411,7 +411,7 @@ trait Types extends api.Types { self: SymbolTable =>
* inherited by typerefs, singleton types, and refinement types,
* The empty list for all other types */
def parents: List[Type] = List()
-
+
/** For a class with nonEmpty parents, the first parent.
* Otherwise some specific fixed top type.
*/
@@ -1424,7 +1424,7 @@ trait Types extends api.Types { self: SymbolTable =>
// override def isNullable: Boolean =
// parents forall (p => p.isNullable && !p.typeSymbol.isAbstractType);
-
+
override def safeToString: String = parentsString(parents) + (
(if (settings.debug.value || parents.isEmpty || (decls.elems ne null))
decls.mkString("{", "; ", "}") else "")
@@ -2106,7 +2106,7 @@ trait Types extends api.Types { self: SymbolTable =>
!sym.isTypeParameter && pre.isTrivial && args.forall(_.isTrivial)
override def isNotNull =
- sym.isModuleClass || sym == NothingClass || isValueClass(sym) || super.isNotNull
+ sym.isModuleClass || sym == NothingClass || (sym isNonBottomSubClass NotNullClass) || super.isNotNull
override def parents: List[Type] = {
val cache = parentsCache
@@ -2155,7 +2155,7 @@ trait Types extends api.Types { self: SymbolTable =>
)
else ""
)
-
+
private def finishPrefix(rest: String) = (
if (sym.isPackageClass) packagePrefix + rest
else if (sym.isModuleClass) objectPrefix + rest
@@ -3094,14 +3094,16 @@ trait Types extends api.Types { self: SymbolTable =>
"De Bruijn "+kind+"("+(pnames mkString ",")+";"+(ptypes mkString ",")+";"+restpe+")"
}
}
-
- abstract case class ErasedInlineType(sym: Symbol) extends Type
-
- final class UniqueErasedInlineType(sym: Symbol) extends ErasedInlineType(sym) with UniqueType
-
- object ErasedInlineType {
- def apply(sym: Symbol): Type =
- unique(new UniqueErasedInlineType(sym))
+
+ abstract case class ErasedValueType(sym: Symbol) extends Type {
+ override def safeToString = sym.name+"$unboxed"
+ }
+
+ final class UniqueErasedValueType(sym: Symbol) extends ErasedValueType(sym) with UniqueType
+
+ object ErasedValueType {
+ def apply(sym: Symbol): Type =
+ unique(new UniqueErasedValueType(sym))
}
/** A class representing an as-yet unevaluated type.
@@ -5445,8 +5447,7 @@ trait Types extends api.Types { self: SymbolTable =>
case NullClass =>
tp2 match {
case TypeRef(_, sym2, _) =>
- sym2.isClass && (sym2 isNonBottomSubClass ObjectClass) &&
- !(tp2.normalize.typeSymbol isNonBottomSubClass NotNullClass)
+ containsNull(sym2)
case _ =>
isSingleType(tp2) && tp1 <:< tp2.widen
}
@@ -5477,6 +5478,11 @@ trait Types extends api.Types { self: SymbolTable =>
firstTry
}
+ private def containsNull(sym: Symbol): Boolean =
+ sym.isClass && sym != NothingClass &&
+ !(sym isNonBottomSubClass AnyValClass) &&
+ !(sym isNonBottomSubClass NotNullClass)
+
/** Are `tps1` and `tps2` lists of equal length such that all elements
* of `tps1` conform to corresponding elements of `tps2`?
*/
@@ -5488,7 +5494,7 @@ trait Types extends api.Types { self: SymbolTable =>
*/
def specializesSym(tp: Type, sym: Symbol): Boolean =
tp.typeSymbol == NothingClass ||
- tp.typeSymbol == NullClass && (sym.owner isSubClass ObjectClass) ||
+ tp.typeSymbol == NullClass && containsNull(sym.owner) ||
(tp.nonPrivateMember(sym.name).alternatives exists
(alt => sym == alt || specializesSym(tp.narrow, alt, sym.owner.thisType, sym)))
@@ -6328,7 +6334,7 @@ trait Types extends api.Types { self: SymbolTable =>
} else {
val args = argss map (_.head)
if (args.tail forall (_ =:= args.head)) Some(typeRef(pre, sym, List(args.head)))
- else if (args exists (arg => isValueClass(arg.typeSymbol))) Some(ObjectClass.tpe)
+ else if (args exists (arg => isPrimitiveValueClass(arg.typeSymbol))) Some(ObjectClass.tpe)
else Some(typeRef(pre, sym, List(lub(args))))
}
}
diff --git a/src/compiler/scala/reflect/internal/pickling/UnPickler.scala b/src/compiler/scala/reflect/internal/pickling/UnPickler.scala
index 34163d54f8..f1ec64bda9 100644
--- a/src/compiler/scala/reflect/internal/pickling/UnPickler.scala
+++ b/src/compiler/scala/reflect/internal/pickling/UnPickler.scala
@@ -229,6 +229,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ {
// (3) Try as a nested object symbol.
nestedObjectSymbol orElse {
// (4) Otherwise, fail.
+ //System.err.println("missing "+name+" in "+owner+"/"+owner.id+" "+owner.info.decls)
adjust(errorMissingRequirement(name, owner))
}
}
diff --git a/src/compiler/scala/reflect/internal/transform/Erasure.scala b/src/compiler/scala/reflect/internal/transform/Erasure.scala
index 7c360e1f25..e87de8db80 100644
--- a/src/compiler/scala/reflect/internal/transform/Erasure.scala
+++ b/src/compiler/scala/reflect/internal/transform/Erasure.scala
@@ -2,6 +2,8 @@ package scala.reflect
package internal
package transform
+import Flags.PARAMACCESSOR
+
trait Erasure {
val global: SymbolTable
@@ -63,57 +65,62 @@ trait Erasure {
if (cls.owner.isClass) cls.owner.tpe else pre // why not cls.isNestedClass?
}
- protected def unboxInlineType(clazz: Symbol): Type =
- clazz.primaryConstructor.info.params.head.tpe
-
- protected def eraseInlineClassRef(clazz: Symbol): Type = {
- scalaErasure(unboxInlineType(clazz))
- }
+ def underlyingOfValueClass(clazz: Symbol): Type =
+ clazz.firstParamAccessor.tpe.resultType
abstract class ErasureMap extends TypeMap {
def mergeParents(parents: List[Type]): Type
- def apply(tp: Type): Type = {
- tp match {
- case ConstantType(_) =>
- tp
- case st: SubType =>
- apply(st.supertype)
- case TypeRef(pre, sym, args) =>
- if (sym == ArrayClass)
- if (unboundedGenericArrayLevel(tp) == 1) ObjectClass.tpe
- else if (args.head.typeSymbol.isBottomClass) ObjectArray
- else typeRef(apply(pre), sym, args map this)
- else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass || sym == NotNullClass) erasedTypeRef(ObjectClass)
- else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass)
- else if (sym.isRefinementClass) apply(mergeParents(tp.parents))
- //else if (sym.isInlineClass) eraseInlineClassRef(sym)
- else if (sym.isClass) typeRef(apply(rebindInnerClass(pre, sym)), sym, List()) // #2585
- else apply(sym.info) // alias type or abstract type
- case PolyType(tparams, restpe) =>
- apply(restpe)
- case ExistentialType(tparams, restpe) =>
- apply(restpe)
- case mt @ MethodType(params, restpe) =>
- MethodType(
- cloneSymbolsAndModify(params, ErasureMap.this),
- if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass)
- // this replaces each typeref that refers to an argument
- // by the type `p.tpe` of the actual argument p (p in params)
- else apply(mt.resultType(params map (_.tpe))))
- case RefinedType(parents, decls) =>
- apply(mergeParents(parents))
- case AnnotatedType(_, atp, _) =>
- apply(atp)
- case ClassInfoType(parents, decls, clazz) =>
- ClassInfoType(
- if (clazz == ObjectClass || isValueClass(clazz)) Nil
- else if (clazz == ArrayClass) List(erasedTypeRef(ObjectClass))
- else removeLaterObjects(parents map this),
- decls, clazz)
- case _ =>
- mapOver(tp)
- }
+ def eraseNormalClassRef(pre: Type, clazz: Symbol): Type =
+ typeRef(apply(rebindInnerClass(pre, clazz)), clazz, List()) // #2585
+
+ protected def eraseDerivedValueClassRef(clazz: Symbol): Type =
+ scalaErasure(underlyingOfValueClass(clazz))
+
+ def apply(tp: Type): Type = tp match {
+ case ConstantType(_) =>
+ tp
+ case st: SubType =>
+ apply(st.supertype)
+ case TypeRef(pre, sym, args) =>
+ if (sym == ArrayClass)
+ if (unboundedGenericArrayLevel(tp) == 1) ObjectClass.tpe
+ else if (args.head.typeSymbol.isBottomClass) ObjectArray
+ else typeRef(apply(pre), sym, args map applyInArray)
+ else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass || sym == NotNullClass) erasedTypeRef(ObjectClass)
+ else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass)
+ else if (sym.isRefinementClass) apply(mergeParents(tp.parents))
+ else if (sym.isDerivedValueClass) eraseDerivedValueClassRef(sym)
+ else if (sym.isClass) eraseNormalClassRef(pre, sym)
+ else apply(sym.info) // alias type or abstract type
+ case PolyType(tparams, restpe) =>
+ apply(restpe)
+ case ExistentialType(tparams, restpe) =>
+ apply(restpe)
+ case mt @ MethodType(params, restpe) =>
+ MethodType(
+ cloneSymbolsAndModify(params, ErasureMap.this),
+ if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass)
+ // this replaces each typeref that refers to an argument
+ // by the type `p.tpe` of the actual argument p (p in params)
+ else apply(mt.resultType(params map (_.tpe))))
+ case RefinedType(parents, decls) =>
+ apply(mergeParents(parents))
+ case AnnotatedType(_, atp, _) =>
+ apply(atp)
+ case ClassInfoType(parents, decls, clazz) =>
+ ClassInfoType(
+ if (clazz == ObjectClass || isPrimitiveValueClass(clazz)) Nil
+ else if (clazz == ArrayClass) List(erasedTypeRef(ObjectClass))
+ else removeLaterObjects(parents map this),
+ decls, clazz)
+ case _ =>
+ mapOver(tp)
+ }
+
+ def applyInArray(tp: Type): Type = tp match {
+ case TypeRef(pre, sym, args) if (sym.isDerivedValueClass) => eraseNormalClassRef(pre, sym)
+ case _ => apply(tp)
}
}
@@ -146,17 +153,41 @@ trait Erasure {
* parents |Ps|, but with duplicate references of Object removed.
* - for all other types, the type itself (with any sub-components erased)
*/
- def erasure(sym: Symbol, tp: Type): Type = {
- if (sym != NoSymbol && sym.enclClass.isJavaDefined) {
- val res = javaErasure(tp)
- if (verifyJavaErasure && sym.isMethod) {
- val old = scalaErasure(tp)
- if (!(res =:= old))
- log("Identified divergence between java/scala erasure:\n scala: " + old + "\n java: " + res)
- }
- res
+ def erasure(sym: Symbol): ErasureMap =
+ if (sym == NoSymbol || !sym.enclClass.isJavaDefined) scalaErasure
+ else if (verifyJavaErasure && sym.isMethod) verifiedJavaErasure
+ else javaErasure
+
+ /** This is used as the Scala erasure during the erasure phase itself
+ * It differs from normal erasure in that value classes are erased to ErasedValueTypes which
+ * are then later converted to the underlying parameter type in phase posterasure.
+ */
+ def specialErasure(sym: Symbol)(tp: Type): Type =
+ if (sym != NoSymbol && sym.enclClass.isJavaDefined)
+ erasure(sym)(tp)
+ else if (sym.isTerm && sym.owner.isDerivedValueClass)
+ specialErasureAvoiding(sym.owner, tp)
+ else if (sym.isValue && sym.owner.isMethodWithExtension)
+ specialErasureAvoiding(sym.owner.owner, tp)
+ else
+ specialScalaErasure(tp)
+
+ def specialErasureAvoiding(clazz: Symbol, tpe: Type): Type = {
+ tpe match {
+ case PolyType(tparams, restpe) =>
+ specialErasureAvoiding(clazz, restpe)
+ case ExistentialType(tparams, restpe) =>
+ specialErasureAvoiding(clazz, restpe)
+ case mt @ MethodType(params, restpe) =>
+ MethodType(
+ cloneSymbolsAndModify(params, specialErasureAvoiding(clazz, _)),
+ if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass)
+ else specialErasureAvoiding(clazz, (mt.resultType(params map (_.tpe)))))
+ case TypeRef(pre, `clazz`, args) =>
+ typeRef(pre, clazz, List())
+ case _ =>
+ specialScalaErasure(tpe)
}
- else scalaErasure(tp)
}
/** Scala's more precise erasure than java's is problematic as follows:
@@ -171,7 +202,7 @@ trait Erasure {
* For this reason and others (such as distinguishing constructors from other methods)
* erasure is now (Symbol, Type) => Type rather than Type => Type.
*/
- object scalaErasure extends ErasureMap {
+ class ScalaErasureMap extends ErasureMap {
/** In scala, calculate a useful parent.
* An intersection such as `Object with Trait` erases to Trait.
*/
@@ -179,6 +210,37 @@ trait Erasure {
intersectionDominator(parents)
}
+ class JavaErasureMap extends ErasureMap {
+ /** In java, always take the first parent.
+ * An intersection such as `Object with Trait` erases to Object.
+ */
+ def mergeParents(parents: List[Type]): Type =
+ if (parents.isEmpty) ObjectClass.tpe
+ else parents.head
+ }
+
+ object scalaErasure extends ScalaErasureMap
+
+ /** This is used as the Scala erasure during the erasure phase itself
+ * It differs from normal erasure in that value classes are erased to ErasedValueTypes which
+ * are then later converted to the underlying parameter type in phase posterasure.
+ */
+ object specialScalaErasure extends ScalaErasureMap {
+ override def eraseDerivedValueClassRef(clazz: Symbol): Type = ErasedValueType(clazz)
+ }
+
+ object javaErasure extends JavaErasureMap
+
+ object verifiedJavaErasure extends JavaErasureMap {
+ override def apply(tp: Type): Type = {
+ val res = javaErasure(tp)
+ val old = scalaErasure(tp)
+ if (!(res =:= old))
+ log("Identified divergence between java/scala erasure:\n scala: " + old + "\n java: " + res)
+ res
+ }
+ }
+
/** 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
@@ -214,18 +276,9 @@ trait Erasure {
}
}
- object javaErasure extends ErasureMap {
- /** In java, always take the first parent.
- * An intersection such as `Object with Trait` erases to Object.
- */
- def mergeParents(parents: List[Type]): Type =
- if (parents.isEmpty) ObjectClass.tpe
- else parents.head
- }
-
/** Type reference after erasure */
def erasedTypeRef(sym: Symbol): Type =
- typeRef(erasure(sym, sym.owner.tpe), sym, Nil)
+ typeRef(erasure(sym)(sym.owner.tpe), sym, Nil)
/** The symbol's erased info. This is the type's erasure, except for the following symbols:
*
@@ -239,25 +292,25 @@ trait Erasure {
if (sym == Object_asInstanceOf)
sym.info
else if (sym == Object_isInstanceOf || sym == ArrayClass)
- PolyType(sym.info.typeParams, erasure(sym, sym.info.resultType))
+ PolyType(sym.info.typeParams, specialErasure(sym)(sym.info.resultType))
else if (sym.isAbstractType)
TypeBounds(WildcardType, WildcardType)
else if (sym.isTerm && sym.owner == ArrayClass) {
if (sym.isClassConstructor)
tp match {
case MethodType(params, TypeRef(pre, sym1, args)) =>
- MethodType(cloneSymbolsAndModify(params, erasure(sym, _)),
- typeRef(erasure(sym, pre), sym1, args))
+ MethodType(cloneSymbolsAndModify(params, specialErasure(sym)),
+ typeRef(specialErasure(sym)(pre), sym1, args))
}
else if (sym.name == nme.apply)
tp
else if (sym.name == nme.update)
(tp: @unchecked) match {
case MethodType(List(index, tvar), restpe) =>
- MethodType(List(index.cloneSymbol.setInfo(erasure(sym, index.tpe)), tvar),
+ MethodType(List(index.cloneSymbol.setInfo(specialErasure(sym)(index.tpe)), tvar),
erasedTypeRef(UnitClass))
}
- else erasure(sym, tp)
+ else specialErasure(sym)(tp)
} else if (
sym.owner != NoSymbol &&
sym.owner.owner == ArrayClass &&
@@ -267,7 +320,7 @@ trait Erasure {
// symbol here
tp
} else {
- erasure(sym, tp)
+ specialErasure(sym)(tp)
}
}
}
diff --git a/src/compiler/scala/reflect/runtime/ScalaToJava.scala b/src/compiler/scala/reflect/runtime/ScalaToJava.scala
index 405a00de8d..87cdd11652 100644
--- a/src/compiler/scala/reflect/runtime/ScalaToJava.scala
+++ b/src/compiler/scala/reflect/runtime/ScalaToJava.scala
@@ -28,7 +28,7 @@ trait ScalaToJava extends ConversionUtil { self: SymbolTable =>
def classToJava(clazz: Symbol): jClass[_] = classCache.toJava(clazz) {
def noClass = throw new ClassNotFoundException("no Java class corresponding to "+clazz+" found")
//println("classToJava "+clazz+" "+clazz.owner+" "+clazz.owner.isPackageClass)//debug
- if (clazz.isValueClass)
+ if (clazz.isPrimitiveValueClass)
valueClassToJavaType(clazz)
else if (clazz == ArrayClass)
noClass
diff --git a/src/compiler/scala/reflect/runtime/Universe.scala b/src/compiler/scala/reflect/runtime/Universe.scala
index 700f819226..324fee87ab 100644
--- a/src/compiler/scala/reflect/runtime/Universe.scala
+++ b/src/compiler/scala/reflect/runtime/Universe.scala
@@ -37,6 +37,12 @@ class Universe extends SymbolTable {
type Position = String // source file?
val NoPosition = ""
+ definitions.AnyValClass // force it.
+
// establish root association to avoid cyclic dependency errors later
classToScala(classOf[java.lang.Object]).initialize
+
+// println("initializing definitions")
+ definitions.init()
+
}
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 248d5d675d..bc2cc8191c 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -453,12 +453,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
val global: Global.this.type = Global.this
} with Analyzer
- object extensionMethods extends {
- val global: Global.this.type = Global.this
- val runsAfter = List("typer")
- val runsRightAfter = None
- } with ExtensionMethods
-
// phaseName = "superaccessors"
object superAccessors extends {
val global: Global.this.type = Global.this
@@ -466,10 +460,17 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
val runsRightAfter = None
} with SuperAccessors
+ // phaseName = "extmethods"
+ object extensionMethods extends {
+ val global: Global.this.type = Global.this
+ val runsAfter = List("superaccessors")
+ val runsRightAfter = None
+ } with ExtensionMethods
+
// phaseName = "pickler"
object pickler extends {
val global: Global.this.type = Global.this
- val runsAfter = List("superaccessors")
+ val runsAfter = List("extmethods")
val runsRightAfter = None
} with Pickler
@@ -483,7 +484,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
// phaseName = "uncurry"
override object uncurry extends {
val global: Global.this.type = Global.this
- val runsAfter = List[String]("refchecks")
+ val runsAfter = List("refchecks")
val runsRightAfter = None
} with UnCurry
@@ -515,6 +516,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
@@ -674,6 +682,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",
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index d7159c5fa8..6d95b6ffdd 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -263,6 +263,22 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL {
)
}
+ /** Cast `tree` to type `pt` by creating
+ * one of the calls of the form
+ *
+ * x.asInstanceOf[`pt`] up to phase uncurry
+ * x.asInstanceOf[`pt`]() if after uncurry but before erasure
+ * x.$asInstanceOf[`pt`]() if at or after erasure
+ */
+ def mkCast(tree: Tree, pt: Type): Tree = {
+ debuglog("casting " + tree + ":" + tree.tpe + " to " + pt + " at phase: " + phase)
+ assert(!tree.tpe.isInstanceOf[MethodType], tree)
+ assert(pt eq pt.normalize, tree +" : "+ debugString(pt) +" ~>"+ debugString(pt.normalize))
+ atPos(tree.pos) {
+ mkAsInstanceOf(tree, pt, any = !phase.next.erasedTypes, wrapInApply = isAtPhaseAfter(currentRun.uncurryPhase))
+ }
+ }
+
/** Generate a cast for tree Tree representing Array with
* elem type elemtp to expected type pt.
*/
@@ -272,6 +288,25 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL {
else
mkCast(tree, pt)
+ def mkZeroContravariantAfterTyper(tp: Type): Tree = {
+ // contravariant -- for replacing an argument in a method call
+ // must use subtyping, as otherwise we miss types like `Any with Int`
+ val tree =
+ if (NullClass.tpe <:< tp) Literal(Constant(null))
+ else if (UnitClass.tpe <:< tp) Literal(Constant())
+ else if (BooleanClass.tpe <:< tp) Literal(Constant(false))
+ else if (FloatClass.tpe <:< tp) Literal(Constant(0.0f))
+ else if (DoubleClass.tpe <:< tp) Literal(Constant(0.0d))
+ else if (ByteClass.tpe <:< tp) Literal(Constant(0.toByte))
+ else if (ShortClass.tpe <:< tp) Literal(Constant(0.toShort))
+ else if (IntClass.tpe <:< tp) Literal(Constant(0))
+ else if (LongClass.tpe <:< tp) Literal(Constant(0L))
+ else if (CharClass.tpe <:< tp) Literal(Constant(0.toChar))
+ else mkCast(Literal(Constant(null)), tp)
+
+ tree
+ }
+
/** Translate names in Select/Ident nodes to type names.
*/
def convertToTypeName(tree: Tree): Option[RefTree] = tree match {
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/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index ad87889145..a1d3846557 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -34,6 +34,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
@@ -149,6 +155,8 @@ trait Trees extends reflect.internal.Trees { self: Global =>
traverser.traverse(definition)
case SelectFromArray(qualifier, selector, erasure) =>
traverser.traverse(qualifier)
+ case InjectDerivedValue(arg) =>
+ traverser.traverse(arg)
case ReferenceToBoxed(idt) =>
traverser.traverse(idt)
case TypeTreeWithDeferredRefCheck() =>
@@ -159,6 +167,7 @@ trait Trees extends reflect.internal.Trees { self: Global =>
trait TreeCopier extends super.TreeCopierOps {
def DocDef(tree: Tree, comment: DocComment, definition: Tree): DocDef
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
}
@@ -171,6 +180,8 @@ trait Trees extends reflect.internal.Trees { self: Global =>
new DocDef(comment, definition).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 {
@@ -189,6 +200,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
@@ -217,6 +233,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 })
@@ -333,6 +352,7 @@ trait Trees extends reflect.internal.Trees { self: Global =>
case DocDef(comment, defn) => (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/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index cd19fca0b0..ab6125df61 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -249,6 +249,8 @@ self =>
final val InBlock = 1
final val InTemplate = 2
+ lazy val ScalaValueClassNames: Set[Name] = definitions.scalaValueClassesSet map (_.name)
+
import nme.raw
abstract class Parser extends ParserCommon {
@@ -2722,23 +2724,6 @@ self =>
* }}}
*/
def templateOpt(mods: Modifiers, name: Name, constrMods: Modifiers, vparamss: List[List[ValDef]], tstart: Int): Template = {
- /** Extra parents for case classes. */
- def caseParents() = (
- if (mods.isCase) {
- val arity = if (vparamss.isEmpty || vparamss.head.isEmpty) 0 else vparamss.head.size
- productConstr :: serializableConstr :: {
- Nil
- // if (arity == 0 || settings.YnoProductN.value) Nil
- // else List(
- // AppliedTypeTree(
- // productConstrN(arity),
- // vparamss.head map (vd => vd.tpt.duplicate setPos vd.tpt.pos.focus)
- // )
- // )
- }
- }
- else Nil
- )
val (parents0, argss, self, body) = (
if (in.token == EXTENDS || in.token == SUBTYPE && mods.hasTraitFlag) {
in.nextToken()
@@ -2750,29 +2735,27 @@ self =>
(List(), List(List()), self, body)
}
)
-
+ def anyrefParents() = {
+ val caseParents = if (mods.isCase) List(productConstr, serializableConstr) else Nil
+ parents0 ::: caseParents match {
+ case Nil => List(scalaAnyRefConstr)
+ case ps => ps
+ }
+ }
+ def anyvalConstructor() = (
+ // Not a well-formed constructor, has to be finished later - see note
+ // regarding AnyVal constructor in AddInterfaces.
+ DefDef(NoMods, nme.CONSTRUCTOR, Nil, List(Nil), TypeTree(), Block(Nil, Literal(Constant())))
+ )
val tstart0 = if (body.isEmpty && in.lastOffset < tstart) in.lastOffset else tstart
+
atPos(tstart0) {
- if (inScalaPackage && name == tpnme.AnyVal) {
- // Not a well-formed constructor, has to be finished later - see note
- // regarding AnyVal constructor in AddInterfaces.
- val constructor = DefDef(NoMods, nme.CONSTRUCTOR, Nil, List(Nil), TypeTree(), Block(Nil, Literal(Constant())))
- Template(parents0, self, constructor :: body)
- }
- else if (isPrimitiveType(name))
- Template(List(scalaAnyValConstr), self, body)
- else if (parents0 exists isReferenceToAnyVal) {
- // @inline and other restrictions enforced in refchecks
- Template(parents0, self, body)
- }
- else {
- val casePs = caseParents()
- val parents = parents0 match {
- case Nil if casePs.isEmpty => List(scalaAnyRefConstr)
- case _ => parents0 ++ casePs
- }
- Template(parents, self, constrMods, vparamss, argss, body, o2p(tstart))
- }
+ // [Martin to Paul: This needs to be refined. We should only include the 9 primitive classes,
+ // not any other value classes that happen to be defined in the Scala package.
+ if (inScalaRootPackage && (name == tpnme.AnyVal || (ScalaValueClassNames contains name)))
+ Template(parents0, self, anyvalConstructor :: body)
+ else
+ Template(anyrefParents, self, constrMods, vparamss, argss, body, o2p(tstart))
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index c609f126d3..4c77cb7082 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -746,7 +746,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
if ((settings.check.value contains "genjvm")) {
val normalizedTpe = beforeErasure(erasure.prepareSigMap(memberTpe))
val bytecodeTpe = owner.thisType.memberInfo(sym)
- if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym, normalizedTpe) =:= bytecodeTpe)) {
+ if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym)(normalizedTpe) =:= bytecodeTpe)) {
clasz.cunit.warning(sym.pos,
"""|compiler bug: created generic signature for %s in %s that does not conform to its erasure
|signature: %s
diff --git a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala
index e72a0007a0..ef17367ce0 100644
--- a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala
+++ b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala
@@ -20,7 +20,7 @@ trait MatrixAdditions extends ast.TreeDSL {
import CODE._
import Debug._
import treeInfo._
- import definitions.{ isValueClass }
+ import definitions.{ isPrimitiveValueClass }
/** The Squeezer, responsible for all the squeezing.
*/
@@ -141,7 +141,7 @@ trait MatrixAdditions extends ast.TreeDSL {
(sym.isMutable) && // indicates that have not yet checked exhaustivity
!(sym hasFlag NO_EXHAUSTIVE) && // indicates @unchecked
(sym.tpe.typeSymbol.isSealed) &&
- !isValueClass(sym.tpe.typeSymbol) // make sure it's not a primitive, else (5: Byte) match { case 5 => ... } sees no Byte
+ !isPrimitiveValueClass(sym.tpe.typeSymbol) // make sure it's not a primitive, else (5: Byte) match { case 5 => ... } sees no Byte
}
private lazy val inexhaustives: List[List[Combo]] = {
@@ -155,7 +155,7 @@ trait MatrixAdditions extends ast.TreeDSL {
pv.tpe.typeSymbol.sealedDescendants.toList sortBy (_.sealedSortName)
// symbols which are both sealed and abstract need not be covered themselves, because
// all of their children must be and they cannot otherwise be created.
- filterNot (x => x.isSealed && x.isAbstractClass && !isValueClass(x))
+ filterNot (x => x.isSealed && x.isAbstractClass && !isPrimitiveValueClass(x))
// have to filter out children which cannot match: see ticket #3683 for an example
filter (_.tpe matchesPattern pv.tpe)
)
diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
index 71d595c9c4..555d0700ae 100644
--- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
+++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
@@ -11,7 +11,7 @@ import Flags._
import scala.collection.{ mutable, immutable }
import collection.mutable.ListBuffer
-abstract class AddInterfaces extends InfoTransform {
+abstract class AddInterfaces extends InfoTransform { self: Erasure =>
import global._ // the global environment
import definitions._ // standard classes and methods
@@ -21,14 +21,6 @@ abstract class AddInterfaces extends InfoTransform {
*/
override def phaseNewFlags: Long = lateDEFERRED | lateINTERFACE
- /** Type reference after erasure; defined in Erasure.
- */
- def erasedTypeRef(sym: Symbol): Type
-
- /** Erasure calculation; defined in Erasure.
- */
- def erasure(sym: Symbol, tpe: Type): Type
-
/** A lazily constructed map that associates every non-interface trait with
* its implementation class.
*/
@@ -176,14 +168,14 @@ abstract class AddInterfaces extends InfoTransform {
/** If `tp` refers to a non-interface trait, return a
* reference to its implementation class. Otherwise return `tp`.
*/
- def mixinToImplClass(tp: Type): Type = erasure(sym,
+ def mixinToImplClass(tp: Type): Type = erasure(sym) {
tp match { //@MATN: no normalize needed (comes after erasure)
case TypeRef(pre, sym, _) if sym.needsImplClass =>
typeRef(pre, implClass(sym), Nil)
case _ =>
tp
}
- )
+ }
def implType(tp: Type): Type = tp match {
case ClassInfoType(parents, decls, _) =>
assert(phase == implClassPhase, tp)
@@ -303,21 +295,19 @@ abstract class AddInterfaces extends InfoTransform {
yield mixinConstructorCall(implClass(mc))
}
tree match {
+ case Block(Nil, expr) =>
+ // AnyVal constructor - have to provide a real body so the
+ // jvm doesn't throw a VerifyError. But we can't add the
+ // body until now, because the typer knows that Any has no
+ // constructor and won't accept a call to super.init.
+ assert((clazz isSubClass AnyValClass) || clazz.info.parents.isEmpty, clazz)
+ val superCall = Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), Nil)
+ Block(List(superCall), expr)
+
case Block(stats, expr) =>
// needs `hasSymbol` check because `supercall` could be a block (named / default args)
- stats span (t => t.hasSymbolWhich(_ hasFlag PRESUPER)) match {
- case (presuper, supercall :: rest) =>
- stats span (t => t.hasSymbolWhich(_ hasFlag PRESUPER))
- treeCopy.Block(tree, presuper ::: (supercall :: mixinConstructorCalls ::: rest), expr)
- case (Nil, Nil) =>
- assert(clazz eq AnyValClass, clazz)
- // AnyVal constructor - have to provide a real body so the
- // jvm doesn't throw a VerifyError. But we can't add the
- // body until now, because the typer knows that Any has no
- // constructor and won't accept a call to super.init.
- val superCall = Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), Nil)
- Block(List(superCall), Literal(Constant()))
- }
+ val (presuper, supercall :: rest) = stats span (t => t.hasSymbolWhich(_ hasFlag PRESUPER))
+ treeCopy.Block(tree, presuper ::: (supercall :: mixinConstructorCalls ::: rest), expr)
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index d04c6115ca..8ed44b5a31 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -94,7 +94,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
localTyper.typedPos(pos)(tree)
/** A value class is defined to be only Java-compatible values: unit is
- * not part of it, as opposed to isValueClass in definitions. scala.Int is
+ * not part of it, as opposed to isPrimitiveValueClass in definitions. scala.Int is
* a value class, java.lang.Integer is not. */
def isJavaValueClass(sym: Symbol) = boxedClass contains sym
def isJavaValueType(tp: Type) = isJavaValueClass(tp.typeSymbol)
@@ -551,7 +551,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
case Literal(c) if (c.tag == ClassTag) && !forMSIL=>
val tpe = c.typeValue
typedWithPos(tree.pos) {
- if (isValueClass(tpe.typeSymbol)) {
+ if (isPrimitiveValueClass(tpe.typeSymbol)) {
if (tpe.typeSymbol == UnitClass)
REF(BoxedUnit_TYPE)
else
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index 445b21c7ad..4f833c82d3 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -46,7 +46,7 @@ abstract class Constructors extends Transform with ast.TreeDSL {
val constrInfo: ConstrInfo = {
stats find (_.symbol.isPrimaryConstructor) match {
case Some(ddef @ DefDef(_, _, _, List(vparams), _, rhs @ Block(_, _))) =>
- ConstrInfo(ddef, vparams map (_.symbol), rhs)
+ ConstrInfo(ddef, vparams map (_.symbol), rhs)
case x =>
// AnyVal constructor is OK
assert(clazz eq AnyValClass, "no constructor in template: impl = " + impl)
@@ -568,7 +568,7 @@ abstract class Constructors extends Transform with ast.TreeDSL {
override def transform(tree: Tree): Tree =
tree match {
- case ClassDef(_,_,_,_) if !tree.symbol.isInterface && !isValueClass(tree.symbol) =>
+ case ClassDef(_,_,_,_) if !tree.symbol.isInterface && !isPrimitiveValueClass(tree.symbol) =>
deriveClassDef(tree)(transformClassTemplate)
case _ =>
super.transform(tree)
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 70364070ff..a98cd5c6b1 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -31,33 +31,6 @@ abstract class Erasure extends AddInterfaces
// -------- erasure on types --------------------------------------------------------
- // A type function from T => Class[U], used to determine the return
- // type of getClass calls. The returned type is:
- //
- // 1. If T is a value type, Class[T].
- // 2. If T is a phantom type (Any or AnyVal), Class[_].
- // 3. If T is a local class, Class[_ <: |T|].
- // 4. Otherwise, Class[_ <: T].
- //
- // Note: AnyVal cannot be Class[_ <: AnyVal] because if the static type of the
- // receiver is AnyVal, it implies the receiver is boxed, so the correct
- // class object is that of java.lang.Integer, not Int.
- //
- // TODO: If T is final, return type could be Class[T]. Should it?
- def getClassReturnType(tpe: Type): Type = {
- if (phase.erasedTypes) ClassClass.tpe else {
- val tp = tpe.widen.normalize
- val sym = tp.typeSymbol
-
- if (isValueClass(sym)) ClassType(tp)
- else boundedClassType(
- if (isPhantomClass(sym)) ObjectClass.tpe
- else if (sym.isLocalClass) intersectionDominator(tp.parents)
- else tp
- )
- }
- }
-
// convert a numeric with a toXXX method
def numericConversion(tree: Tree, numericSym: Symbol): Tree = {
val mname = newTermName("to" + numericSym.name)
@@ -257,7 +230,7 @@ abstract class Erasure extends AddInterfaces
// Anything which could conceivably be a module (i.e. isn't known to be
// a type parameter or similar) must go through here or the signature is
// likely to end up with Foo<T>.Empty where it needs Foo<T>.Empty$.
- def fullNameInSig(sym: Symbol) = "L" + beforeIcode(sym.javaBinaryName.toString)
+ def fullNameInSig(sym: Symbol) = "L" + beforeIcode(sym.javaBinaryName)
def jsig(tp0: Type, existentiallyBound: List[Symbol] = Nil, toplevel: Boolean = false, primitiveOK: Boolean = true): String = {
val tp = tp0.dealias
@@ -294,7 +267,7 @@ abstract class Erasure extends AddInterfaces
jsig(RuntimeNothingClass.tpe)
else if (sym == NullClass)
jsig(RuntimeNullClass.tpe)
- else if (isValueClass(sym)) {
+ else if (isPrimitiveValueClass(sym)) {
if (!primitiveOK) jsig(ObjectClass.tpe)
else if (sym == UnitClass) jsig(BoxedUnitClass.tpe)
else abbrvTag(sym).toString
@@ -317,7 +290,7 @@ abstract class Erasure extends AddInterfaces
)
)
}
- else jsig(erasure(sym0, tp), existentiallyBound, toplevel, primitiveOK)
+ else jsig(erasure(sym0)(tp), existentiallyBound, toplevel, primitiveOK)
case PolyType(tparams, restpe) =>
assert(tparams.nonEmpty)
val poly = if (toplevel) polyParamSig(tparams) else ""
@@ -337,7 +310,7 @@ abstract class Erasure extends AddInterfaces
println("something's wrong: "+sym0+":"+sym0.tpe+" has a bounded wildcard type")
jsig(bounds.hi, existentiallyBound, toplevel, primitiveOK)
case _ =>
- val etp = erasure(sym0, tp)
+ val etp = erasure(sym0)(tp)
if (etp eq tp) throw new UnknownSig
else jsig(etp)
}
@@ -396,36 +369,79 @@ 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.isDerivedValueClass &&
+ 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.isDerivedValueClass) =>
+ 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 isPrimitiveValueType(tpe: Type) = isPrimitiveValueClass(tpe.typeSymbol)
+
+ private def isErasedValueType(tpe: Type) = tpe.isInstanceOf[ErasedValueType]
+
+ 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 = {
+ 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(_, _, _) =>
- val ldef = deriveLabelDef(tree)(box)
+ val ldef = deriveLabelDef(tree)(box1)
ldef setType ldef.rhs.tpe
case _ =>
- typedPos(tree.pos)(tree.tpe.typeSymbol match {
+ val tree1 = tree.tpe match {
+ case ErasedValueType(clazz) =>
+ tree match {
+ case Unboxed(arg) if arg.tpe.typeSymbol == clazz =>
+ log("shortcircuiting unbox -> box "+arg); arg
+ case _ =>
+ New(clazz, cast(tree, underlyingOfValueClass(clazz)))
+ }
+ case _ =>
+ tree.tpe.typeSymbol match {
case UnitClass =>
if (treeInfo isExprSafeToInline tree) REF(BoxedUnit_UNIT)
else BLOCK(tree, REF(BoxedUnit_UNIT))
@@ -445,7 +461,15 @@ abstract class Erasure extends AddInterfaces
case _ =>
(REF(boxMethod(x)) APPLY tree) setPos (tree.pos) setType ObjectClass.tpe
}
- })
+ }
+ }
+ 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`.
@@ -454,7 +478,7 @@ abstract class Erasure extends AddInterfaces
* @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.
@@ -464,7 +488,19 @@ abstract class Erasure extends AddInterfaces
val ldef = deriveLabelDef(tree)(unbox(_, pt))
ldef setType ldef.rhs.tpe
case _ =>
- typedPos(tree.pos)(pt.typeSymbol match {
+ val tree1 = pt match {
+ case ErasedValueType(clazz) =>
+ tree match {
+ case Boxed(arg) if arg.tpe.isInstanceOf[ErasedValueType] =>
+ 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 =>
if (treeInfo isExprSafeToInline tree) UNIT
else BLOCK(tree, UNIT)
@@ -472,7 +508,9 @@ abstract class Erasure extends AddInterfaces
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)
}
/** Generate a synthetic cast operation from tree.tpe to pt.
@@ -487,9 +525,6 @@ abstract class Erasure extends AddInterfaces
else gen.mkAttributedCast(tree, pt)
}
- private def isUnboxedValueMember(sym: Symbol) =
- sym != NoSymbol && isValueClass(sym.owner)
-
/** Adapt `tree` to expected type `pt`.
*
* @param tree the given tree
@@ -501,29 +536,30 @@ abstract class Erasure extends AddInterfaces
log("adapting " + tree + ":" + tree.tpe + " : " + tree.tpe.parents + " to " + pt)//debug
if (tree.tpe <:< pt)
tree
- else if (isValueClass(tree.tpe.typeSymbol) && !isValueClass(pt.typeSymbol))
- adaptToType(box(tree), pt)
- else if (tree.tpe.isInstanceOf[MethodType] && tree.tpe.params.isEmpty) {
+ 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 (isValueClass(pt.typeSymbol) && !isValueClass(tree.tpe.typeSymbol))
+// } else if (pt <:< tree.tpe)
+// cast(tree, pt)
+ } else if (isPrimitiveValueType(pt) && !isPrimitiveValueType(tree.tpe))
adaptToType(unbox(tree, pt), pt)
else
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.
* - `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.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
@@ -533,22 +569,34 @@ 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 =>
val qual1 = typedQualifier(qual, NOmode, ObjectClass.tpe) // need to have an expected type, see #3037
val qualClass = qual1.tpe.typeSymbol
- val targClass = targ.tpe.typeSymbol
/*
+ val targClass = targ.tpe.typeSymbol
+
if (isNumericValueClass(qualClass) && isNumericValueClass(targClass))
// convert numeric type casts
atPos(tree.pos)(Apply(Select(qual1, "to" + targClass.name), List()))
else
*/
- if (isValueClass(targClass)) unbox(qual1, targ.tpe)
+ if (isPrimitiveValueType(targ.tpe) || isErasedValueType(targ.tpe)) unbox(qual1, targ.tpe)
else tree
- case Select(qual, name) if (name != nme.CONSTRUCTOR) =>
- if (tree.symbol == NoSymbol)
+ 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 _ =>
+ }
+ tree
+ case Select(qual, name) =>
+ if (tree.symbol == NoSymbol) {
+ tree
+ } else if (name == nme.CONSTRUCTOR) {
+ if (tree.symbol.owner == AnyValClass) tree.symbol = ObjectClass.primaryConstructor
tree
- else if (tree.symbol == Any_asInstanceOf)
+ } else if (tree.symbol == Any_asInstanceOf)
adaptMember(atPos(tree.pos)(Select(qual, Object_asInstanceOf)))
else if (tree.symbol == Any_isInstanceOf)
adaptMember(atPos(tree.pos)(Select(qual, Object_isInstanceOf)))
@@ -556,12 +604,13 @@ abstract class Erasure extends AddInterfaces
adaptMember(atPos(tree.pos)(Select(qual, getMember(ObjectClass, name))))
else {
var qual1 = typedQualifier(qual)
- if ((isValueClass(qual1.tpe.typeSymbol) && !isUnboxedValueMember(tree.symbol)))
- qual1 = box(qual1)
- else if (!isValueClass(qual1.tpe.typeSymbol) && isUnboxedValueMember(tree.symbol))
+ if ((isPrimitiveValueType(qual1.tpe) && !isPrimitiveValueMember(tree.symbol)) ||
+ isErasedValueType(qual1.tpe))
+ qual1 = box(qual1, "owner "+tree.symbol.owner)
+ else if (!isPrimitiveValueType(qual1.tpe) && isPrimitiveValueMember(tree.symbol))
qual1 = unbox(qual1, tree.symbol.owner.tpe)
- if (isValueClass(tree.symbol.owner) && !isValueClass(qual1.tpe.typeSymbol))
+ 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);
@@ -590,7 +639,16 @@ abstract class Erasure extends AddInterfaces
*/
override protected def typed1(tree: Tree, mode: Int, pt: Type): Tree = {
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
+
+ case _ =>
super.typed1(adaptMember(tree), mode, pt)
+ }
} catch {
case er: TypeError =>
Console.println("exception when typing " + tree)
@@ -646,6 +704,7 @@ abstract class Erasure extends AddInterfaces
* but their erased types are the same.
*/
private def checkNoDoubleDefs(root: Symbol) {
+ def afterErasure[T](op: => T): T = atPhase(phase.next.next)(op)
def doubleDefError(sym1: Symbol, sym2: Symbol) {
// the .toString must also be computed at the earlier phase
val tpe1 = afterRefchecks(root.thisType.memberType(sym1))
@@ -750,7 +809,7 @@ abstract class Erasure extends AddInterfaces
val other = opc.overridden
//println("bridge? " + member + ":" + member.tpe + member.locationString + " to " + other + ":" + other.tpe + other.locationString)//DEBUG
if (beforeExplicitOuter(!member.isDeferred)) {
- val otpe = erasure(owner, other.tpe)
+ val otpe = erasure(owner)(other.tpe)
val bridgeNeeded = afterErasure (
!(other.tpe =:= member.tpe) &&
!(deconstMap(other.tpe) =:= deconstMap(member.tpe)) &&
@@ -795,7 +854,7 @@ abstract class Erasure extends AddInterfaces
IF (typeTest) THEN bridgingCall ELSE REF(NoneModule)
} else bridgingCall
});
- debuglog("generating bridge from " + other + "(" + Flags.flagsToString(bridge.flags) + ")" + ":" + otpe + other.locationString + " to " + member + ":" + erasure(owner, member.tpe) + member.locationString + " =\n " + bridgeDef);
+ debuglog("generating bridge from " + other + "(" + Flags.flagsToString(bridge.flags) + ")" + ":" + otpe + other.locationString + " to " + member + ":" + erasure(owner)(member.tpe) + member.locationString + " =\n " + bridgeDef);
bridgeDef
}
} :: bridges
@@ -841,6 +900,7 @@ abstract class Erasure extends AddInterfaces
* - Given a selection q.s, where the owner of `s` is not accessible but the
* type symbol of q's type qT is accessible, insert a cast (q.asInstanceOf[qT]).s
* This prevents illegal access errors (see #4283).
+ * - Remove all instance creations new C(arg) where C is an inlined class.
* - Reset all other type attributes to null, thus enforcing a retyping.
*/
private val preTransformer = new TypingTransformer(unit) {
@@ -866,7 +926,7 @@ abstract class Erasure extends AddInterfaces
gen.mkMethodCall(
qual1(),
fun.symbol,
- List(erasure(fun.symbol, arg.tpe)),
+ List(specialErasure(fun.symbol)(arg.tpe)),
Nil
),
isArrayTest(qual1())
@@ -899,7 +959,7 @@ abstract class Erasure extends AddInterfaces
// need to do the cast in adaptMember
treeCopy.Apply(
tree,
- SelectFromArray(qual, name, erasure(tree.symbol, qual.tpe)).copyAttrs(fn),
+ SelectFromArray(qual, name, erasure(tree.symbol)(qual.tpe)).copyAttrs(fn),
args)
}
case Apply(fn @ Select(qual, _), Nil) if interceptedMethods(fn.symbol) =>
@@ -918,11 +978,13 @@ abstract class Erasure extends AddInterfaces
}
}
// Rewrite 5.getClass to ScalaRunTime.anyValClass(5)
- else if (isValueClass(qual.tpe.typeSymbol))
+ else if (isPrimitiveValueClass(qual.tpe.typeSymbol))
global.typer.typed(gen.mkRuntimeCall(nme.anyValClass, List(qual)))
else
tree
+ case Apply(Select(New(tpt), nme.CONSTRUCTOR), List(arg)) if (tpt.tpe.typeSymbol.isDerivedValueClass) =>
+ InjectDerivedValue(arg) setSymbol tpt.tpe.typeSymbol
case Apply(fn, args) =>
def qualifier = fn match {
case Select(qual, _) => qual
@@ -942,7 +1004,7 @@ abstract class Erasure extends AddInterfaces
else if (fn.symbol == Any_isInstanceOf) {
fn match {
case TypeApply(sel @ Select(qual, name), List(targ)) =>
- if (qual.tpe != null && isValueClass(qual.tpe.typeSymbol) && targ.tpe != null && targ.tpe <:< AnyRefClass.tpe)
+ if (qual.tpe != null && isPrimitiveValueClass(qual.tpe.typeSymbol) && targ.tpe != null && targ.tpe <:< AnyRefClass.tpe)
unit.error(sel.pos, "isInstanceOf cannot test if value types are references.")
def mkIsInstanceOf(q: () => Tree)(tp: Type): Tree =
@@ -979,7 +1041,7 @@ abstract class Erasure extends AddInterfaces
}
} else if (fn.symbol.owner.isRefinementClass && !fn.symbol.isOverridingSymbol) {
ApplyDynamic(qualifier, args) setSymbol fn.symbol setPos tree.pos
- } else if (fn.symbol.owner.isInlineClass && extensionMethods.hasExtension(fn.symbol)) {
+ } else if (fn.symbol.isMethodWithExtension) {
Apply(gen.mkAttributedRef(extensionMethods.extensionMethod(fn.symbol)), qualifier :: args)
} else {
tree
@@ -1016,7 +1078,11 @@ abstract class Erasure extends AddInterfaces
case Literal(ct) if ct.tag == ClassTag
&& ct.typeValue.typeSymbol != definitions.UnitClass =>
- treeCopy.Literal(tree, Constant(erasure(NoSymbol, ct.typeValue)))
+ val erased = ct.typeValue match {
+ case TypeRef(pre, clazz, args) if clazz.isDerivedValueClass => scalaErasure.eraseNormalClassRef(pre, clazz)
+ case tpe => specialScalaErasure(tpe)
+ }
+ treeCopy.Literal(tree, Constant(erased))
case _ =>
tree
@@ -1034,10 +1100,13 @@ abstract class Erasure extends AddInterfaces
val tree1 = preErase(tree)
tree1 match {
case EmptyTree | TypeTree() =>
- tree1 setType erasure(NoSymbol, tree1.tpe)
+ tree1 setType specialScalaErasure(tree1.tpe)
+ case ArrayValue(elemtpt, trees) =>
+ treeCopy.ArrayValue(
+ tree1, elemtpt setType specialScalaErasure.applyInArray(elemtpt.tpe), trees map transform) setType null
case DefDef(_, _, _, _, tpt, _) =>
val result = super.transform(tree1) setType null
- tpt.tpe = erasure(tree1.symbol, tree1.symbol.tpe).resultType
+ tpt.tpe = specialErasure(tree1.symbol)(tree1.symbol.tpe).resultType
result
case _ =>
super.transform(tree1) setType null
@@ -1051,6 +1120,7 @@ abstract class Erasure extends AddInterfaces
*/
override def transform(tree: Tree): Tree = {
val tree1 = preTransformer.transform(tree)
+ log("tree after pretransform: "+tree1)
afterErasure {
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 c308a3633e..455eb1d3b1 100644
--- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
@@ -1,9 +1,7 @@
/* NSC -- new Scala compiler
* Copyright 2005-2011 LAMP/EPFL
- * @author Gilles Dubochet
* @author Martin Odersky
*/
-
package scala.tools.nsc
package transform
@@ -16,7 +14,8 @@ import scala.runtime.ScalaRunTime.{ isAnyVal, isTuple }
import sun.tools.tree.OrExpression
/**
- * Perform Step 1 in the inline classes SIP
+ * Perform Step 1 in the inline classes SIP: Creates extension methods for all
+ * methods in a value class, except parameter or super accessors, or constructors.
*
* @author Martin Odersky
* @version 2.10
@@ -33,9 +32,6 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
def newTransformer(unit: CompilationUnit): Transformer =
new Extender(unit)
- def hasExtension(sym: Symbol) =
- !sym.isParamAccessor && !sym.isConstructor
-
/** Generate stream of possible names for the extension version of given instance method `imeth`.
* If the method is not overloaded, this stream consists of just "extension$imeth".
* If the method is overloaded, the stream has as first element "extensionX$imeth", where X is the
@@ -68,7 +64,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) =>
@@ -87,13 +83,13 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
val thisParam = extensionMeth.newValueParameter(nme.SELF, extensionMeth.pos) setInfo thisParamType
def transform(clonedType: Type): Type = clonedType match {
case MethodType(params, restpe) =>
- // I assume it was a bug that this was dropping params...
- MethodType(thisParam :: params, clonedType)
+ // I assume it was a bug that this was dropping params... [Martin]: No, it wasn't; it's curried.
+ MethodType(List(thisParam), clonedType)
case NullaryMethodType(restpe) =>
MethodType(List(thisParam), restpe)
}
val GenPolyType(tparams, restpe) = origInfo cloneInfo extensionMeth
- GenPolyType(tparams ::: newTypeParams, transform(restpe))
+ GenPolyType(tparams ::: newTypeParams, transform(restpe) substSym (clazz.typeParams, newTypeParams))
}
private def allParams(tpe: Type): List[Symbol] = tpe match {
@@ -104,29 +100,29 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
override def transform(tree: Tree): Tree = {
tree match {
case Template(_, _, _) =>
- if (currentOwner.isInlineClass) {
+ if (currentOwner.isDerivedValueClass) {
extensionDefs(currentOwner.companionModule) = new mutable.ListBuffer[Tree]
super.transform(tree)
- }
- else tree
- case DefDef(mods, name, tparams, vparamss, tpt, rhs)
- if currentOwner.isInlineClass && hasExtension(tree.symbol) =>
+ } else if (currentOwner.isStaticOwner) {
+ super.transform(tree)
+ } else tree
+ case DefDef(mods, name, tparams, vparamss, tpt, rhs) if tree.symbol.isMethodWithExtension =>
val companion = currentOwner.companionModule
val origMeth = tree.symbol
val extensionName = extensionNames(origMeth).head
- val extensionMeth = companion.moduleClass.newMethod(extensionName, origMeth.pos, origMeth.flags & ~OVERRIDE | FINAL)
+ val extensionMeth = companion.moduleClass.newMethod(extensionName, origMeth.pos, origMeth.flags & ~OVERRIDE & ~PROTECTED | FINAL)
.setAnnotations(origMeth.annotations)
companion.info.decls.enter(extensionMeth)
val newInfo = extensionMethInfo(extensionMeth, origMeth.info, currentOwner)
extensionMeth setInfo newInfo
- log("Inline class %s spawns extension method.\n Old: %s\n New: %s".format(
+ log("Value class %s spawns extension method.\n Old: %s\n New: %s".format(
currentOwner,
- origMeth.defString,
+ origMeth.defString,
extensionMeth.defString)) // extensionMeth.defStringSeenAs(origInfo
def thisParamRef = gen.mkAttributedIdent(extensionMeth.info.params.head setPos extensionMeth.pos)
val GenPolyType(extensionTpeParams, extensionMono) = extensionMeth.info
- val origTpeParams = origMeth.typeParams ::: currentOwner.typeParams
+ val origTpeParams = (tparams map (_.symbol)) ::: currentOwner.typeParams
val extensionBody = rhs
.substTreeSyms(origTpeParams, extensionTpeParams)
.substTreeSyms(vparamss.flatten map (_.symbol), allParams(extensionMono).tail)
@@ -156,8 +152,8 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
case stat @ ModuleDef(mods, name, tmpl @ Template(parents, self, body)) =>
extensionDefs.remove(stat.symbol) match {
case Some(buf) =>
- val extensionDefs = buf.toList map { mdef => atOwner(stat.symbol) { localTyper.typed(mdef) }}
- treeCopy.ModuleDef(stat, mods, name, treeCopy.Template(tmpl, parents, self, body ++ buf))
+ val extensionDefs = buf.toList map { mdef => atOwner(stat.symbol) { localTyper.typed(mdef) } }
+ treeCopy.ModuleDef(stat, mods, name, treeCopy.Template(tmpl, parents, self, body ++ extensionDefs))
case None =>
stat
}
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index 570eaba3a9..13ca8e55bc 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -25,7 +25,7 @@ abstract class LambdaLift extends InfoTransform {
if (sym.isCapturedVariable) {
val symClass = tpe.typeSymbol
def refType(valueRef: Map[Symbol, Symbol], objectRefClass: Symbol) =
- if (isValueClass(symClass) && symClass != UnitClass) valueRef(symClass).tpe
+ if (isPrimitiveValueClass(symClass) && symClass != UnitClass) valueRef(symClass).tpe
else if (erasedTypes) objectRefClass.tpe
else appliedType(objectRefClass.typeConstructor, List(tpe))
if (sym.hasAnnotation(VolatileAttr)) refType(volatileRefClass, VolatileObjectRefClass)
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index c9794cc20f..d1e95e3a27 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -448,7 +448,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
if ((sym.hasAccessorFlag || (sym.isTerm && !sym.isMethod))
&& sym.isPrivate
&& !(currentOwner.isGetter && currentOwner.accessed == sym) // getter
- && !definitions.isValueClass(sym.tpe.resultType.typeSymbol)
+ && !definitions.isPrimitiveValueClass(sym.tpe.resultType.typeSymbol)
&& sym.owner == templ.symbol.owner
&& !sym.isLazy
&& !tree.isDef) {
@@ -520,7 +520,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
localTyper = erasure.newTyper(rootContext.make(tree, currentOwner))
afterMixin(currentOwner.owner.info)//todo: needed?
- if (!currentOwner.isTrait && !isValueClass(currentOwner))
+ if (!currentOwner.isTrait && !isPrimitiveValueClass(currentOwner))
addMixedinMembers(currentOwner, unit)
else if (currentOwner hasFlag lateINTERFACE)
addLateInterfaceMembers(currentOwner)
diff --git a/src/compiler/scala/tools/nsc/transform/PostErasure.scala b/src/compiler/scala/tools/nsc/transform/PostErasure.scala
new file mode 100644
index 0000000000..ef158a71f6
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/transform/PostErasure.scala
@@ -0,0 +1,68 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2012 LAMP/EPFL
+ * @author Martin odersky
+ */
+package scala.tools.nsc
+package transform
+
+/** This phase maps ErasedValueTypes to the underlying unboxed representation and
+ * performs peephole optimizations.
+ */
+trait PostErasure extends InfoTransform with TypingTransformers {
+
+ val global: Global
+ import global._
+ import definitions._
+
+ val phaseName: String = "posterasure"
+
+ def newTransformer(unit: CompilationUnit): Transformer = new PostErasureTransformer(unit)
+ override def changesBaseClasses = false
+
+ object elimErasedValueType extends TypeMap {
+ def apply(tp: Type) = tp match {
+ case ErasedValueType(clazz) => erasure.underlyingOfValueClass(clazz)
+ case _ => mapOver(tp)
+ }
+ }
+
+ def transformInfo(sym: Symbol, tp: Type) = elimErasedValueType(tp)
+
+ class PostErasureTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
+
+ override def transform(tree: Tree) =
+ super.transform(tree) setType elimErasedValueType(tree.tpe) match {
+ case // new C(arg).underlying ==> arg
+ Apply(sel @ Select(
+ Apply(Select(New(tpt), nme.CONSTRUCTOR), List(arg)),
+ acc), List())
+ if atPhase(currentRun.erasurePhase) {
+ tpt.tpe.typeSymbol.isDerivedValueClass &&
+ sel.symbol == tpt.tpe.typeSymbol.firstParamAccessor
+ } =>
+ if (settings.debug.value) log("Removing "+tree+" -> "+arg)
+ arg
+ case // new C(arg1) == new C(arg2) ==> arg1 == arg2
+ Apply(sel @ Select(
+ Apply(Select(New(tpt1), nme.CONSTRUCTOR), List(arg1)),
+ cmp),
+ List(Apply(Select(New(tpt2), nme.CONSTRUCTOR), List(arg2))))
+ if atPhase(currentRun.erasurePhase) {
+ tpt1.tpe.typeSymbol.isDerivedValueClass &&
+ (cmp == nme.EQ || cmp == nme.NE) &&
+ tpt2.tpe.typeSymbol == tpt1.tpe.typeSymbol
+ } =>
+ val result = Apply(Select(arg1, cmp) setPos sel.pos, List(arg2)) setPos tree.pos
+ log("shortcircuiting equality "+tree+" -> "+result)
+ localTyper.typed(result)
+
+ case // arg.asInstanceOf[T] ==> arg if arg.tpe == T
+ Apply(TypeApply(cast @ Select(arg, asinstanceof), List(tpt)), List())
+ if cast.symbol == Object_asInstanceOf && arg.tpe =:= tpt.tpe => // !!! <:< ?
+ if (settings.debug.value) log("Shortening "+tree+" -> "+arg)
+ arg
+ case tree1 =>
+ tree1
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 323fecfd0a..28a9818017 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -66,7 +66,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
import definitions.{
RootClass, BooleanClass, UnitClass, ArrayClass,
- ScalaValueClasses, isValueClass, isScalaValueType,
+ ScalaValueClasses, isPrimitiveValueClass, isScalaValueType,
SpecializedClass, RepeatedParamClass, JavaRepeatedParamClass,
AnyRefClass, ObjectClass, AnyRefModule,
GroupOfSpecializable, uncheckedVarianceClass, ScalaInlineClass
@@ -123,14 +123,14 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
// then pos/spec-List.scala fails - why? Does this kind of check fail
// for similar reasons? Does `sym.isAbstractType` make a difference?
private def isSpecializedAnyRefSubtype(tp: Type, sym: Symbol) = {
- specializedOn(sym).exists(s => !isValueClass(s)) &&
- !isValueClass(tp.typeSymbol) &&
+ specializedOn(sym).exists(s => !isPrimitiveValueClass(s)) &&
+ !isPrimitiveValueClass(tp.typeSymbol) &&
isBoundedGeneric(tp)
//(tp <:< AnyRefClass.tpe)
}
private def isBoundedGeneric(tp: Type) = tp match {
case TypeRef(_, sym, _) if sym.isAbstractType => (tp <:< AnyRefClass.tpe)
- case TypeRef(_, sym, _) => !isValueClass(sym)
+ case TypeRef(_, sym, _) => !isPrimitiveValueClass(sym)
case _ => false
}
@@ -994,7 +994,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
private def unify(tp1: Type, tp2: Type, env: TypeEnv, strict: Boolean): TypeEnv = (tp1, tp2) match {
case (TypeRef(_, sym1, _), _) if isSpecialized(sym1) =>
debuglog("Unify - basic case: " + tp1 + ", " + tp2)
- if (isValueClass(tp2.typeSymbol))
+ if (isPrimitiveValueClass(tp2.typeSymbol) || isSpecializedAnyRefSubtype(tp2, sym1))
env + ((sym1, tp2))
else if (isSpecializedAnyRefSubtype(tp2, sym1))
env + ((sym1, tp2)) // env + ((sym1, AnyRefClass.tpe))
@@ -1342,7 +1342,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
val env = typeEnv(specMember)
val residualTargs = symbol.info.typeParams zip targs collect {
- case (tvar, targ) if !env.contains(tvar) || !isValueClass(env(tvar).typeSymbol) => targ
+ case (tvar, targ) if !env.contains(tvar) || !isPrimitiveValueClass(env(tvar).typeSymbol) => targ
}
ifDebug(assert(residualTargs.length == specMember.info.typeParams.length,
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 0ddacf7d36..7d1198a4a2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -1094,7 +1094,11 @@ trait Implicits {
/** Creates a tree that calls the factory method called constructor in object reflect.Manifest */
def manifestFactoryCall(constructor: String, tparg: Type, args: Tree*): Tree =
if (args contains EmptyTree) EmptyTree
- else typedPos(tree.pos.focus)(gen.mkManifestFactoryCall(full, constructor, tparg, args.toList))
+ else typedPos(tree.pos.focus) {
+ val mani = gen.mkManifestFactoryCall(full, constructor, tparg, args.toList)
+ if (settings.debug.value) println("generated manifest: "+mani) // DEBUG
+ mani
+ }
/** Creates a tree representing one of the singleton manifests.*/
def findSingletonManifest(name: String) = typedPos(tree.pos.focus) {
@@ -1119,7 +1123,7 @@ trait Implicits {
case ConstantType(value) =>
manifestOfType(tp1.deconst, full)
case TypeRef(pre, sym, args) =>
- if (isValueClass(sym) || isPhantomClass(sym)) {
+ if (isPrimitiveValueClass(sym) || isPhantomClass(sym)) {
findSingletonManifest(sym.name.toString)
} else if (sym == ObjectClass || sym == AnyRefClass) {
findSingletonManifest("Object")
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index c0c801910c..8b3bc253fd 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -196,6 +196,10 @@ trait Infer {
/* -- Error Messages --------------------------------------------------- */
def setError[T <: Tree](tree: T): T = {
+ if (settings.debug.value) { // DEBUG
+ println("set error: "+tree);
+ throw new Error()
+ }
def name = newTermName("<error: " + tree.symbol + ">")
def errorClass = if (context.reportErrors) context.owner.newErrorClass(name.toTypeName) else stdErrorClass
def errorValue = if (context.reportErrors) context.owner.newErrorValue(name) else stdErrorValue
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 1566897dab..955d51bf8d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -73,7 +73,7 @@ trait Namers extends MethodSynthesis {
classAndNamerOfModule.clear()
}
- abstract class Namer(val context: Context) extends MethodSynth with NamerContextErrors {
+ abstract class Namer(val context: Context) extends MethodSynth with NamerContextErrors { thisNamer =>
import NamerErrorGen._
val typer = newTyper(context)
@@ -99,6 +99,13 @@ trait Namers extends MethodSynthesis {
owner.unsafeTypeParams foreach (paramContext.scope enter _)
newNamer(paramContext)
}
+
+ def enclosingNamerWithScope(scope: Scope) = {
+ var cx = context
+ while (cx != NoContext && cx.scope != scope) cx = cx.outer
+ if (cx == NoContext || cx == context) thisNamer
+ else newNamer(cx)
+ }
def enterValueParams(vparamss: List[List[ValDef]]): List[List[Symbol]] = {
mmap(vparamss) { param =>
@@ -709,17 +716,17 @@ trait Namers extends MethodSynthesis {
if (needsCycleCheck && !typer.checkNonCyclic(tree.pos, tp))
sym setInfo ErrorType
}
- tree match {
- case ClassDef(_, _, _, impl) =>
- val parentsOK = (
- treeInfo.isInterface(sym, impl.body)
- || (sym eq ArrayClass)
- || (sym isSubClass AnyValClass)
- )
- if (!parentsOK)
- ensureParent(sym, AnyRefClass)
- case _ => ()
- }
+ // tree match {
+ // case ClassDef(_, _, _, impl) =>
+ // val parentsOK = (
+ // treeInfo.isInterface(sym, impl.body)
+ // || (sym eq ArrayClass)
+ // || (sym isSubClass AnyValClass)
+ // )
+ // if (!parentsOK)
+ // ensureParent(sym, AnyRefClass)
+ // case _ => ()
+ // }
}
def moduleClassTypeCompleter(tree: Tree) = {
@@ -1267,7 +1274,10 @@ trait Namers extends MethodSynthesis {
val clazz = tree.symbol
val result = createNamer(tree).classSig(tparams, impl)
clazz setInfo result
- if (clazz.isInlineClass) ensureCompanionObject(cdef)
+ if (clazz.isDerivedValueClass) {
+ clazz setFlag FINAL
+ enclosingNamerWithScope(clazz.owner.info.decls).ensureCompanionObject(cdef)
+ }
result
case ModuleDef(_, _, impl) =>
@@ -1417,13 +1427,6 @@ trait Namers extends MethodSynthesis {
if (sym.info.typeSymbol == FunctionClass(0) && sym.isValueParameter && sym.owner.isCaseClass)
fail(ByNameParameter)
- if (sym.isClass && sym.hasAnnotation(ScalaInlineClass) && !phase.erasedTypes) {
- if (!sym.isSubClass(AnyValClass))
- ensureParent(sym, NotNullClass)
-
- sym setFlag FINAL
- }
-
if (sym.isDeferred) {
// Is this symbol type always allowed the deferred flag?
def symbolAllowsDeferred = (
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index a9278a2616..1e17cb2e3f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -526,7 +526,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
// #3622: erasure operates on uncurried types --
// note on passing sym in both cases: only sym.isType is relevant for uncurry.transformInfo
// !!! erasure.erasure(sym, uncurry.transformInfo(sym, tp)) gives erreneous of inaccessible type - check whether that's still the case!
- def uncurryAndErase(tp: Type) = erasure.erasure(sym, uncurry.transformInfo(sym, tp))
+ def uncurryAndErase(tp: Type) = erasure.erasure(sym)(uncurry.transformInfo(sym, tp))
val tp1 = uncurryAndErase(clazz.thisType.memberType(sym))
val tp2 = uncurryAndErase(clazz.thisType.memberType(other))
afterErasure(tp1 matches tp2)
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 243e685b13..4248b6f024 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -266,6 +266,9 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
}
transformSuperSelect(sel)
+ case DefDef(mods, name, tparams, vparamss, tpt, rhs) if tree.symbol.isMethodWithExtension =>
+ treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, withInvalidOwner(transform(rhs)))
+
case TypeApply(sel @ Select(qual, name), args) =>
mayNeedProtectedAccessor(sel, args, true)
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index def6475221..f9d41bcc5e 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 = (
+ def canEqualMethod: Tree = {
+ syntheticCanEqual = true
createMethod(nme.canEqual_, List(AnyClass.tpe), BooleanClass.tpe)(m =>
Ident(m.firstParam) IS_OBJ classExistentialType(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.isDerivedValueClass || 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, classExistentialType(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 equalsDerivedValueClassMethod: 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 hashCodeDerivedValueClassMethod: 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)))
}
@@ -178,7 +217,7 @@ trait SyntheticMethods extends ast.TreeDSL {
List(
Product_productPrefix -> (() => constantNullary(nme.productPrefix, clazz.name.decode)),
Product_productArity -> (() => constantNullary(nme.productArity, arity)),
- Product_productElement -> (() => perElementMethod(nme.productElement, accessorLub)(Ident)),
+ Product_productElement -> (() => perElementMethod(nme.productElement, accessorLub)(Select(This(clazz), _))),
Product_iterator -> (() => productIteratorMethod),
Product_canEqual -> (() => canEqualMethod)
// This is disabled pending a reimplementation which doesn't add any
@@ -187,10 +226,19 @@ trait SyntheticMethods extends ast.TreeDSL {
)
}
+ def valueClassMethods = List(
+ Any_hashCode -> (() => hashCodeDerivedValueClassMethod),
+ Any_equals -> (() => equalsDerivedValueClassMethod)
+ )
+
def caseClassMethods = productMethods ++ productNMethods ++ Seq(
Object_hashCode -> (() => forwardToRuntime(Object_hashCode)),
Object_toString -> (() => forwardToRuntime(Object_toString)),
- Object_equals -> (() => equalsClassMethod)
+ Object_equals -> (() => equalsCaseClassMethod)
+ )
+
+ def valueCaseClassMethods = productMethods ++ productNMethods ++ valueClassMethods ++ Seq(
+ Any_toString -> (() => forwardToRuntime(Object_toString))
)
def caseObjectMethods = productMethods ++ Seq(
@@ -214,10 +262,14 @@ trait SyntheticMethods extends ast.TreeDSL {
def synthesize(): List[Tree] = {
val methods = (
- if (!clazz.isCase) Nil
- else if (clazz.isModuleClass) caseObjectMethods
- else caseClassMethods
+ if (clazz.isCase)
+ if (clazz.isDerivedValueClass) valueCaseClassMethods
+ else if (clazz.isModuleClass) caseObjectMethods
+ else caseClassMethods
+ else if (clazz.isDerivedValueClass) valueClassMethods
+ else Nil
)
+
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 24ec0c8028..65c46fca98 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1266,6 +1266,34 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
}
+ private def validateDerivedValueClass(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"))
+ val constr = clazz.primaryConstructor
+ if ((constr hasFlag (PRIVATE | PROTECTED)) || constr.privateWithin != NoSymbol)
+ unit.error(constr.pos, "value class must have public primary constructor")
+ 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")
+ for (stat <- body)
+ if (!treeInfo.isAllowedInUniversalTrait(stat) && !isUnderlyingAcc(stat.symbol))
+ 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 =>
+ unit.error(clazz.pos, "value class needs to have exactly one public val parameter")
+ }
+ for (tparam <- clazz.typeParams)
+ if (tparam hasAnnotation definitions.SpecializedClass)
+ unit.error(tparam.pos, "type parameter of value class may not be specialized")
+ }
+
def parentTypes(templ: Template): List[Tree] =
if (templ.parents.isEmpty) List(TypeTree(AnyRefClass.tpe))
else try {
@@ -1282,7 +1310,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
@@ -1373,7 +1401,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
else xs
)
}
-
+
fixDuplicates(supertpt :: mixins) mapConserve (tpt => checkNoEscaping.privates(clazz, tpt))
}
catch {
@@ -1489,10 +1517,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
_.typedTemplate(cdef.impl, parentTypes(cdef.impl))
}
val impl2 = finishMethodSynthesis(impl1, clazz, context)
- if (clazz.isTrait && clazz.info.parents.nonEmpty && clazz.info.firstParent.typeSymbol == AnyClass)
+ if (clazz.isTrait && clazz.info.parents.nonEmpty && clazz.info.firstParent.normalize.typeSymbol == AnyClass)
for (stat <- impl2.body)
- if (!treeInfo.isAllowedInAnyTrait(stat))
- unit.error(stat.pos, "this statement is not allowed in trait extending from class Any: "+stat)
+ if (!treeInfo.isAllowedInUniversalTrait(stat))
+ unit.error(stat.pos, "this statement is not allowed in universal trait extending from class Any: "+stat)
if ((clazz != ClassfileAnnotationClass) &&
(clazz isNonBottomSubClass ClassfileAnnotationClass))
restrictionWarning(cdef.pos, unit,
@@ -1609,6 +1637,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])
@@ -1617,6 +1646,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.isDerivedValueClass)
+ validateDerivedValueClass(clazz, body1)
+
treeCopy.Template(templ, parents1, self1, body1) setType clazz.tpe
}
@@ -1869,11 +1902,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
transformedOrTyped(ddef.rhs, EXPRmode, tpt1.tpe)
}
- if (meth.isPrimaryConstructor && meth.isClassConstructor && !isPastTyper && !reporter.hasErrors) {
+ if (meth.isPrimaryConstructor && meth.isClassConstructor && !isPastTyper && !reporter.hasErrors && !meth.owner.isSubClass(AnyValClass)) {
// At this point in AnyVal there is no supercall, which will blow up
// in computeParamAliases; there's nothing to be computed for Anyval anyway.
- if (meth.owner ne AnyValClass)
- computeParamAliases(meth.owner, vparamss1, rhs1)
+ computeParamAliases(meth.owner, vparamss1, rhs1)
}
if (tpt1.tpe.typeSymbol != NothingClass && !context.returnsSeen && rhs1.tpe.typeSymbol != NothingClass)
rhs1 = checkDead(rhs1)
@@ -4327,7 +4359,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case Typed(expr0, tpt @ Ident(tpnme.WILDCARD_STAR)) =>
val expr = typed(expr0, onlyStickyModes(mode), WildcardType)
def subArrayType(pt: Type) =
- if (isValueClass(pt.typeSymbol) || !isFullyDefined(pt)) arrayType(pt)
+ if (isPrimitiveValueClass(pt.typeSymbol) || !isFullyDefined(pt)) arrayType(pt)
else {
val tparam = context.owner freshExistential "" setInfo TypeBounds.upper(pt)
newExistentialType(List(tparam), arrayType(tparam.tpe))