Skip to content

Commit f57a6d9

Browse files
committed
Check value class member restrictions
According to SIP 15 a value class C must obey the following restrictions: C may not have secondary constructors. C may not declare fields (other than the parameter of a value class). C may not contain object definitions. C may not have initialization statements. These are enforced by this commit. We are still missing restrictions on value class paremeters. We should review what the right set of conditions is (probably we want to admit non-vals, and maybe even multiple parameters).
1 parent 257bf52 commit f57a6d9

File tree

4 files changed

+22
-4
lines changed

4 files changed

+22
-4
lines changed

src/dotty/tools/dotc/typer/RefChecks.scala

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -655,15 +655,27 @@ object RefChecks {
655655
}
656656

657657
/** Verify classes extending AnyVal meet the requirements */
658-
private def checkDerivedValueClass(clazz: Symbol)(implicit ctx: Context) =
658+
private def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(implicit ctx: Context) = {
659+
def checkValueClassMember(stat: Tree) = stat match {
660+
case _: ValDef if !stat.symbol.is(ParamAccessor) =>
661+
ctx.error(s"value class may not define non-parameter field", stat.pos)
662+
case _: DefDef if stat.symbol.isConstructor =>
663+
ctx.error(s"value class may not define secondary constructor", stat.pos)
664+
case _: MemberDef | _: Import | EmptyTree =>
665+
// ok
666+
case _ =>
667+
ctx.error(s"value class may not contain initialization statements", stat.pos)
668+
}
659669
if (isDerivedValueClass(clazz)) {
660670
if (clazz.is(Trait))
661671
ctx.error("Only classes (not traits) are allowed to extend AnyVal", clazz.pos)
662672
if (clazz.is(Abstract))
663673
ctx.error("`abstract' modifier cannot be used with value classes", clazz.pos)
664674
if (!clazz.isStatic)
665675
ctx.error("value class cannot be an inner class", clazz.pos)
676+
stats.foreach(checkValueClassMember)
666677
}
678+
}
667679

668680
type LevelAndIndex = immutable.Map[Symbol, (LevelInfo, Int)]
669681

@@ -780,7 +792,7 @@ class RefChecks extends MiniPhase { thisTransformer =>
780792
checkParents(cls)
781793
checkCompanionNameClashes(cls)
782794
checkAllOverrides(cls)
783-
checkDerivedValueClass(cls)
795+
checkDerivedValueClass(cls, tree.body)
784796
tree
785797
}
786798

test/dotc/tests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ class tests extends CompilerTest {
134134
@Test def neg_i0281 = compileFile(negDir, "i0281-null-primitive-conforms", xerrors = 3)
135135
@Test def neg_i583 = compileFile(negDir, "i0583-skolemize", xerrors = 2)
136136
@Test def neg_finalSealed = compileFile(negDir, "final-sealed", xerrors = 2)
137-
@Test def neg_i705 = compileFile(negDir, "i705-inner-value-class", xerrors = 3)
137+
@Test def neg_i705 = compileFile(negDir, "i705-inner-value-class", xerrors = 7)
138138
@Test def neg_moduleSubtyping = compileFile(negDir, "moduleSubtyping", xerrors = 4)
139139
@Test def neg_escapingRefs = compileFile(negDir, "escapingRefs", xerrors = 2)
140140
@Test def neg_instantiateAbstract = compileFile(negDir, "instantiateAbstract", xerrors = 8)

tests/neg/i705-inner-value-class.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@ class Foo {
22
class B(val a: Int) extends AnyVal // error
33
}
44

5+
class VCwithBadMembers(val a: Int) extends AnyVal {
6+
def this() = this(1) // error
7+
var x = 0 // error
8+
val y = 2 // error
9+
println("hi") // error
10+
}
11+
512
object Test {
613
class B(val a: Int) extends AnyVal // ok
714
def f = {

tests/pos/extmethods.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
trait That1[A]
22
class T[A, This <: That1[A]](val x: Int) extends AnyVal {
33
self: This =>
4-
var next: This = _
54
final def loop(x: This, cnt: Int): Int = loop(x, cnt + 1)
65
def const[B](): Boolean = return true
76
}

0 commit comments

Comments
 (0)