Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid brittle flags encoding for Java enums #10424

Merged
merged 2 commits into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Set enum as abstract always
  • Loading branch information
som-snytt committed Jun 19, 2023
commit 8d5cb076a3b2ef90280d411c14c4c9ef51d88f78
26 changes: 13 additions & 13 deletions src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -593,19 +593,17 @@ abstract class ClassfileParser(reader: ReusableInstance[ReusableDataReader]) {
getScope(jflags) enter sym

// sealed java enums
if (jflags.isEnum) {
val enumClass = sym.owner.linkedClassOfClass
enumClass match {
if (jflags.isEnum)
sym.owner.linkedClassOfClass match {
case NoSymbol =>
devWarning(s"no linked class for java enum $sym in ${sym.owner}. A referencing class file might be missing an InnerClasses entry.")
case linked =>
if (!linked.isSealed)
// Marking the enum class SEALED | ABSTRACT enables exhaustiveness checking. See also JavaParsers.
// This is a bit of a hack and requires excluding the ABSTRACT flag in the backend, see method javaClassfileFlags.
linked setFlag (SEALED | ABSTRACT)
linked addChild sym
case enumClass =>
// Marking the enum class SEALED | ABSTRACT enables exhaustiveness checking. See also JavaParsers.
// This is a bit of a hack and requires excluding the ABSTRACT flag in the backend, see method javaClassfileFlags.
// Java enums may be already sealed by virtue of permittedSubclasses, if an element had a body.
enumClass.setFlag(SEALED | ABSTRACT)
enumClass.addChild(sym)
}
}
}
}

Expand Down Expand Up @@ -1382,9 +1380,11 @@ abstract class ClassfileParser(reader: ReusableInstance[ReusableDataReader]) {
ClassInfoType(superTpe1 :: ifacesTypes, instanceScope, clazz)
}
sym.setInfo(info)
for (k <- permittedSubclasses)
if (k.parentSymbols.contains(sym))
sym.addChild(k)
// enum children are its enum fields, so don't register subclasses (which are listed as permitted)
if (!sym.hasJavaEnumFlag)
for (k <- permittedSubclasses)
if (k.parentSymbols.contains(sym))
sym.addChild(k)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ trait TreeAndTypeAnalysis extends Debugging {
def filterAndSortChildren(children: Set[Symbol]) = {
// symbols which are both sealed and abstract need not be covered themselves,
// because all of their children must be and they cannot otherwise be created.
val children1 = children.toList.filterNot(child => child.isSealed && child.isAbstractClass).sortBy(_.sealedSortName)
val children1 = children.toList
.filterNot(child => child.isSealed && (child.isAbstractClass || child.hasJavaEnumFlag))
.sortBy(_.sealedSortName)
children1.filterNot { child =>
// remove private abstract children that are superclasses of other children, for example in t6159 drop X2
child.isPrivate && child.isAbstractClass && children1.exists(sym => (sym ne child) && sym.isSubClass(child))
Expand Down Expand Up @@ -874,7 +876,7 @@ trait MatchAnalysis extends MatchApproximation {
case args => args
}.map(ListExample)
case _ if isTupleSymbol(cls) => args(brevity = true).map(TupleExample)
case _ if cls.isSealed && cls.isAbstractClass =>
case _ if cls.isSealed && (cls.isAbstractClass || cls.hasJavaEnumFlag) =>
// don't report sealed abstract classes, since
// 1) they can't be instantiated
// 2) we are already reporting any missing subclass (since we know the full domain)
Expand Down
7 changes: 7 additions & 0 deletions test/files/neg/t12800.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
matcher_1.scala:8: warning: match may not be exhaustive.
It would fail on the following input: ORANGE
jb match {
^
error: No warnings can be incurred under -Werror.
1 warning
1 error
13 changes: 13 additions & 0 deletions test/files/neg/t12800/JetBrains.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

public enum JetBrains {
APPLE {
@Override public String text() {
return "Cupertino tech company";
}
},
ORANGE
;
public String text() {
return "Boring default";
}
}
11 changes: 11 additions & 0 deletions test/files/neg/t12800/matcher_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

// scalac: -Werror -Xsource:3

import JetBrains.*

class C {
def f(jb: JetBrains): Int =
jb match {
case APPLE => 42
}
}
14 changes: 14 additions & 0 deletions test/files/pos/t12800/JetBrains.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

public enum JetBrains {
APPLE {
@Override public String text() {
return "Cupertino tech company";
}
},
ORANGE {
@Override public String text() {
return "SoCal county";
}
};
public abstract String text();
}
12 changes: 12 additions & 0 deletions test/files/pos/t12800/matcher_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

// scalac: -Werror -Xsource:3

import JetBrains.*

class C {
def f(jb: JetBrains): Int =
jb match {
case APPLE => 42
case ORANGE => 27
}
}