Skip to content

Commit de004ca

Browse files
committed
[JEP-409] Add support for sealed classes and interfaces in Java
1 parent a0ea484 commit de004ca

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
@@ -489,6 +489,9 @@ object JavaParsers {
489489
addAnnot(scalaDot(jtpnme.VOLATILEkw))
490490
case SYNCHRONIZED | STRICTFP =>
491491
in.nextToken()
492+
case SEALED =>
493+
flags |= Flags.Sealed
494+
in.nextToken()
492495
case _ =>
493496
val privateWithin: TypeName =
494497
if (isPackageAccess && !inInterface) thisPackageName
@@ -812,6 +815,17 @@ object JavaParsers {
812815
else
813816
List()
814817

818+
819+
def permittedSubclassesOpt(isSealed: Boolean) : List[Tree] =
820+
if in.token == PERMITS && !isSealed then
821+
syntaxError(em"A type declaration that has a permits clause should have a sealed modifier")
822+
if in.token == PERMITS then
823+
in.nextToken()
824+
repsep(() => typ(), COMMA)
825+
else
826+
// JEP-409: Class/Interface may omit the permits clause
827+
Nil
828+
815829
def classDecl(start: Offset, mods: Modifiers): List[Tree] = {
816830
accept(CLASS)
817831
val nameOffset = in.offset
@@ -825,6 +839,7 @@ object JavaParsers {
825839
else
826840
ObjectTpt()
827841
val interfaces = interfacesOpt()
842+
val permittedSubclasses = permittedSubclassesOpt(mods.is(Flags.Sealed))
828843
val (statics, body) = typeBody(CLASS, name)
829844
val cls = atSpan(start, nameOffset) {
830845
TypeDef(name, makeTemplate(superclass :: interfaces, body, tparams, needsDummyConstr = true)).withMods(mods)
@@ -889,6 +904,7 @@ object JavaParsers {
889904
}
890905
else
891906
List(ObjectTpt())
907+
val permittedSubclasses = permittedSubclassesOpt(mods is Flags.Sealed)
892908
val (statics, body) = typeBody(INTERFACE, name)
893909
val iface = atSpan(start, nameOffset) {
894910
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
@@ -1546,6 +1546,7 @@ class Namer { typer: Typer =>
15461546
* (2) If may not derive from itself
15471547
* (3) The class is not final
15481548
* (4) If the class is sealed, it is defined in the same compilation unit as the current class
1549+
* (unless defined in Java. See JEP-409)
15491550
*/
15501551
def checkedParentType(parent: untpd.Tree): Type = {
15511552
val ptype = parentType(parent)(using completerCtx.superCallContext).dealiasKeepAnnots
@@ -1567,7 +1568,7 @@ class Namer { typer: Typer =>
15671568
if pclazz.is(Final) then
15681569
report.error(ExtendFinalClass(cls, pclazz), cls.srcPos)
15691570
else if pclazz.isEffectivelySealed && pclazz.associatedFile != cls.associatedFile then
1570-
if pclazz.is(Sealed) then
1571+
if pclazz.is(Sealed) && !pclazz.is(JavaDefined) then
15711572
report.error(UnableToExtendSealedClass(pclazz), cls.srcPos)
15721573
else if sourceVersion.isAtLeast(future) then
15731574
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)