Skip to content

Commit fbcba8f

Browse files
nox213som-snytt
authored andcommitted
Disallow value classes extending type aliases of AnyVal
1 parent 98443b6 commit fbcba8f

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
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
@@ -1813,6 +1813,12 @@ class ValueClassParameterMayNotBeCallByName(valueClass: Symbol, param: Symbol)(u
18131813
def explain(using Context) = ""
18141814
}
18151815

1816+
class ValueClassCannotExtendAliasOfAnyVal(valueClass: Symbol, alias: Symbol)(using Context)
1817+
extends SyntaxMsg(ValueClassCannotExtendAliasOfAnyValID) {
1818+
def msg(using Context) = i"""A value class cannot extend a type alias ($alias) of ${hl("AnyVal")}"""
1819+
def explain(using Context) = ""
1820+
}
1821+
18161822
class SuperCallsNotAllowedInlineable(symbol: Symbol)(using Context)
18171823
extends SyntaxMsg(SuperCallsNotAllowedInlineableID) {
18181824
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
@@ -244,7 +244,7 @@ object TreeChecker {
244244
private val everDefinedSyms = MutableSymbolMap[untpd.Tree]()
245245

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

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

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

+15-4
Original file line numberDiff line numberDiff line change
@@ -743,7 +743,7 @@ object Checking {
743743
}
744744

745745
/** Verify classes extending AnyVal meet the requirements */
746-
def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(using Context): Unit = {
746+
def checkDerivedValueClass(cdef: untpd.TypeDef, clazz: Symbol, stats: List[Tree])(using Context): Unit = {
747747
def checkValueClassMember(stat: Tree) = stat match {
748748
case _: TypeDef if stat.symbol.isClass =>
749749
report.error(ValueClassesMayNotDefineInner(clazz, stat.symbol), stat.srcPos)
@@ -760,6 +760,15 @@ object Checking {
760760
// enum extending a value class type (AnyVal or an alias of it)
761761
// The error message 'EnumMayNotBeValueClassesID' will take care of generating the error message (See #22236)
762762
if (clazz.isDerivedValueClass && !clazz.isEnumAnonymClass) {
763+
val parentOpt = cdef.rhs match {
764+
case impl: Template =>
765+
impl.parents.headOption
766+
case _ => None
767+
}
768+
val isExtendingAliasOfAnyVal = parentOpt.exists { parent =>
769+
parent.symbol.isAliasType && parent.tpe.nn.dealias =:= defn.AnyValType
770+
}
771+
763772
if (clazz.is(Trait))
764773
report.error(CannotExtendAnyVal(clazz), clazz.srcPos)
765774
if clazz.is(Module) then
@@ -770,6 +779,8 @@ object Checking {
770779
report.error(ValueClassesMayNotBeAbstract(clazz), clazz.srcPos)
771780
if (!clazz.isStatic)
772781
report.error(ValueClassesMayNotBeContainted(clazz), clazz.srcPos)
782+
if (isExtendingAliasOfAnyVal)
783+
report.error(ValueClassCannotExtendAliasOfAnyVal(clazz, parentOpt.get.symbol), clazz.srcPos)
773784
if (isDerivedValueClass(underlyingOfValueClass(clazz.asClass).classSymbol))
774785
report.error(ValueClassesMayNotWrapAnotherValueClass(clazz), clazz.srcPos)
775786
else {
@@ -1307,8 +1318,8 @@ trait Checking {
13071318
else tpt
13081319

13091320
/** Verify classes extending AnyVal meet the requirements */
1310-
def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(using Context): Unit =
1311-
Checking.checkDerivedValueClass(clazz, stats)
1321+
def checkDerivedValueClass(cdef: untpd.TypeDef, clazz: Symbol, stats: List[Tree])(using Context): Unit =
1322+
Checking.checkDerivedValueClass(cdef, clazz, stats)
13121323

13131324
/** Check that case classes are not inherited by case classes.
13141325
*/
@@ -1689,7 +1700,7 @@ trait NoChecking extends ReChecking {
16891700
override def checkNoTargetNameConflict(stats: List[Tree])(using Context): Unit = ()
16901701
override def checkParentCall(call: Tree, caller: ClassSymbol)(using Context): Unit = ()
16911702
override def checkSimpleKinded(tpt: Tree)(using Context): Tree = tpt
1692-
override def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(using Context): Unit = ()
1703+
override def checkDerivedValueClass(cdef: untpd.TypeDef, clazz: Symbol, stats: List[Tree])(using Context): Unit = ()
16931704
override def checkCaseInheritance(parentSym: Symbol, caseCls: ClassSymbol, pos: SrcPos)(using Context): Unit = ()
16941705
override def checkNoForwardDependencies(vparams: List[ValDef])(using Context): Unit = ()
16951706
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
@@ -3243,7 +3243,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
32433243
checkNonCyclicInherited(cls.thisType, cls.info.parents, cls.info.decls, cdef.srcPos)
32443244

32453245
// check value class constraints
3246-
checkDerivedValueClass(cls, body1)
3246+
checkDerivedValueClass(cdef, cls, body1)
32473247

32483248
val effectiveOwner = cls.owner.skipWeakOwner
32493249
if cls.is(ModuleClass)

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)