Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrey Loskutov2019-12-06 22:59:59 +0000
committerStephan Herrmann2019-12-15 21:38:10 +0000
commitbea783c841d5c85a86f047b715181e363e74ba62 (patch)
treea15b7af344d54a8d1887786a5e9f8a65d0be4b53
parentb232dab5f7ce89322dae86fcd5334d03116ec929 (diff)
downloadeclipse.jdt.core-bea783c841d5c85a86f047b715181e363e74ba62.tar.gz
eclipse.jdt.core-bea783c841d5c85a86f047b715181e363e74ba62.tar.xz
eclipse.jdt.core-bea783c841d5c85a86f047b715181e363e74ba62.zip
Bug 553885 - BootstrapMethodError for method reference to inheritedI20191215-1800
non-public default method See https://bugs.openjdk.java.net/browse/JDK-8068253 as root cause and https://bugs.openjdk.java.net/browse/JDK-8068254 as workaround in javac. Reference expressions to default methods from package protected interfaces should use implicit lambda methods to avoid runtime errors. Change-Id: Iec5121bd4d8814a4348519dd25efc454deb61908 Signed-off-by: Andrey Loskutov <loskutov@gmx.de> Also-by: Stephan Herrmann <stephan.herrmann@berlin.de>
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java103
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java4
2 files changed, 106 insertions, 1 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java
index 5be3c39bc7..b11075770d 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java
@@ -6846,6 +6846,109 @@ public void testBug529199() {
"A.m"
);
}
+public void testBug553885a() {
+ runConformTest(
+ new String[] {
+ "p2/Test.java",
+ "package p2;\n" +
+ "import java.util.Optional;\n" +
+ "import p1.B;\n" +
+ "import p1.BImpl;\n" +
+ "\n" +
+ "public class Test {\n" +
+ " public static void main(String[] args) {\n" +
+ " Optional<Integer> map = Optional.of(new BImpl()).map(B::amount);\n" +
+ " System.out.print(map);\n" +
+ " }\n" +
+ "}",
+ "p1/A.java",
+ "package p1;\n" +
+ "interface A {\n" +
+ " default int amount() {\n" +
+ " return 0;\n" +
+ " }\n" +
+ "}\n",
+ "p1/B.java",
+ "package p1;\n" +
+ "public interface B extends A {}\n" +
+ "\n",
+ "p1/BImpl.java",
+ "package p1;\n" +
+ "public class BImpl implements B {}\n",
+ },
+ "Optional[0]"
+ );
+}
+public void testBug553885b() {
+ runConformTest(
+ new String[] {
+ "p2/Test.java",
+ "package p2;\n" +
+ "import java.util.Optional;\n" +
+ "import p1.B;\n" +
+ "import p1.BImpl;\n" +
+ "\n" +
+ "public class Test {\n" +
+ " public static void main(String[] args) {\n" +
+ " B b = new BImpl();\n" + // lead inference towards Optional<B> instead of Optional<BImpl>
+ " Optional<Integer> map = Optional.of(b).map(B::amount);\n" +
+ " System.out.print(map);\n" +
+ " }\n" +
+ "}",
+ "p1/A.java",
+ "package p1;\n" +
+ "interface A {\n" +
+ " default int amount() {\n" +
+ " return 0;\n" +
+ " }\n" +
+ "}\n",
+ "p1/B.java",
+ "package p1;\n" +
+ "public interface B extends A {}\n" +
+ "\n",
+ "p1/BImpl.java",
+ "package p1;\n" +
+ "public class BImpl implements B {}\n",
+ },
+ "Optional[0]"
+ );
+}
+public void testBug553885c() {
+ // classes instead of interface with default method
+ runConformTest(
+ new String[] {
+ "p2/Test.java",
+ "package p2;\n" +
+ "import java.util.Optional;\n" +
+ "import p1.B;\n" +
+ "import p1.BImpl;\n" +
+ "\n" +
+ "public class Test {\n" +
+ " public static void main(String[] args) {\n" +
+ " B b = new BImpl();\n" +
+ " Optional<Integer> map = Optional.of(b).map(B::amount);\n" +
+ " System.out.print(map);\n" +
+ " }\n" +
+ "}",
+ "p1/A.java",
+ "package p1;\n" +
+ "class A {\n" +
+ " public int amount() {\n" +
+ " return 0;\n" +
+ " }\n" +
+ "}\n",
+ "p1/B.java",
+ "package p1;\n" +
+ "public class B extends A {}\n" +
+ "\n",
+ "p1/BImpl.java",
+ "package p1;\n" +
+ "public class BImpl extends B {}\n",
+ },
+ "Optional[0]"
+ );
+}
+
public void testBug521182() {
runConformTest(
new String[] {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
index cfa39258eb..dc687c59df 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
@@ -287,9 +287,11 @@ public class ReferenceExpression extends FunctionalExpression implements IPolyEx
if (TypeBinding.notEquals(this.binding.declaringClass, this.lhs.resolvedType.erasure())) {
// reference to a method declared by an inaccessible type accessed via a
// subtype - normally a bridge method would be present to facilitate
- // this access, unless the method is final/static, in which case, direct access to
+ // this access, unless the method is final/static/default, in which case, direct access to
// the method is not possible, an implicit lambda is needed
if (!this.binding.declaringClass.canBeSeenBy(this.enclosingScope)) {
+ if (this.binding.isDefaultMethod())
+ return false; // workaround for bug in MethodHandle lookup, see https://bugs.openjdk.java.net/browse/JDK-8068253
return !(this.binding.isFinal() || this.binding.isStatic());
}
}

Back to the top