summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-03-14 13:06:06 -0700
committerPaul Phillips <paulp@improving.org>2012-03-14 13:06:06 -0700
commit1c061e5931ccc39090d955e3bc18dd0a1e48df84 (patch)
tree4e351e3c3f3efa5a8e63c3d79bcb665d21d25630 /src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
parenta127aae2a5fbae146ea81e470541209436222970 (diff)
parent54e284d669418ebc6445bd0ec66804b9067f6dd3 (diff)
downloadscala-1c061e5931ccc39090d955e3bc18dd0a1e48df84.tar.gz
scala-1c061e5931ccc39090d955e3bc18dd0a1e48df84.tar.bz2
scala-1c061e5931ccc39090d955e3bc18dd0a1e48df84.zip
Merge remote-tracking branch 'odersky/topic/inline' into merge-inline
Conflicts: lib/scala-compiler.jar.desired.sha1 lib/scala-library-src.jar.desired.sha1 lib/scala-library.jar.desired.sha1 src/compiler/scala/reflect/internal/Definitions.scala src/compiler/scala/reflect/internal/Symbols.scala src/compiler/scala/tools/nsc/Global.scala src/compiler/scala/tools/nsc/transform/Constructors.scala src/compiler/scala/tools/nsc/transform/Erasure.scala src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala src/compiler/scala/tools/nsc/typechecker/Contexts.scala src/compiler/scala/tools/nsc/typechecker/RefChecks.scala src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala src/library/scala/Function0.scala src/library/scala/Function1.scala src/library/scala/Function10.scala src/library/scala/Function11.scala src/library/scala/Function12.scala src/library/scala/Function13.scala src/library/scala/Function14.scala src/library/scala/Function15.scala src/library/scala/Function16.scala src/library/scala/Function17.scala src/library/scala/Function18.scala src/library/scala/Function19.scala src/library/scala/Function2.scala src/library/scala/Function20.scala src/library/scala/Function21.scala src/library/scala/Function22.scala src/library/scala/Function3.scala src/library/scala/Function4.scala src/library/scala/Function5.scala src/library/scala/Function6.scala src/library/scala/Function7.scala src/library/scala/Function8.scala src/library/scala/Function9.scala test/files/codelib/code.jar.desired.sha1 test/files/neg/anyval-children-2.check test/files/run/programmatic-main.check
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala118
1 files changed, 85 insertions, 33 deletions
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) {