Skip to content

Commit

Permalink
[JEP-409] Add support for sealed classes and interfaces in Java
Browse files Browse the repository at this point in the history
  • Loading branch information
hamzaremmal committed Feb 14, 2024
1 parent a0ea484 commit de004ca
Show file tree
Hide file tree
Showing 10 changed files with 46 additions and 5 deletions.
16 changes: 16 additions & 0 deletions compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,9 @@ object JavaParsers {
addAnnot(scalaDot(jtpnme.VOLATILEkw))
case SYNCHRONIZED | STRICTFP =>
in.nextToken()
case SEALED =>
flags |= Flags.Sealed
in.nextToken()
case _ =>
val privateWithin: TypeName =
if (isPackageAccess && !inInterface) thisPackageName
Expand Down Expand Up @@ -812,6 +815,17 @@ object JavaParsers {
else
List()


def permittedSubclassesOpt(isSealed: Boolean) : List[Tree] =
if in.token == PERMITS && !isSealed then
syntaxError(em"A type declaration that has a permits clause should have a sealed modifier")
if in.token == PERMITS then
in.nextToken()
repsep(() => typ(), COMMA)
else
// JEP-409: Class/Interface may omit the permits clause
Nil

def classDecl(start: Offset, mods: Modifiers): List[Tree] = {
accept(CLASS)
val nameOffset = in.offset
Expand All @@ -825,6 +839,7 @@ object JavaParsers {
else
ObjectTpt()
val interfaces = interfacesOpt()
val permittedSubclasses = permittedSubclassesOpt(mods.is(Flags.Sealed))
val (statics, body) = typeBody(CLASS, name)
val cls = atSpan(start, nameOffset) {
TypeDef(name, makeTemplate(superclass :: interfaces, body, tparams, needsDummyConstr = true)).withMods(mods)
Expand Down Expand Up @@ -889,6 +904,7 @@ object JavaParsers {
}
else
List(ObjectTpt())
val permittedSubclasses = permittedSubclassesOpt(mods is Flags.Sealed)
val (statics, body) = typeBody(INTERFACE, name)
val iface = atSpan(start, nameOffset) {
TypeDef(
Expand Down
1 change: 0 additions & 1 deletion compiler/src/dotty/tools/dotc/parsing/JavaScanners.scala
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,6 @@ object JavaScanners {
'5' | '6' | '7' | '8' | '9' =>
putChar(ch)
nextChar()

case '_' =>
putChar(ch)
nextChar()
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/parsing/JavaTokens.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ object JavaTokens extends TokensCommon {

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

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

/** modifiers */
inline val PUBLIC = 110; enter(PUBLIC, "public")
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/parsing/Tokens.scala
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ abstract class TokensCommon {
//inline val YIELD = 48; enter(YIELD, "yield")
inline val DO = 49; enter(DO, "do")
//inline val TRAIT = 50; enter(TRAIT, "trait")
//inline val SEALED = 51; enter(SEALED, "sealed")
inline val SEALED = 51; enter(SEALED, "sealed")
inline val THROW = 52; enter(THROW, "throw")
inline val TRY = 53; enter(TRY, "try")
inline val CATCH = 54; enter(CATCH, "catch")
Expand Down Expand Up @@ -169,7 +169,7 @@ object Tokens extends TokensCommon {
inline val OBJECT = 44; enter(OBJECT, "object")
inline val YIELD = 48; enter(YIELD, "yield")
inline val TRAIT = 50; enter(TRAIT, "trait")
inline val SEALED = 51; enter(SEALED, "sealed")
//inline val SEALED = 51; enter(SEALED, "sealed")
inline val MATCH = 58; enter(MATCH, "match")
inline val LAZY = 59; enter(LAZY, "lazy")
inline val THEN = 60; enter(THEN, "then")
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1546,6 +1546,7 @@ class Namer { typer: Typer =>
* (2) If may not derive from itself
* (3) The class is not final
* (4) If the class is sealed, it is defined in the same compilation unit as the current class
* (unless defined in Java. See JEP-409)
*/
def checkedParentType(parent: untpd.Tree): Type = {
val ptype = parentType(parent)(using completerCtx.superCallContext).dealiasKeepAnnots
Expand All @@ -1567,7 +1568,7 @@ class Namer { typer: Typer =>
if pclazz.is(Final) then
report.error(ExtendFinalClass(cls, pclazz), cls.srcPos)
else if pclazz.isEffectivelySealed && pclazz.associatedFile != cls.associatedFile then
if pclazz.is(Sealed) then
if pclazz.is(Sealed) && !pclazz.is(JavaDefined) then
report.error(UnableToExtendSealedClass(pclazz), cls.srcPos)
else if sourceVersion.isAtLeast(future) then
checkFeature(nme.adhocExtensions,
Expand Down
4 changes: 4 additions & 0 deletions tests/neg/i18533.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- Error: tests/neg/i18533/Pet_SCALA_ONLY.java:3:10 --------------------------------------------------------------------
3 |class Pet permits Cat { // error
| ^^^^^^^
| A type declaration that has a permits clause should have a sealed modifier
5 changes: 5 additions & 0 deletions tests/neg/i18533/Cat_SCALA_ONLY.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package i18533;

public class Cat extends Pet {

}
5 changes: 5 additions & 0 deletions tests/neg/i18533/Pet_SCALA_ONLY.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package i18533;

class Pet permits Cat { // error

}
5 changes: 5 additions & 0 deletions tests/pos/i18533/Cat.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package i18533;

public final class Cat extends Pet {

}
5 changes: 5 additions & 0 deletions tests/pos/i18533/Pet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package i18533;

public sealed class Pet permits Cat {

}

0 comments on commit de004ca

Please sign in to comment.