Skip to content

Commit 47db103

Browse files
nox213tgodzik
authored andcommitted
Fix scala#21918: Disallow value classes extending type aliases of AnyVal
1 parent 4c096bb commit 47db103

File tree

6 files changed

+26
-6
lines changed

6 files changed

+26
-6
lines changed

compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala

+1
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
223223
case IllegalUnrollPlacementID // errorNumber: 207 - unused in LTS
224224
case ExtensionHasDefaultID // errorNumber: 208
225225
case FormatInterpolationErrorID // errorNumber: 209
226+
case ValueClassCannotExtendAliasOfAnyValID // errorNumber: 210
226227

227228
def errorNumber = ordinal - 1
228229

compiler/src/dotty/tools/dotc/reporting/messages.scala

+6
Original file line numberDiff line numberDiff line change
@@ -1793,6 +1793,12 @@ class ValueClassParameterMayNotBeCallByName(valueClass: Symbol, param: Symbol)(u
17931793
def explain(using Context) = ""
17941794
}
17951795

1796+
class ValueClassCannotExtendAliasOfAnyVal(valueClass: Symbol, alias: Symbol)(using Context)
1797+
extends SyntaxMsg(ValueClassCannotExtendAliasOfAnyValID) {
1798+
def msg(using Context) = i"""A value class cannot extend a type alias ($alias) of ${hl("AnyVal")}"""
1799+
def explain(using Context) = ""
1800+
}
1801+
17961802
class SuperCallsNotAllowedInlineable(symbol: Symbol)(using Context)
17971803
extends SyntaxMsg(SuperCallsNotAllowedInlineableID) {
17981804
def msg(using Context) = i"Super call not allowed in inlineable $symbol"

compiler/src/dotty/tools/dotc/transform/TreeChecker.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ object TreeChecker {
214214
private val everDefinedSyms = MutableSymbolMap[untpd.Tree]()
215215

216216
// don't check value classes after typer, as the constraint about constructors doesn't hold after transform
217-
override def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(using Context): Unit = ()
217+
override def checkDerivedValueClass(cdef: untpd.TypeDef, clazz: Symbol, stats: List[Tree])(using Context): Unit = ()
218218

219219
def withDefinedSyms[T](trees: List[untpd.Tree])(op: => T)(using Context): T = {
220220
var locally = List.empty[Symbol]

compiler/src/dotty/tools/dotc/typer/Checking.scala

+15-4
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,7 @@ object Checking {
720720
}
721721

722722
/** Verify classes extending AnyVal meet the requirements */
723-
def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(using Context): Unit = {
723+
def checkDerivedValueClass(cdef: untpd.TypeDef, clazz: Symbol, stats: List[Tree])(using Context): Unit = {
724724
def checkValueClassMember(stat: Tree) = stat match {
725725
case _: TypeDef if stat.symbol.isClass =>
726726
report.error(ValueClassesMayNotDefineInner(clazz, stat.symbol), stat.srcPos)
@@ -733,6 +733,14 @@ object Checking {
733733
case _ =>
734734
report.error(ValueClassesMayNotContainInitalization(clazz), stat.srcPos)
735735
}
736+
inline def checkParentIsNotAnyValAlias(): Unit =
737+
cdef.rhs match {
738+
case impl: Template =>
739+
val parent = impl.parents.head
740+
if parent.symbol.isAliasType && parent.typeOpt.dealias =:= defn.AnyValType then
741+
report.error(ValueClassCannotExtendAliasOfAnyVal(clazz, parent.symbol), cdef.srcPos)
742+
case _ => ()
743+
}
736744
// We don't check synthesised enum anonymous classes that are generated from
737745
// enum extending a value class type (AnyVal or an alias of it)
738746
// The error message 'EnumMayNotBeValueClassesID' will take care of generating the error message (See #22236)
@@ -747,6 +755,9 @@ object Checking {
747755
report.error(ValueClassesMayNotBeAbstract(clazz), clazz.srcPos)
748756
if (!clazz.isStatic)
749757
report.error(ValueClassesMayNotBeContainted(clazz), clazz.srcPos)
758+
759+
checkParentIsNotAnyValAlias()
760+
750761
if (isDerivedValueClass(underlyingOfValueClass(clazz.asClass).classSymbol))
751762
report.error(ValueClassesMayNotWrapAnotherValueClass(clazz), clazz.srcPos)
752763
else {
@@ -1228,8 +1239,8 @@ trait Checking {
12281239
else tpt
12291240

12301241
/** Verify classes extending AnyVal meet the requirements */
1231-
def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(using Context): Unit =
1232-
Checking.checkDerivedValueClass(clazz, stats)
1242+
def checkDerivedValueClass(cdef: untpd.TypeDef, clazz: Symbol, stats: List[Tree])(using Context): Unit =
1243+
Checking.checkDerivedValueClass(cdef, clazz, stats)
12331244

12341245
/** Check that case classes are not inherited by case classes.
12351246
*/
@@ -1600,7 +1611,7 @@ trait NoChecking extends ReChecking {
16001611
override def checkNoTargetNameConflict(stats: List[Tree])(using Context): Unit = ()
16011612
override def checkParentCall(call: Tree, caller: ClassSymbol)(using Context): Unit = ()
16021613
override def checkSimpleKinded(tpt: Tree)(using Context): Tree = tpt
1603-
override def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(using Context): Unit = ()
1614+
override def checkDerivedValueClass(cdef: untpd.TypeDef, clazz: Symbol, stats: List[Tree])(using Context): Unit = ()
16041615
override def checkCaseInheritance(parentSym: Symbol, caseCls: ClassSymbol, pos: SrcPos)(using Context): Unit = ()
16051616
override def checkNoForwardDependencies(vparams: List[ValDef])(using Context): Unit = ()
16061617
override def checkMembersOK(tp: Type, pos: SrcPos)(using Context): Type = tp

compiler/src/dotty/tools/dotc/typer/Typer.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -2779,7 +2779,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
27792779
checkNonCyclicInherited(cls.thisType, cls.info.parents, cls.info.decls, cdef.srcPos)
27802780

27812781
// check value class constraints
2782-
checkDerivedValueClass(cls, body1)
2782+
checkDerivedValueClass(cdef, cls, body1)
27832783

27842784
// check PolyFunction constraints (no erased functions!)
27852785
if parents1.exists(_.tpe.classSymbol eq defn.PolyFunctionClass) then

tests/neg/i21918.scala

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
type AliasToAnyVal = AnyVal
2+
class Foo(a: Int) extends AliasToAnyVal // error

0 commit comments

Comments
 (0)