8293348: A false cyclic inheritance error reported

Reviewed-by: vromero
This commit is contained in:
Jan Lahoda 2022-09-08 14:10:06 +00:00
parent 85ec1f8d02
commit c0ee30a25a
3 changed files with 66 additions and 46 deletions

View File

@ -497,6 +497,7 @@ public class Enter extends JCTree.Visitor {
c.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, c, tree) | FROM_SOURCE;
c.classfile = c.sourcefile = env.toplevel.sourcefile;
c.members_field = WriteableScope.create(c);
c.isPermittedExplicit = tree.permitting.nonEmpty();
c.clearAnnotationMetadata();
ClassType ct = (ClassType)c.type;

View File

@ -728,14 +728,6 @@ public class TypeEnter implements Completer {
}
}
// Determine permits.
ListBuffer<Symbol> permittedSubtypeSymbols = new ListBuffer<>();
List<JCExpression> permittedTrees = tree.permitting;
for (JCExpression permitted : permittedTrees) {
Type pt = attr.attribBase(permitted, baseEnv, false, false, false);
permittedSubtypeSymbols.append(pt.tsym);
}
if ((sym.flags_field & ANNOTATION) != 0) {
ct.interfaces_field = List.of(syms.annotationType);
ct.all_interfaces_field = ct.interfaces_field;
@ -744,15 +736,6 @@ public class TypeEnter implements Completer {
ct.all_interfaces_field = (all_interfaces == null)
? ct.interfaces_field : all_interfaces.toList();
}
/* it could be that there are already some symbols in the permitted list, for the case
* where there are subtypes in the same compilation unit but the permits list is empty
* so don't overwrite the permitted list if it is not empty
*/
if (!permittedSubtypeSymbols.isEmpty()) {
sym.permitted = permittedSubtypeSymbols.toList();
}
sym.isPermittedExplicit = !permittedSubtypeSymbols.isEmpty();
}
//where:
protected JCExpression clearTypeParams(JCExpression superType) {
@ -763,7 +746,7 @@ public class TypeEnter implements Completer {
private final class HierarchyPhase extends AbstractHeaderPhase implements Completer {
public HierarchyPhase() {
super(CompletionCause.HIERARCHY_PHASE, new PermitsPhase());
super(CompletionCause.HIERARCHY_PHASE, new HeaderPhase());
}
@Override
@ -837,33 +820,6 @@ public class TypeEnter implements Completer {
}
private final class PermitsPhase extends AbstractHeaderPhase {
public PermitsPhase() {
super(CompletionCause.HIERARCHY_PHASE, new HeaderPhase());
}
@Override
protected void runPhase(Env<AttrContext> env) {
JCClassDecl tree = env.enclClass;
if (!tree.sym.isAnonymous() || tree.sym.isEnum()) {
for (Type supertype : types.directSupertypes(tree.sym.type)) {
if (supertype.tsym.kind == TYP) {
ClassSymbol supClass = (ClassSymbol) supertype.tsym;
Env<AttrContext> supClassEnv = enter.getEnv(supClass);
if (supClass.isSealed() &&
!supClass.isPermittedExplicit &&
supClassEnv != null &&
supClassEnv.toplevel == env.toplevel) {
supClass.permitted = supClass.permitted.append(tree.sym);
}
}
}
}
}
}
private final class HeaderPhase extends AbstractHeaderPhase {
public HeaderPhase() {
@ -887,6 +843,8 @@ public class TypeEnter implements Completer {
attribSuperTypes(env, baseEnv);
fillPermits(tree, baseEnv);
Set<Type> interfaceSet = new HashSet<>();
for (JCExpression iface : tree.implementing) {
@ -915,6 +873,36 @@ public class TypeEnter implements Completer {
sym.flags_field |= AUXILIARY;
}
}
private void fillPermits(JCClassDecl tree, Env<AttrContext> baseEnv) {
ClassSymbol sym = tree.sym;
//fill in implicit permits in supertypes:
if (!sym.isAnonymous() || sym.isEnum()) {
for (Type supertype : types.directSupertypes(sym.type)) {
if (supertype.tsym.kind == TYP) {
ClassSymbol supClass = (ClassSymbol) supertype.tsym;
Env<AttrContext> supClassEnv = enter.getEnv(supClass);
if (supClass.isSealed() &&
!supClass.isPermittedExplicit &&
supClassEnv != null &&
supClassEnv.toplevel == baseEnv.toplevel) {
supClass.permitted = supClass.permitted.append(sym);
}
}
}
}
// attribute (explicit) permits of the current class:
if (sym.isPermittedExplicit) {
ListBuffer<Symbol> permittedSubtypeSymbols = new ListBuffer<>();
List<JCExpression> permittedTrees = tree.permitting;
for (JCExpression permitted : permittedTrees) {
Type pt = attr.attribBase(permitted, baseEnv, false, false, false);
permittedSubtypeSymbols.append(pt.tsym);
}
sym.permitted = permittedSubtypeSymbols.toList();
}
}
}
private abstract class AbstractMembersPhase extends Phase {

View File

@ -22,7 +22,7 @@
*/
/*
* @test 8247352
* @test 8247352 8293348
* @summary test different configurations of sealed classes, same compilation unit, diff pkg or mdl, etc
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
@ -662,4 +662,35 @@ public class SealedDiffConfigurationsTest extends TestRunner {
.writeAll()
.getOutputLines(OutputKind.DIRECT);
}
@Test //JDK-8293348
public void testSupertypePermitsLoop(Path base) throws Exception {
Path src = base.resolve("src");
tb.writeJavaFiles(src,
"class Main implements T2 {}",
"non-sealed interface T2 extends T {}",
"sealed interface T permits T2 {}");
Path out = base.resolve("out");
Files.createDirectories(out);
new JavacTask(tb)
.outdir(out)
.files(findJavaFiles(src))
.run()
.writeAll();
Files.delete(out.resolve("Main.class"));
Files.delete(out.resolve("T.class"));
new JavacTask(tb)
.outdir(out)
.options("-cp", out.toString(),
"-sourcepath", src.toString())
.files(src.resolve("Main.java"))
.run()
.writeAll();
}
}