diff options
author | Martin Odersky <odersky@gmail.com> | 2012-02-19 18:02:44 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2012-02-19 18:03:19 +0100 |
commit | 64aaef72504b46b9d40359eb0476ad8416f36023 (patch) | |
tree | cb41068323ee789847e287a9caf6695856580f16 | |
parent | 8cc7de74d35b437b7126d02a6219796b5872ac14 (diff) | |
download | scala-64aaef72504b46b9d40359eb0476ad8416f36023.tar.gz scala-64aaef72504b46b9d40359eb0476ad8416f36023.tar.bz2 scala-64aaef72504b46b9d40359eb0476ad8416f36023.zip |
Implemented super access in value classes, restrictions for value classes.
-rw-r--r-- | src/compiler/scala/reflect/internal/Symbols.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 15 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala | 3 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 18 | ||||
-rw-r--r-- | test/files/neg/valueclasses.check | 46 | ||||
-rw-r--r-- | test/files/neg/valueclasses.scala | 36 | ||||
-rw-r--r-- | test/files/run/GenericValueClass.scala | 12 | ||||
-rw-r--r-- | test/files/run/Meter.check | 13 | ||||
-rw-r--r-- | test/files/run/Meter.scala | 55 | ||||
-rw-r--r-- | test/files/run/programmatic-main.check | 4 |
10 files changed, 156 insertions, 48 deletions
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index 89af10283b..d3641c1ee8 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -504,7 +504,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => !isPrimitiveValueClass final def isMethodWithExtension = - isMethod && owner.isInlineClass && !isParamAccessor && !isConstructor + isMethod && owner.isInlineClass && !isParamAccessor && !isConstructor && !hasFlag(SUPERACCESSOR) final def isAnonymousClass = isClass && (name containsName tpnme.ANON_CLASS_NAME) final def isAnonymousFunction = isSynthetic && (name containsName tpnme.ANON_FUN_NAME) diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 3f6a0f8f73..a3529020d4 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -438,12 +438,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 @@ -451,10 +445,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 diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index 0ab09b4fec..d294cc86bc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -237,6 +237,9 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT } transformSuperSelect(tree) + 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/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 008a2e1764..fde9b6f551 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1205,13 +1205,19 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { sym == acc || acc.hasAccessorFlag && sym == acc.accessed if (acc.accessBoundary(clazz) != RootClass) unit.error(acc.pos, "Value class needs to have a publicly accessible val parameter") - else - for (stat <- body) - if (!treeInfo.isAllowedInUniversalTrait(stat) && !isUnderlyingAcc(stat.symbol)) - unit.error(stat.pos, "This statement is not allowed in value class: "+stat) + if (acc.tpe.resultType.typeSymbol.isTypeParameter) + unit.error(acc.pos, "Type of parameter of value class may not be a type variable") + for (stat <- body) + if (!treeInfo.isAllowedInUniversalTrait(stat) && !isUnderlyingAcc(stat.symbol)) + unit.error(stat.pos, + 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] = @@ -1437,10 +1443,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.isAllowedInUniversalTrait(stat)) - unit.error(stat.pos, "this statement is not allowed in trait extending from class Any: "+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, diff --git a/test/files/neg/valueclasses.check b/test/files/neg/valueclasses.check new file mode 100644 index 0000000000..c4430c8e1a --- /dev/null +++ b/test/files/neg/valueclasses.check @@ -0,0 +1,46 @@ +valueclasses.scala:3: error: Only classes (not traits) are allowed to extend AnyVal +trait T extends AnyVal // fail + ^ +valueclasses.scala:6: error: Value class may not be a member of another class + class Bar(x: Int) extends AnyVal // fail + ^ +valueclasses.scala:8: error: Value class may not be a local class + class Baz(x: Int) extends AnyVal // fail + ^ +valueclasses.scala:12: error: Value class needs to have exactly one public val parameter +class V1 extends AnyVal // fail + ^ +valueclasses.scala:14: error: Value class needs to have a publicly accessible val parameter +class V2(private[test] val x: Int) extends AnyVal // fail + ^ +valueclasses.scala:15: error: Value class needs to have a publicly accessible val parameter +class V3(protected[test] val x: Int) extends AnyVal // fail + ^ +valueclasses.scala:16: error: Value class needs to have a publicly accessible val parameter +class V4(protected val x: Int) extends AnyVal // fail + ^ +valueclasses.scala:17: error: Value class needs to have a publicly accessible val parameter +class V5(private val x: Int) extends AnyVal // fail + ^ +valueclasses.scala:19: error: Value class needs to have exactly one public val parameter +class V6(val x: Int, val y: String) extends AnyVal // fail + ^ +valueclasses.scala:20: error: Illegal parameter for value class +class V7(val x: Int, private[this] val y: String) extends AnyVal // fail + ^ +valueclasses.scala:21: error: Value class needs to have exactly one public val parameter +class V8(var x: Int) extends AnyVal // fail + ^ +valueclasses.scala:24: error: This statement is not allowed in value class: private[this] val y: Int = V9.this.x + val y = x // fail + ^ +valueclasses.scala:27: error: Type of parameter of value class may not be a type variable +class V10[T](val x: T) extends AnyVal // fail + ^ +valueclasses.scala:29: error: type parameter of value class may not be specialized +class V12[@specialized T, U](val x: (T, U)) extends AnyVal // fail + ^ +valueclasses.scala:31: error: Value class needs to have exactly one public val parameter +class V13(x: Int) extends AnyVal // fail + ^ +15 errors found diff --git a/test/files/neg/valueclasses.scala b/test/files/neg/valueclasses.scala new file mode 100644 index 0000000000..2794a852ee --- /dev/null +++ b/test/files/neg/valueclasses.scala @@ -0,0 +1,36 @@ +package test + +trait T extends AnyVal // fail + +class Foo { + class Bar(x: Int) extends AnyVal // fail + def foo() { + class Baz(x: Int) extends AnyVal // fail + } +} + +class V1 extends AnyVal // fail + +class V2(private[test] val x: Int) extends AnyVal // fail +class V3(protected[test] val x: Int) extends AnyVal // fail +class V4(protected val x: Int) extends AnyVal // fail +class V5(private val x: Int) extends AnyVal // fail + +class V6(val x: Int, val y: String) extends AnyVal // fail +class V7(val x: Int, private[this] val y: String) extends AnyVal // fail +class V8(var x: Int) extends AnyVal // fail + +class V9(val x: Int) extends AnyVal { + val y = x // fail +} + +class V10[T](val x: T) extends AnyVal // fail +class V11[T](val x: List[T]) extends AnyVal // ok +class V12[@specialized T, U](val x: (T, U)) extends AnyVal // fail + +class V13(x: Int) extends AnyVal // fail + + + + + diff --git a/test/files/run/GenericValueClass.scala b/test/files/run/GenericValueClass.scala deleted file mode 100644 index 10068d6cae..0000000000 --- a/test/files/run/GenericValueClass.scala +++ /dev/null @@ -1,12 +0,0 @@ -class Box[T](val x: T) extends AnyVal { - def get: T = x -} - -object Test extends App { - val b = new Box(1) - println(b.get) - - val c = new Box("abc") - println(c.get) - -} diff --git a/test/files/run/Meter.check b/test/files/run/Meter.check index d5073b3c31..7562f9a1bf 100644 --- a/test/files/run/Meter.check +++ b/test/files/run/Meter.check @@ -9,10 +9,13 @@ a == b: true testing native arrays Array(1.0m, 2.0m) 1.0m -1.0m 1.0m -2.0m 2.0m +>>>1.0m<<< 1.0m +>>>2.0m<<< 2.0m testing wrapped arrays -RowFactory(1.0m, 2.0m) +FlatArray(1.0m, 2.0m) 1.0m -1.0m 1.0m -2.0m 2.0m +>>>1.0m<<< 1.0m +>>>2.0m<<< 2.0m +FlatArray(2.0m, 3.0m) +ArrayBuffer(1.0, 2.0) +FlatArray(0.3048ft, 0.6096ft) diff --git a/test/files/run/Meter.scala b/test/files/run/Meter.scala index 936b8d98b7..42a3aac5f8 100644 --- a/test/files/run/Meter.scala +++ b/test/files/run/Meter.scala @@ -1,23 +1,46 @@ -class Meter(val underlying: Double) extends AnyVal with Printable { - def + (other: Meter): Meter = - new Meter(this.underlying + other.underlying) - def / (other: Meter): Double = this.underlying / other.underlying - def / (factor: Double): Meter = new Meter(this.underlying / factor) - def < (other: Meter): Boolean = this.underlying < other.underlying - override def toString: String = underlying.toString+"m" -} -object Meter extends (Double => Meter) { +package a { + class Meter(val underlying: Double) extends AnyVal with _root_.b.Printable { + def + (other: Meter): Meter = + new Meter(this.underlying + other.underlying) + def / (other: Meter): Double = this.underlying / other.underlying + def / (factor: Double): Meter = new Meter(this.underlying / factor) + def < (other: Meter): Boolean = this.underlying < other.underlying + def toFoot: Foot = new Foot(this.underlying * 0.3048) + override def print = { Console.print(">>>"); super.print; proprint } + override def toString: String = underlying.toString+"m" + } - def apply(x: Double): Meter = new Meter(x) + object Meter extends (Double => Meter) { + + def apply(x: Double): Meter = new Meter(x) - implicit val boxings = new BoxingConversions[Meter, Double] { - def box(x: Double) = new Meter(x) - def unbox(m: Meter) = m.underlying + implicit val boxings = new BoxingConversions[Meter, Double] { + def box(x: Double) = new Meter(x) + def unbox(m: Meter) = m.underlying + } } -} -trait Printable extends Any { def print: Unit = Console.print(this) } + class Foot(val unbox: Double) extends AnyVal { + def + (other: Foot): Foot = + new Foot(this.unbox + other.unbox) + override def toString = unbox.toString+"ft" + } + object Foot { + implicit val boxings = new BoxingConversions[Foot, Double] { + def box(x: Double) = new Foot(x) + def unbox(m: Foot) = m.unbox + } + } +} +package b { + trait Printable extends Any { + def print: Unit = Console.print(this) + protected def proprint = Console.print("<<<") + } +} +import a._ +import _root_.b._ object Test extends App { { @@ -72,6 +95,8 @@ object Test extends App { println(ys) val zs = arr map (_ / Meter(1)) println(zs) + val fs = arr map (_.toFoot) + println(fs) } } diff --git a/test/files/run/programmatic-main.check b/test/files/run/programmatic-main.check index 9ddd4a6e14..d16e2c5178 100644 --- a/test/files/run/programmatic-main.check +++ b/test/files/run/programmatic-main.check @@ -4,8 +4,8 @@ namer 2 resolve names, attach symbols to named trees packageobjects 3 load package objects typer 4 the meat and potatoes: type the trees - extmethods 5 add extension methods for inline classes - superaccessors 6 add super accessors in traits and nested classes + superaccessors 5 add super accessors in traits and nested classes + extmethods 6 add extension methods for inline classes pickler 7 serialize symbol tables refchecks 8 reference/override checking, translate nested objects uncurry 9 uncurry, translate function values to anonymous classes |