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

[Sealed types] Broken program crashes the compiler #3039

Closed
srikanth-sankaran opened this issue Oct 2, 2024 · 6 comments · Fixed by #3148
Closed

[Sealed types] Broken program crashes the compiler #3039

srikanth-sankaran opened this issue Oct 2, 2024 · 6 comments · Fixed by #3148
Assignees
Milestone

Comments

@srikanth-sankaran
Copy link
Contributor

While experimenting I found the following program to crash ECJ:

public interface X {

  static <T extends Object & I1 & I2> Integer get(T object) {
    return switch (object) {
      case A ignored -> 42;
    };
  }

  public abstract sealed interface I1 permits A, AB {
  }
  
  public abstract sealed interface I2 permits , AB {
  }

  
  final class A implements I1 {}
  final class B implements I2 {}
  final class AB implements I1, I2 {}

  public static void main(String[] args) {
   System.out.println(get(new ClassC()));
  }
}

Notice that I2's declaration is syntactically flawed. Nevertheless the compiler should not crash.

@srikanth-sankaran srikanth-sankaran self-assigned this Oct 2, 2024
@stephan-herrmann
Copy link
Contributor

@srikanth-sankaran during your work on sealed types, you may want to check if the following has any impact for ecj: https://bugs.openjdk.org/browse/JDK-8338981

Thanks, and sorry for hijacking this issue :)

@srikanth-sankaran
Copy link
Contributor Author

Thanks for the pointer. I'll follow up.

@srikanth-sankaran
Copy link
Contributor Author

Smaller test case:

public interface X {

  static <T extends Object & I2> Integer get(T object) {
    return switch (object) {
      case A ignored -> 42;
      default -> 42;
    };
  }

  public abstract sealed interface I2 permits , AB {
  }


  final class AB implements I2 {}

}

Stack trace:

java.lang.NullPointerException: Cannot invoke "org.eclipse.jdt.internal.compiler.lookup.ModuleBinding.isUnnamed()" because "sourceModuleBinding" is null
	at org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding.checkPermitsInType(SourceTypeBinding.java:1153)
	at org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding.faultInTypesForFieldsAndMethods(SourceTypeBinding.java:1117)
	at org.eclipse.jdt.internal.compiler.lookup.ClassScope.buildLocalTypeBinding(ClassScope.java:394)
	at org.eclipse.jdt.internal.compiler.lookup.BlockScope.addLocalType(BlockScope.java:129)
	at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.resolve(TypeDeclaration.java:1633)
	at org.eclipse.jdt.internal.compiler.ast.Statement.resolveWithBindings(Statement.java:496)
	at org.eclipse.jdt.internal.compiler.ast.ASTNode.resolveStatements(ASTNode.java:725)
	at org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration.resolveStatements(AbstractMethodDeclaration.java:713)
	at org.eclipse.jdt.internal.compiler.ast.MethodDeclaration.resolveStatements(MethodDeclaration.java:409)
	at org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration.resolve(AbstractMethodDeclaration.java:611)
	at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.resolve(TypeDeclaration.java:1537)
	at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.resolve(TypeDeclaration.java:1666)
	at org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration.resolve(CompilationUnitDeclaration.java:670)
	at org.eclipse.jdt.core.dom.CompilationUnitResolver.resolve(CompilationUnitResolver.java:1372)

@srikanth-sankaran
Copy link
Contributor Author

The relevant code has completely overhauled and this program doesn't crash anymore - I will add a regression test and close this.

@srikanth-sankaran
Copy link
Contributor Author

@srikanth-sankaran during your work on sealed types, you may want to check if the following has any impact for ecj: https://bugs.openjdk.org/browse/JDK-8338981

Thanks, and sorry for hijacking this issue :)

We compile the program fine!

This slightly modified program draws one error from ECJ: The type X.C is not visible

public sealed class X permits X.C {
    private final static class C extends X implements I {}
}

sealed interface I permits X.C {}

while javac complains:

X.java:5: error: C has private access in X
sealed interface I permits X.C {}
                            ^
X.java:1: error: C has private access in X
public sealed class X permits X.C {
                               ^
X.java:2: error: class is not allowed to extend sealed class: X (as it is not listed in its 'permits' clause)
    private final static class C extends X implements I {}
                         ^
3 errors

@srikanth-sankaran
Copy link
Contributor Author

public record X(I i) {
	private class I {}
}

This one compiles too - so we seem not to have a problem with * Access occurs in the record component list of the top level record class that encloses the declaration of the member. clause.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants