summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Typers.scala
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2013-09-19 14:53:03 +0200
committerJason Zaugg <jzaugg@gmail.com>2013-09-29 22:37:17 +0200
commit4595ac665674b25af776d499ae1da61bb297d379 (patch)
tree5ce5c591fba9237a10abc82e7efeb6e61b755952 /src/compiler/scala/tools/nsc/typechecker/Typers.scala
parent0aaf59149871f817a67c1fefcc3b0457fcb5e4fc (diff)
downloadscala-4595ac665674b25af776d499ae1da61bb297d379.tar.gz
scala-4595ac665674b25af776d499ae1da61bb297d379.tar.bz2
scala-4595ac665674b25af776d499ae1da61bb297d379.zip
SI-7859 Value classes may wrap a non-public member
We allow value class constructors to be non-public, so to be regular, we should also allow the same for the param accessor. This commit uses the 'makeNotPrivate' machinery to ensure that the backend can generate the requisite unboxing calls. This commit: - refactors the code that enforced the restrictions, improving a few error messages and positions. The remaining restrictions needed some rewording in light of this change. - allows value classes to have non-public, val parameters. private[this] / protected[this] are still disallowed as value classes don't have a concept of `this`, and because trying to accomdate then would complicate the implementation. This means that `class C(x: Int) extends AnyVal` is not allowed, the user still must write `private val x: Int` or `val x: Int`. - Outlaw `class C()()(val x: Int) extends AnyVal` to curtail any bugs that might lurk in such a formulation. The tests: - Show that the privacy is respected in the typer phase, under joint and separate compilation. We don't want a repeat performance of SI-6601. - Show that code that needs compiler-generated unboxes works under both compilation scenarios - Checks that the remaining restrictions are enforced and well communicated.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Typers.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala30
1 files changed, 19 insertions, 11 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 157c6ba4de..e3ec8b7fb8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1356,17 +1356,25 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
unit.error(clazz.pos, "value class may not be a "+
(if (clazz.owner.isTerm) "local class" else "member of another class"))
if (!clazz.isPrimitiveValueClass) {
- clazz.info.decls.toList.filter(acc => acc.isMethod && acc.isParamAccessor) match {
- case List(acc) =>
- def isUnderlyingAcc(sym: Symbol) =
- sym == acc || acc.hasAccessorFlag && sym == acc.accessed
- if (acc.accessBoundary(clazz) != rootMirror.RootClass)
- unit.error(acc.pos, "value class needs to have a publicly accessible val parameter")
- else if (acc.tpe.typeSymbol.isDerivedValueClass)
- unit.error(acc.pos, "value class may not wrap another user-defined value class")
- checkEphemeral(clazz, body filterNot (stat => isUnderlyingAcc(stat.symbol)))
- case x =>
- unit.error(clazz.pos, "value class needs to have exactly one public val parameter")
+ clazz.primaryConstructor.paramss match {
+ case List(List(param)) =>
+ val decls = clazz.info.decls
+ val paramAccessor = clazz.constrParamAccessors.head
+ if (paramAccessor.isMutable)
+ unit.error(paramAccessor.pos, "value class parameter must not be a var")
+ val accessor = decls.toList.find(x => x.isMethod && x.accessedOrSelf == paramAccessor)
+ accessor match {
+ case None =>
+ unit.error(paramAccessor.pos, "value class parameter must be a val and not be private[this]")
+ case Some(acc) if acc.isProtectedLocal =>
+ unit.error(paramAccessor.pos, "value class parameter must not be protected[this]")
+ case Some(acc) =>
+ if (acc.tpe.typeSymbol.isDerivedValueClass)
+ unit.error(acc.pos, "value class may not wrap another user-defined value class")
+ checkEphemeral(clazz, body filterNot (stat => stat.symbol != null && stat.symbol.accessedOrSelf == paramAccessor))
+ }
+ case _ =>
+ unit.error(clazz.pos, "value class needs to have exactly one val parameter")
}
}