Skip to content

Commit 6078ce5

Browse files
committed
[JEP-409] Add support for sealed classes and interfaces in Java
[Cherry-picked 3154c59][modified]
1 parent ff7edb5 commit 6078ce5

File tree

10 files changed

+46
-5
lines changed

10 files changed

+46
-5
lines changed

compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,9 @@ object JavaParsers {
483483
addAnnot(scalaDot(jtpnme.VOLATILEkw))
484484
case SYNCHRONIZED | STRICTFP =>
485485
in.nextToken()
486+
case SEALED =>
487+
flags |= Flags.Sealed
488+
in.nextToken()
486489
case _ =>
487490
val privateWithin: TypeName =
488491
if (isPackageAccess && !inInterface) thisPackageName
@@ -806,6 +809,17 @@ object JavaParsers {
806809
else
807810
List()
808811

812+
813+
def permittedSubclassesOpt(isSealed: Boolean) : List[Tree] =
814+
if in.token == PERMITS && !isSealed then
815+
syntaxError(em"A type declaration that has a permits clause should have a sealed modifier")
816+
if in.token == PERMITS then
817+
in.nextToken()
818+
repsep(() => typ(), COMMA)
819+
else
820+
// JEP-409: Class/Interface may omit the permits clause
821+
Nil
822+
809823
def classDecl(start: Offset, mods: Modifiers): List[Tree] = {
810824
accept(CLASS)
811825
val nameOffset = in.offset
@@ -820,6 +834,7 @@ object JavaParsers {
820834
javaLangObject()
821835
val interfaces = interfacesOpt()
822836
val (statics, body) = typeBody(CLASS, name, tparams)
837+
val permittedSubclasses = permittedSubclassesOpt(mods.is(Flags.Sealed))
823838
val cls = atSpan(start, nameOffset) {
824839
TypeDef(name, makeTemplate(superclass :: interfaces, body, tparams, true)).withMods(mods)
825840
}
@@ -883,6 +898,7 @@ object JavaParsers {
883898
}
884899
else
885900
List(javaLangObject())
901+
val permittedSubclasses = permittedSubclassesOpt(mods is Flags.Sealed)
886902
val (statics, body) = typeBody(INTERFACE, name, tparams)
887903
val iface = atSpan(start, nameOffset) {
888904
TypeDef(

compiler/src/dotty/tools/dotc/parsing/JavaScanners.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,6 @@ object JavaScanners {
393393
'5' | '6' | '7' | '8' | '9' =>
394394
putChar(ch)
395395
nextChar()
396-
397396
case '_' =>
398397
putChar(ch)
399398
nextChar()

compiler/src/dotty/tools/dotc/parsing/JavaTokens.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ object JavaTokens extends TokensCommon {
1010

1111
final val javaOnlyKeywords: TokenSet = tokenRange(INSTANCEOF, ASSERT)
1212
final val sharedKeywords: BitSet = BitSet( IF, FOR, ELSE, THIS, NULL, NEW, SUPER, ABSTRACT, FINAL, PRIVATE, PROTECTED,
13-
EXTENDS, TRUE, FALSE, CLASS, IMPORT, PACKAGE, DO, THROW, TRY, CATCH, FINALLY, WHILE, RETURN )
13+
EXTENDS, TRUE, FALSE, CLASS, IMPORT, PACKAGE, DO, THROW, TRY, CATCH, FINALLY, WHILE, RETURN, SEALED)
1414
final val primTypes: TokenSet = tokenRange(VOID, DOUBLE)
1515
final val keywords: BitSet = sharedKeywords | javaOnlyKeywords | primTypes
1616

@@ -22,6 +22,7 @@ object JavaTokens extends TokensCommon {
2222
inline val INTERFACE = 105; enter(INTERFACE, "interface")
2323
inline val ENUM = 106; enter(ENUM, "enum")
2424
inline val IMPLEMENTS = 107; enter(IMPLEMENTS, "implements")
25+
inline val PERMITS = 108; enter(PERMITS, "permits")
2526

2627
/** modifiers */
2728
inline val PUBLIC = 110; enter(PUBLIC, "public")

compiler/src/dotty/tools/dotc/parsing/Tokens.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ abstract class TokensCommon {
7878
//inline val YIELD = 48; enter(YIELD, "yield")
7979
inline val DO = 49; enter(DO, "do")
8080
//inline val TRAIT = 50; enter(TRAIT, "trait")
81-
//inline val SEALED = 51; enter(SEALED, "sealed")
81+
inline val SEALED = 51; enter(SEALED, "sealed")
8282
inline val THROW = 52; enter(THROW, "throw")
8383
inline val TRY = 53; enter(TRY, "try")
8484
inline val CATCH = 54; enter(CATCH, "catch")
@@ -169,7 +169,7 @@ object Tokens extends TokensCommon {
169169
inline val OBJECT = 44; enter(OBJECT, "object")
170170
inline val YIELD = 48; enter(YIELD, "yield")
171171
inline val TRAIT = 50; enter(TRAIT, "trait")
172-
inline val SEALED = 51; enter(SEALED, "sealed")
172+
//inline val SEALED = 51; enter(SEALED, "sealed")
173173
inline val MATCH = 58; enter(MATCH, "match")
174174
inline val LAZY = 59; enter(LAZY, "lazy")
175175
inline val THEN = 60; enter(THEN, "then")

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1543,6 +1543,7 @@ class Namer { typer: Typer =>
15431543
* (2) If may not derive from itself
15441544
* (3) The class is not final
15451545
* (4) If the class is sealed, it is defined in the same compilation unit as the current class
1546+
* (unless defined in Java. See JEP-409)
15461547
*
15471548
* @param isJava If true, the parent type is in Java mode, and we do not require a stable prefix
15481549
*/
@@ -1566,7 +1567,7 @@ class Namer { typer: Typer =>
15661567
if pclazz.is(Final) then
15671568
report.error(ExtendFinalClass(cls, pclazz), cls.srcPos)
15681569
else if pclazz.isEffectivelySealed && pclazz.associatedFile != cls.associatedFile then
1569-
if pclazz.is(Sealed) then
1570+
if pclazz.is(Sealed) && !pclazz.is(JavaDefined) then
15701571
report.error(UnableToExtendSealedClass(pclazz), cls.srcPos)
15711572
else if sourceVersion.isAtLeast(future) then
15721573
checkFeature(nme.adhocExtensions,

tests/neg/i18533.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- Error: tests/neg/i18533/Pet_SCALA_ONLY.java:3:10 --------------------------------------------------------------------
2+
3 |class Pet permits Cat { // error
3+
| ^^^^^^^
4+
| A type declaration that has a permits clause should have a sealed modifier

tests/neg/i18533/Cat_SCALA_ONLY.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package i18533;
2+
3+
public class Cat extends Pet {
4+
5+
}

tests/neg/i18533/Pet_SCALA_ONLY.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package i18533;
2+
3+
class Pet permits Cat { // error
4+
5+
}

tests/pos/i18533/Cat.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package i18533;
2+
3+
public final class Cat extends Pet {
4+
5+
}

tests/pos/i18533/Pet.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package i18533;
2+
3+
public sealed class Pet permits Cat {
4+
5+
}

0 commit comments

Comments
 (0)