blob: b13e295c3313ba2673eee79c7f3000439ea3d8fd [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Stephan Herrmann - Contribution for
* Bug 446691 - [1.8][null][compiler] NullPointerException in SingleNameReference.analyseCode
*******************************************************************************/
package org.eclipse.jdt.core.tests.compiler.regression;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.tests.compiler.regression.AbstractRegressionTest.JavacTestOptions.EclipseHasABug;
import org.eclipse.jdt.core.tests.compiler.regression.AbstractRegressionTest.JavacTestOptions.JavacHasABug;
import junit.framework.Test;
@SuppressWarnings({ "rawtypes" })
public class LambdaRegressionTest extends AbstractRegressionTest {
static {
// TESTS_NAMES = new String[] { "test001"};
// TESTS_NUMBERS = new int[] { 50 };
// TESTS_RANGE = new int[] { 11, -1 };
}
public LambdaRegressionTest(String name) {
super(name);
}
public static Test suite() {
return buildMinimalComplianceTestSuite(testClass(), F_1_8);
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=446317, java.lang.VerifyError: Bad type on operand stack with Lambdas and/or inner classes
public void test001() {
this.runConformTest(
new String[] {
"X.java",
"import java.util.HashMap;\n" +
"import java.util.Map;\n" +
"import java.util.function.Function;\n" +
"public class X {\n" +
" public static void main(String[] args) {\n" +
" new X().run();\n" +
" }\n" +
" public void run() {\n" +
" class Inner {\n" +
" public Inner() {\n" +
" System.out.println(\"miep\");\n" +
" }\n" +
" }\n" +
" Map<String, Inner> map = new HashMap<>();\n" +
" Function<String, Inner> function = (name) -> {\n" +
" Inner i = map.get(name);\n" +
" if (i == null) {\n" +
" i = new Inner();\n" +
" map.put(name, i);\n" +
" }\n" +
" return i;\n" +
"\n" +
" };\n" +
" function.apply(\"test\");\n" +
" }\n" +
"}\n",
},
"miep"
);
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=446317, java.lang.VerifyError: Bad type on operand stack with Lambdas and/or inner classes
public void test002() {
this.runNegativeTest(
false,
EclipseHasABug.EclipseBug529197,
new String[] {
"X.java",
"import java.util.function.Consumer;\n" +
"@SuppressWarnings(\"all\")\n" +
"public class X {\n" +
" private final String text = \"Bug?\";\n" +
" public static void main(String[] args) {\n" +
" new X().doIt();\n" +
" }\n" +
" private void doIt() {\n" +
" new Sub();\n" +
" }\n" +
" private class Super<T> {\n" +
" public Super(Consumer<T> consumer) {\n" +
" }\n" +
" }\n" +
" private class Sub extends Super<String> {\n" +
" public Sub() {\n" +
" super(s -> System.out.println(text));\n" +
" // super(s -> System.out.println(\"miep\"));\n" +
" }\n" +
" }\n" +
"}\n",
},
"----------\n" +
"1. ERROR in X.java (at line 17)\n" +
" super(s -> System.out.println(text));\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
"Cannot refer to \'this\' nor \'super\' while explicitly invoking a constructor\n" +
"----------\n"
);
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=446317, java.lang.VerifyError: Bad type on operand stack with Lambdas and/or inner classes
public void test003() {
this.runNegativeTest(
new String[] {
"X.java",
"import java.util.function.Consumer;\n" +
"@SuppressWarnings(\"all\")\n" +
"public class X {\n" +
" private final String text = \"Bug?\";\n" +
" public static void main(String[] args) {\n" +
" new X().doIt();\n" +
" }\n" +
" private void doIt() {\n" +
" new Sub();\n" +
" }\n" +
" private class Super<T> {\n" +
" public Super(Consumer<T> consumer) {\n" +
" }\n" +
" }\n" +
" private class Sub extends Super<String> {\n" +
" public Sub() {\n" +
" super(s -> System.out.println(\"miep\"));\n" +
" }\n" +
" }\n" +
"}\n",
},
""
);
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=446317, java.lang.VerifyError: Bad type on operand stack with Lambdas and/or inner classes
public void test004() {
this.runConformTest(
false,
JavacHasABug.JavacThrowsAnException,
new String[] {
"Y.java",
"import java.util.function.Supplier;\n" +
"class E {\n" +
" E(Supplier<Object> factory) { }\n" +
"}\n" +
"public class Y extends E {\n" +
" Y() {\n" +
" super( () -> {\n" +
" class Z extends E {\n" +
" Z() {\n" +
" super(() -> new Object());\n" +
" }\n" +
" }\n" +
" return null;\n" +
" });\n" +
" }\n" +
" public static void main(String[] args) {\n" +
" new Y();\n" +
" }\n" +
"}"
},
null);
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448724, [1.8] [compiler] Wrong resolution of overloaded method when irrelevant type parameter is present and lambda is used as parameter
public void test448724() {
this.runConformTest(
new String[] {
"X.java",
"import java.util.concurrent.Callable;\n" +
"public class X {\n" +
" public void mismatchRunnableCallable() throws Exception {\n" +
" //Resolves to case1(Runnable) method invocation; lambda with block\n" +
" case1(() -> {\"abc\".length();});\n" +
" //Resolves to case1(Callable) method invocation, resulting in type mismatch; block removed - lambda with expression\n" +
" case1(() -> \"abc\".length());\n" +
" }\n" +
" public void noSuchMismatch() throws Exception {\n" +
" //no difference to case1 \n" +
" case2(() -> {\"abc\".length();});\n" +
" //the only difference to case 1 is the missing irrelevant <T> type parameter. Properly resolves to case2(Runnable) here\n" +
" case2(() -> \"abc\".length());\n" +
" }\n" +
" public void case1(final Runnable r) {\n" +
" System.out.println(\"case1: Runnable\");\n" +
" }\n" +
" public <T> void case1(Callable<Boolean> c) {\n" +
" System.out.println(\"case1: Callable\");\n" +
" }\n" +
" public void case2(final Runnable supplier) {\n" +
" System.out.println(\"case2: Runnable\");\n" +
" }\n" +
" public void case2(Callable<Boolean> conditionEvaluator) {\n" +
" System.out.println(\"case2: Callable\");\n" +
" }\n" +
" public static void main(String[] args) throws Exception {\n" +
" new X().mismatchRunnableCallable();\n" +
" new X().noSuchMismatch();\n" +
" }\n" +
"}\n"
},
"case1: Runnable\n" +
"case1: Runnable\n" +
"case2: Runnable\n" +
"case2: Runnable");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=447767, [1.8][compiler] Spurious method not applicable error due to interaction between overload resolution and type inference
public void test447767() {
this.runConformTest(
new String[] {
"X.java",
"interface I<T, U, V> {\n" +
" T goo(U u, V v);\n" +
"}\n" +
"public class X {\n" +
" static <T, U, V> T foo(T t, U u, V v) {\n" +
" System.out.println(\"Wrong!\");\n" +
" return null;\n" +
" }\n" +
" static <T, U, V> V foo(T t, U u, I<T, U, V> i) {\n" +
" System.out.println(\"Right!\");\n" +
" return null;\n" +
" }\n" +
" public static void main(String[] args) {\n" +
" String s = goo(foo(\"String\", \"String\", (u, v) -> v));\n" +
" }\n" +
" static <T> T goo(T t) {\n" +
" return t; \n" +
" }\n" +
"}\n"
},
"Right!");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=447767, [1.8][compiler] Spurious method not applicable error due to interaction between overload resolution and type inference
public void test447767a() {
this.runNegativeTest(
new String[] {
"X.java",
"interface I<T, U, V> {\n" +
" T goo(U u, V v);\n" +
"}\n" +
"public class X {\n" +
" static <T, U, V> T foo(T t, U u, I<T, U, V> i) {\n" +
" return null;\n" +
" }\n" +
" public static void main(String[] args) {\n" +
" String s = goo(foo(\"String\", \"String\", (u, v) -> v));\n" +
" }\n" +
" static <T> T goo(T t) {\n" +
" return t; \n" +
" }\n" +
"}\n"
},
"----------\n" +
"1. ERROR in X.java (at line 9)\n" +
" String s = goo(foo(\"String\", \"String\", (u, v) -> v));\n" +
" ^\n" +
"Type mismatch: cannot convert from Object to String\n" +
"----------\n");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=447767, [1.8][compiler] Spurious method not applicable error due to interaction between overload resolution and type inference
public void test447767b() {
this.runConformTest(
new String[] {
"X.java",
"interface I<T, U, V> {\n" +
" T goo(U u, V v);\n" +
"}\n" +
"public class X {\n" +
" static String goo(String s, String s2) {\n" +
" return null;\n" +
" }\n" +
" static <T, U, V> V foo(T t, U u, I<T, U, V> i) {\n" +
" System.out.println(\"Right!\");\n" +
" return null;\n" +
" }\n" +
" public static void main(String[] args) {\n" +
" String s = goo(foo(\"String\", \"String\", X::goo));\n" +
" }\n" +
" static <T> T goo(T t) {\n" +
" return t; \n" +
" }\n" +
"}\n"
},
"Right!");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=447767, [1.8][compiler] Spurious method not applicable error due to interaction between overload resolution and type inference
public void test447767c() {
this.runConformTest(
new String[] {
"X.java",
"interface I<T, U, V> {\n" +
" T goo(U u, V v);\n" +
"}\n" +
"public class X {\n" +
" static String goo(String s, String s2) {\n" +
" return null;\n" +
" }\n" +
" static <T, U, V> T foo(T t, U u, V v) {\n" +
" System.out.println(\"Wrong!\");\n" +
" return null;\n" +
" }\n" +
" static <T, U, V> V foo(T t, U u, I<T, U, V> i) {\n" +
" System.out.println(\"Right!\");\n" +
" return null;\n" +
" }\n" +
" public static void main(String[] args) {\n" +
" String s = goo(foo(\"String\", \"String\", X::goo));\n" +
" }\n" +
" static <T> T goo(T t) {\n" +
" return t; \n" +
" }\n" +
"}\n"
},
"Right!");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=447767, [1.8][compiler] Spurious method not applicable error due to interaction between overload resolution and type inference
public void test447767d() {
this.runConformTest(
new String[] {
"X.java",
"interface I<T, U, V> {\n" +
" T goo(U u, V v);\n" +
"}\n" +
"public class X {\n" +
" static String goo(String s, String s2) {\n" +
" return null;\n" +
" }\n" +
" static <T, U, V> T foo(T t, U u, V v) {\n" +
" System.out.println(\"Wrong!\");\n" +
" return null;\n" +
" }\n" +
" static <T, U, V> V foo(T t, U u, I<T, U, V> i) {\n" +
" System.out.println(\"Right!\");\n" +
" return null;\n" +
" }\n" +
" public static void main(String[] args) {\n" +
" String s = goo(foo(\"String\", \"String\", X::goo));\n" +
" }\n" +
" static <T> T goo(T t) {\n" +
" return t; \n" +
" }\n" +
"}\n"
},
"Right!");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=449410, [1.8][compiler] Eclipse java compiler does not detect a bad return type in lambda expression
public void test449410() {
this.runNegativeTest(
new String[] {
"X.java",
"import java.util.Collections;\n" +
"public class X {\n" +
" public static void main(String[] args) {\n" +
" Collections.emptyMap()\n" +
" .entrySet()\n" +
" .forEach(entry -> test() ? bad() : returnType());\n" +
" }\n" +
" private static boolean test() {\n" +
" return (System.currentTimeMillis() & 0x1) == 0;\n" +
" }\n" +
" private static void returnType() {\n" +
" }\n" +
" private static void bad() {\n" +
" }\n" +
"}\n"
},
"----------\n" +
"1. ERROR in X.java (at line 6)\n" +
" .forEach(entry -> test() ? bad() : returnType());\n" +
" ^^^^^^^\n" +
"The method forEach(Consumer<? super Map.Entry<Object,Object>>) in the type Iterable<Map.Entry<Object,Object>> is not applicable for the arguments ((<no type> entry) -> {})\n" +
"----------\n" +
"2. ERROR in X.java (at line 6)\n" +
" .forEach(entry -> test() ? bad() : returnType());\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
"Invalid expression as statement\n" +
"----------\n");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=449824, [1.8] Difference in behaviour with method references and lambdas
// Captures present behavior - may not be correct.
public void test449824() {
this.runNegativeTest(
new String[] {
"X.java",
"public class X {\n" +
" public static void main(String[] args) {\n" +
" Concrete<Target> fl = new Concrete<Target>();\n" +
" fl.call(each -> each.doSomething()); // fails\n" +
" fl.call((Target each) -> each.doSomething()); // fails\n" +
" fl.call(Target::doSomething); // succeeds in Eclipse 4.5M3 and 4.4.1\n" +
" // but fails in Java 8 1.8.0_11\n" +
" }\n" +
" public static class Target {\n" +
" public void doSomething() {\n" +
" }\n" +
" }\n" +
" public static class Concrete<T> implements Left<T>, Right<T> {\n" +
" public void call(RightHand<? super T> p) {\n" +
" }\n" +
" }\n" +
" public interface Left<T> {\n" +
" default void call(LeftHand<? super T> p) {\n" +
" }\n" +
" }\n" +
" public interface LeftHand<T> {\n" +
" public void left(T t);\n" +
" }\n" +
" public interface Right<T> {\n" +
" public void call(RightHand<? super T> p);\n" +
" }\n" +
" public interface RightHand<T> {\n" +
" public void right(T t);\n" +
" }\n" +
"}\n"
},
"----------\n" +
"1. ERROR in X.java (at line 4)\n" +
" fl.call(each -> each.doSomething()); // fails\n" +
" ^^^^\n" +
"The method call(X.RightHand<? super X.Target>) is ambiguous for the type X.Concrete<X.Target>\n" +
"----------\n" +
"2. ERROR in X.java (at line 6)\n" +
" fl.call(Target::doSomething); // succeeds in Eclipse 4.5M3 and 4.4.1\n" +
" ^^^^\n" +
"The method call(X.RightHand<? super X.Target>) is ambiguous for the type X.Concrete<X.Target>\n" +
"----------\n");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448954, [1.8][compiler] Suspect error: "The method foo(String, String, X::goo) is undefined for the type X"
public void test448954() {
this.runConformTest(
new String[] {
"X.java",
"interface I<T, U, V> {\n" +
" T goo(U u, V v);\n" +
"}\n" +
"interface J {\n" +
" void foo();\n" +
"}\n" +
"public class X {\n" +
" static String goo(String s, String s2) {\n" +
" return null;\n" +
" }\n" +
" static <T, U, V> T foo(T t, U u, J j) {\n" +
" System.out.println(\"Wrong!\");\n" +
" return null;\n" +
" }\n" +
" static <T, U, V> V foo(T t, U u, I<T, U, V> i) {\n" +
" System.out.println(\"Right!\");\n" +
" return null;\n" +
" }\n" +
" public static void main(String[] args) {\n" +
" String s = goo(foo(\"String\", \"String\", X::goo));\n" +
" }\n" +
" static <T> T goo(T t) {\n" +
" return t;\n" +
" }\n" +
"}\n"
},
"Right!");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=450380, [1.8][compiler] NPE in Scope.getExactConstructor(..) for bad constructor reference
public void test450380() {
this.runNegativeTest(
new String[] {
"X.java",
"import java.util.ArrayList;\n" +
"import java.util.function.IntFunction;\n" +
"public class X {\n" +
" IntFunction<ArrayList<String>> noo() {\n" +
" return System::new;\n" +
" }\n" +
"}\n"
},
"----------\n" +
"1. ERROR in X.java (at line 5)\n" +
" return System::new;\n" +
" ^^^^^^^^^^^\n" +
"The type System does not define System(int) that is applicable here\n" +
"----------\n");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=450604, [1.8] CCE at InferenceContext18.getParameter line 1377
public void test450604() {
this.runNegativeTest(
new String[] {
"X.java",
"import java.io.IOException;\n" +
"import java.util.List;\n" +
"import java.util.function.Function;\n" +
"public class X<T, E extends Exception> {\n" +
" public static <T> List<T> of(T one) { return null; }\n" +
" public @SafeVarargs static <T> List<T> of(T... items) { return null; }\n" +
" public static void printDependencyLoops() throws IOException {\n" +
" Function<? super String, ? extends List<String>> mapping = X::of;\n" +
" }\n" +
"}\n"
},
"");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=450604, [1.8] CCE at InferenceContext18.getParameter line 1377
public void test450604a() {
this.runConformTest(
new String[] {
"X.java",
"import java.util.List;\n" +
"public class X {\n" +
" public static <T> List<T> of() { return null; }\n" +
" public static @SafeVarargs <T> List<T> of(T... values) { return null; }\n" +
" static void walkAll() {\n" +
" X.<String> of();\n" +
" }\n" +
"}\n"
});
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=451677, [1.8][compiler] missing type inference
public void _test451677() {
this.runConformTest(
new String[] {
"X.java",
"import java.util.ArrayList;\n" +
"import java.util.function.Function;\n" +
"public class X {\n" +
" public static void test() {\n" +
" operationOnCreated(create(123, size -> new ArrayList<Integer>(size)), l -> l.size()); // works with: (ArrayList<Integer> l) -> l.size()\n" +
" }\n" +
" public static <R, A> R create(A arg, Function<A, R> factory) {\n" +
" return factory.apply(arg);\n" +
" }\n" +
" public static <R, A> R operationOnCreated(A created, Function<A, R> function) {\n" +
" return function.apply(created);\n" +
" }\n" +
"}\n"
});
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=451840
// [1.8] java.lang.BootstrapMethodError when running code with constructor reference
public void testBug451840() {
runNegativeTest(new String [] {
"X.java",
"public class X {\n" +
" public static void main(String[] args) {\n" +
" X test = new X();\n" +
" MySupplier<X> s = test::new; // incorrect\n" +
" }\n" +
" public interface MySupplier<T> {\n" +
" T create();\n" +
" }\n" +
"}"},
"----------\n" +
"1. ERROR in X.java (at line 4)\n" +
" MySupplier<X> s = test::new; // incorrect\n" +
" ^^^^\n" +
"test cannot be resolved to a type\n" +
"----------\n");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448556
// [1.8][compiler] Invalid compiler error about effectively final variable outside the context of a lambda.
public void testBug4448556() {
this.runConformTest(new String [] {
"X.java",
"import java.io.Serializable;\n" +
"import java.util.Arrays;\n" +
"import java.util.List;\n" +
"public class X {\n" +
" private static final List<Integer> INTEGERS = Arrays.asList(1, 2, 3, 4);\n" +
" public static void main(String[] args) {\n" +
" for (int i = 0; i < INTEGERS.size(); i++) {\n" +
" MyPredicate<Integer> predicate = INTEGERS.get(i)::equals;\n" +
" }\n" +
" } \n" +
" public interface MyPredicate<T> extends Serializable {\n" +
" boolean accept(T each);\n" +
" }\n" +
"}"
},
"");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448556
// [1.8][compiler] Invalid compiler error about effectively final variable outside the context of a lambda.
public void testBug4448556a() {
this.runConformTest(new String [] {
"X.java",
"import java.io.Serializable;\n" +
"import java.util.Arrays;\n" +
"import java.util.List;\n" +
"public class X {\n" +
" int value = 0; \n" +
" private static final List<Integer> INTEGERS = Arrays.asList(1, 2, 3, 4);\n" +
" public Integer next() {\n" +
" return new Integer(++value);\n" +
" }\n" +
" public static void main(String[] args) {\n" +
" X t = new X();\n" +
" MyPredicate<Integer> predicate = t.next()::equals;\n" +
" System.out.println(\"Value \" + t.value + \" accept \" + predicate.accept(t.value));\n" +
" }\n" +
" public interface MyPredicate<T> extends Serializable {\n" +
" boolean accept(T each);\n" +
" }\n" +
"}"
},
"Value 1 accept true");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=453687
// [1.8][compiler]Incorrect errors when compiling code with Method References
public void testBug453687() {
this.runConformTest(new String [] {
"X.java",
"import static java.util.stream.Collectors.groupingBy;\n" +
"import static java.util.stream.Collectors.mapping;\n" +
"import static java.util.stream.Collectors.toSet;\n" +
"import java.util.Locale;\n" +
"import java.util.Map;\n" +
"import java.util.Set;\n" +
"import java.util.stream.Stream;\n" +
"public class X {\n" +
" public static void main(String[] args) {\n" +
" Map<String, Set<String>> countryLanguagesMap = Stream.of(Locale.getAvailableLocales()).collect(\n" +
" groupingBy(Locale::getDisplayCountry, mapping(Locale::getDisplayLanguage, toSet())));\n" +
" }\n" +
"} "
},
"");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=456481 - [1.8] VerifyError on constructor reference inside lambda
public void testBug456481() {
this.runConformTest(new String [] {
"Test.java",
"public class Test {\n" +
" interface Constructor {\n" +
" MyTest execute();\n" +
" }\n" +
" interface ArrayConstructor {\n" +
" MyTest[] execute(int no);\n" +
" }\n" +
" interface ParameterizedConstructor {\n" +
" MyParameterizedTest<String> execute();\n" +
" }\n" +
" class MyTest {\n" +
" MyTest() { System.out.println(\"Constructor executed\"); }\n" +
" }\n" +
" class MyParameterizedTest<T> {\n" +
" MyParameterizedTest() {\n" +
" System.out.println(\"Parameterized Constructor executed\");\n" +
" }\n" +
" }\n" +
" public Constructor getConstructor() {\n" +
" return getConstructor(() -> { return MyTest::new; });\n" +
" }\n" +
" public MyTest[] getArray(int no) {\n" +
" return new MyTest[no];\n" +
" }\n" +
" ArrayConstructor getArrayConstructor() {\n" +
" return getArrayConstructor(() -> {return MyTest[]::new;});\n" +
" }\n" +
" ParameterizedConstructor getParameterizedConstructor() {\n" +
" return getParameterizedConstructor(() -> {return MyParameterizedTest<String>::new;});\n" +
" }\n" +
" ArrayConstructor getArrayConstructor(ArrayWrapper w) {\n" +
" return w.unwrap();\n" +
" }\n" +
" public static void main(String argv[]) {\n" +
" Test t = new Test();\n" +
" MyTest mytest = t.getConstructor().execute();\n" +
" MyTest[] array = t.getArrayConstructor().execute(2);\n" +
" MyParameterizedTest<String> pt = t.getParameterizedConstructor().execute();\n" +
" }\n" +
" ParameterizedConstructor getParameterizedConstructor(PTWrapper ptw) {\n" +
" return ptw.unwrap();\n" +
" }\n" +
" Constructor getConstructor(Wrapper arg) {\n" +
" return arg.unwrap();\n" +
" }\n" +
" interface PTWrapper {\n" +
" ParameterizedConstructor unwrap();\n" +
" }\n" +
" interface ArrayWrapper {\n" +
" ArrayConstructor unwrap();\n" +
" }\n" +
" interface Wrapper {\n" +
" Constructor unwrap();\n" +
" }\n" +
"}"
},
"Constructor executed\n" +
"Parameterized Constructor executed");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=457007, VerifyError
public void testBug457007() {
this.runConformTest(new String [] {
"Test.java",
"public class Test {\n" +
" void method() {\n" +
" class Bar {}\n" +
" java.util.function.Function<String, Bar> f = str -> new Bar();\n" +
" }\n" +
" public static void main(String[] args) {\n" +
" System.out.println(\"done\");\n" +
" }\n" +
"}"
},
"done");
}
public void testBug446691_comment5() {
runConformTest(new String [] {
"Test.java",
"import java.util.*;\n" +
"\n" +
"public class Test {\n" +
" protected final Integer myInt;\n" +
"\n" +
" public Test() {\n" +
" myInt = Integer.valueOf(0);\n" +
" try {\n" +
" Optional.empty().orElseThrow(() -> new IllegalArgumentException(myInt.toString()));\n" +
" } catch (IllegalArgumentException e) {\n" +
" throw new RuntimeException();\n" +
" }\n" +
" return;\n" +
" }\n" +
"}\n"
});
}
public void testBug446691_comment8() {
runConformTest(new String [] {
"Boom.java",
"public class Boom {\n" +
" private final String field;\n" +
" public Boom(String arg) {\n" +
" this.field = arg;\n" +
" try {\n" +
" java.util.function.Supplier<String> supplier = () -> field;\n" +
" } catch (Exception e) {\n" +
" \n" +
" }\n" +
" }\n" +
"}\n"
});
}
public void testBug446691_comment14() {
runNegativeTest(new String [] {
"test/Main.java",
"package test;\n" +
"\n" +
"import java.util.logging.Logger;\n" +
"\n" +
"public class Main {\n" +
"\n" +
" private static final Logger LOG = Logger.getLogger(\"test\");\n" +
" private final static String value;\n" +
"\n" +
" static {\n" +
" try {\n" +
" LOG.info(() -> String.format(\"Value is: %s\", value));\n" +
" } catch (final Exception ex) {\n" +
" throw new ExceptionInInitializerError(ex);\n" +
" }\n" +
" }\n" +
"}"
},
"----------\n" +
"1. ERROR in test\\Main.java (at line 8)\n" +
" private final static String value;\n" +
" ^^^^^\n" +
"The blank final field value may not have been initialized\n" +
"----------\n" +
"2. ERROR in test\\Main.java (at line 12)\n" +
" LOG.info(() -> String.format(\"Value is: %s\", value));\n" +
" ^^^^^\n" +
"The blank final field value may not have been initialized\n" +
"----------\n");
}
// error in lambda even if field is assigned later
public void testBug446691_comment14b() {
runNegativeTest(new String [] {
"test/Main.java",
"package test;\n" +
"\n" +
"import java.util.logging.Logger;\n" +
"\n" +
"public class Main {\n" +
"\n" +
" private static final Logger LOG = Logger.getLogger(\"test\");\n" +
" private final static String value;\n" +
"\n" +
" static {\n" +
" try {\n" +
" LOG.info(() -> String.format(\"Value is: %s\", value));\n" +
" } catch (final Exception ex) {\n" +
" throw new ExceptionInInitializerError(ex);\n" +
" }\n" +
" value = \"\";" +
" }\n" +
"}"
},
"----------\n" +
"1. ERROR in test\\Main.java (at line 12)\n" +
" LOG.info(() -> String.format(\"Value is: %s\", value));\n" +
" ^^^^^\n" +
"The blank final field value may not have been initialized\n" +
"----------\n");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=463526
// Parenthesis are incorrectly allowed in lambda when LambdaBody is an expression statement
public void testBug463526() {
runNegativeTest(new String [] {
"Test.java",
"public class Test {\n" +
" public static void main(String[] args) {\n" +
" Receiver r = new Receiver();\n" +
" r.accept((l) -> (doItOnTheClass(new Object())));\n" +
" }\n" +
" public static void doItOnTheClass(Object o) {\n" +
" System.out.println(\"done it\");\n" +
" }\n" +
" public static class Receiver {\n" +
" public void accept(Listener l) {\n" +
" l.doIt(new Object());\n" +
" }\n" +
" }\n" +
" public static interface Listener {\n" +
" public void doIt(Object o);\n" +
" }\n" +
"}"
},
"----------\n" +
"1. ERROR in Test.java (at line 4)\n" +
" r.accept((l) -> (doItOnTheClass(new Object())));\n" +
" ^^^^^^\n" +
"The method accept(Test.Listener) in the type Test.Receiver is not applicable for the arguments ((<no type> l) -> {})\n" +
"----------\n" +
"2. ERROR in Test.java (at line 4)\n" +
" r.accept((l) -> (doItOnTheClass(new Object())));\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
"Invalid expression as statement\n" +
"----------\n");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=463526
// Parenthesis are incorrectly allowed in lambda when LambdaBody is an expression statement
public void testBug463526b() {
runNegativeTest(new String [] {
"Test.java",
"import java.util.function.Consumer;\n" +
"public class Test {\n" +
" public static void main(String[] args) {\n" +
" Receiver r = new Receiver();\n" +
" r.process((o) -> (new Object()));\n" +
" }\n" +
" public static class Receiver {\n" +
" public void process(Consumer<Object> p) {\n" +
" }\n" +
" }\n" +
"}"
},
"----------\n" +
"1. ERROR in Test.java (at line 5)\n" +
" r.process((o) -> (new Object()));\n" +
" ^^^^^^^\n" +
"The method process(Consumer<Object>) in the type Test.Receiver is not applicable for the arguments ((<no type> o) -> {})\n" +
"----------\n" +
"2. ERROR in Test.java (at line 5)\n" +
" r.process((o) -> (new Object()));\n" +
" ^^^^^^^^^^^^^^\n" +
"Void methods cannot return a value\n" +
"----------\n");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=463526
// Parenthesis are incorrectly allowed in lambda when LambdaBody is an expression statement
public void testBug463526c() {
runNegativeTest(new String [] {
"Test.java",
"import java.util.function.Consumer;\n" +
"public class Test {\n" +
" public static void main(String[] args) {\n" +
" Receiver r = new Receiver();\n" +
" r.assign((o) -> (o = new Object()));\n" +
" }\n" +
" public static class Receiver {\n" +
" public void assign(Consumer<Object> a) {\n" +
" }\n" +
" }\n" +
"}"
},
"----------\n" +
"1. ERROR in Test.java (at line 5)\n" +
" r.assign((o) -> (o = new Object()));\n" +
" ^^^^^^\n" +
"The method assign(Consumer<Object>) in the type Test.Receiver is not applicable for the arguments ((<no type> o) -> {})\n" +
"----------\n" +
"2. ERROR in Test.java (at line 5)\n" +
" r.assign((o) -> (o = new Object()));\n" +
" ^^^^^^^^^^^^^^^^^^\n" +
"Void methods cannot return a value\n" +
"----------\n");
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=464408
public void testBug464408() {
runNegativeTest(new String[]{
"test/X.java",
"import java.util.ArrayList;\n" +
"import java.util.List;\n" +
"public class X {\n" +
" void x() {\n" +
" List<List<String>> list = new ArrayList<>();\n" +
" list.stream().toArray(List<String>[]::new);\n" +
" }" +
"}"
}, "----------\n" +
"1. ERROR in test\\X.java (at line 6)\n" +
" list.stream().toArray(List<String>[]::new);\n" +
" ^^^^^^^^^^^^^^^^^^^\n" +
"Cannot create a generic array of List<String>\n" +
"----------\n");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=465900
// Internal compiler error: java.lang.IllegalArgumentException: info cannot be null at org.eclipse.jdt.internal.compiler.codegen.StackMapFrame.addStackItem(StackMapFrame.java:81)
public void testBug465900() {
this.runConformTest(new String [] {
"X.java",
"import java.io.Serializable;\n" +
"import java.util.ArrayList;\n" +
"import java.util.List;\n" +
"import java.util.function.Supplier;\n" +
"public class X {\n" +
" private static final long serialVersionUID = 1L;\n" +
" protected void x() {\n" +
" String str = \"groep.koppeling.\" + (\"\".isEmpty() ? \"toevoegen\" : \"bewerken\");\n" +
" List<String> bean = new ArrayList<>();\n" +
" test(bean.get(0)::isEmpty);\n" +
" }\n" +
" private void test(SerializableSupplier<Boolean> test) {}\n" +
"}\n" +
"@FunctionalInterface\n" +
"interface SerializableSupplier<T> extends Supplier<T>, Serializable {}\n"
},
"");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=477888
// [1.8][compiler] Compiler silently produces garbage but editor shows no errors
public void testBug477888() {
runNegativeTest(new String [] {
"Test.java",
"import java.io.IOException;\n" +
"import java.nio.file.Files;\n" +
"import java.nio.file.Paths;\n" +
"import java.util.function.Consumer;\n" +
"public class Test {\n" +
" public static void main(String[] args) throws IOException {\n" +
" Files.lines(Paths.get(args[0])).filter(x -> {return !x.startsWith(\".\");}).forEach(printMe());\n" +
" }\n" +
" private static Consumer<String> printMe() {\n" +
" return x -> x.isEmpty() ? System.out.println() : System.out.println(getIndex() + \" \" + x); // error must be reported here!\n" +
" }\n" +
" static int idx;\n" +
"\n" +
" private static int getIndex() {\n" +
" return ++idx;\n" +
" }\n" +
"}\n"
},
"----------\n" +
"1. ERROR in Test.java (at line 10)\n" +
" return x -> x.isEmpty() ? System.out.println() : System.out.println(getIndex() + \" \" + x); // error must be reported here!\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
"Invalid expression as statement\n" +
"----------\n");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=472648
// [compiler][1.8] Lambda expression referencing method with generic type has incorrect compile errors
public void testBug472648() {
runNegativeTest(
false,
JavacHasABug.JavacBugFixed_901,
new String [] {
"Test.java",
"import java.util.ArrayList;\n" +
"import java.util.List;\n" +
"import java.util.function.Consumer;\n" +
"public class Test {\n" +
" public static void main(String argv[]) {\n" +
" new Test();\n" +
" }\n" +
" public Test() {\n" +
" List<Number> numList = new ArrayList<>();\n" +
" numList.add(1);\n" +
" numList.add(1.5);\n" +
" numList.add(2);\n" +
" numList.add(2.5);\n" +
" forEachValueOfType(numList, Integer.class, (Integer i) -> (System.out.println(Integer.toString(i))));\n" +
" }\n" +
" private <T> void forEachValueOfType(List<?> list, Class<T> type, Consumer<T> action) {\n" +
" \n" +
" for (Object o : list) {\n" +
" if (type.isAssignableFrom(o.getClass())) {\n" +
" @SuppressWarnings(\"unchecked\")\n" +
" T convertedObject = (T) o;\n" +
" action.accept(convertedObject);\n" +
" }\n" +
" }\n" +
" }\n" +
"}"
},
"----------\n" +
"1. ERROR in Test.java (at line 14)\n" +
" forEachValueOfType(numList, Integer.class, (Integer i) -> (System.out.println(Integer.toString(i))));\n" +
" ^^^^^^^^^^^^^^^^^^\n" +
"The method forEachValueOfType(List<?>, Class<T>, Consumer<T>) in the type Test is not applicable for the arguments (List<Number>, Class<Integer>, (Integer i) -> {})\n" +
"----------\n" +
"2. ERROR in Test.java (at line 14)\n" +
" forEachValueOfType(numList, Integer.class, (Integer i) -> (System.out.println(Integer.toString(i))));\n" +
" ^^^^^^^\n" +
"Incompatible type specified for lambda expression's parameter i\n" +
"----------\n" +
"3. ERROR in Test.java (at line 14)\n" +
" forEachValueOfType(numList, Integer.class, (Integer i) -> (System.out.println(Integer.toString(i))));\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
"Invalid expression as statement\n" +
"----------\n");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=473432
// Internal compiler error: java.lang.IllegalArgumentException: info cannot be null at org.eclipse.jdt.internal.compiler.codegen.StackMapFrame.addStackItem(StackMapFrame.java:81)
public void testBug473432() {
this.runConformTest(new String [] {
"Tester.java",
"import java.util.function.Function;\n" +
"public class Tester {\n" +
" private static class ValueWrapper<O> {\n" +
" private O val_;\n" +
" public ValueWrapper(O val) {\n" +
" val_ = val;\n" +
" }\n" +
" public <R> R mapOrElse(Function<O, R> func, R defaultValue) {\n" +
" if(val_ != null) {\n" +
" return func.apply(val_);\n" +
" }\n" +
" return defaultValue;\n" +
" }\n" +
" }\n" +
" private static void handleObject(Object object) {\n" +
" System.out.println(\"Handled: \" + object);\n" +
" }\n" +
" public static void main(String[] args) {\n" +
" ValueWrapper<String> wrapper = new ValueWrapper<>(\"value\");\n" +
" boolean skipMethod = false;\n" +
" // works on both JDT 3.9.2 and 3.11.0\n" +
" Boolean result = skipMethod ? true : wrapper.mapOrElse(v -> false, null);\n" +
" System.out.println(result);\n" +
" wrapper = new ValueWrapper<>(null);\n" +
" // works on JDT 3.9.2\n" +
" handleObject(skipMethod ?\n" +
" true :\n" +
" wrapper.mapOrElse(v -> false, null));\n" +
" wrapper = new ValueWrapper<>(null);\n" +
" // works on neither version\n" +
" result = skipMethod ?\n" +
" true :\n" +
" wrapper.mapOrElse(v -> false, null);\n" +
" System.out.println(result);\n" +
" }\n" +
"}\n"
},
"false\n" +
"Handled: null\n" +
"null");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=511676 [1.8] Lambda with inner class defs causes java.lang.VerifyError: Bad type on operand stack
public void testBug511676() {
this.runConformTest(new String [] {
"A.java",
"import java.util.function.Function;\n" +
"public class A {\n" +
" interface C<T> { }\n" +
" interface O<T> {\n" +
" Object r(C<T> s);\n" +
" }\n" +
" static <T, R> O<R> m(O<T> source, Function<T, O<R>> mapper) {\n" +
" return o -> {\n" +
" class D {\n" +
" class E {\n" +
" }\n" +
" E e = new E();\n" +
" }\n" +
" D d = new D();\n" +
" return d.e;\n" +
" };\n" +
" }\n" +
" public static void main(String[] args) {\n" +
" m(null, null);\n" +
" System.out.println(\" Done\");\n" +
" }\n" +
"}\n"
},
"Done");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=511676 [1.8] Lambda with inner class defs causes java.lang.VerifyError: Bad type on operand stack
public void testBug511676a() {
this.runConformTest(new String [] {
"A.java",
"public class A {\n" +
" interface C<T> { }\n" +
" interface O<T> {\n" +
" Object r(C<T> s);\n" +
" }\n" +
" static O<Object> def = o -> {\n" +
" class D {\n" +
" class E {\n" +
" }\n" +
" E e = new E();\n" +
" }\n" +
" D d = new D();\n" +
" return d.e;\n" +
" };\n" +
" public static void main(String[] args) {\n" +
" O<Object> o = A.def;\n" +
" System.out.println(\" Done\");\n" +
" }\n" +
"}\n"
},
"Done");
}
public void testBug543778() {
Runner runner = new Runner();
runner.testFiles =
new String[] {
"Sandbox.java",
"import java.util.function.Supplier;\n" +
"\n" +
"public class Sandbox {\n" +
"\n" +
" <R extends Object> R get(Supplier<@NonNull R> impl) {\n" +
" return null;\n" +
" }\n" +
"\n" +
" Object getter() {\n" +
" return get(() -> new Object() {\n" +
"\n" +
" @Override\n" +
" public String toString() {\n" +
" return super.toString();\n" +
" }\n" +
"\n" +
" });\n" +
" }\n" +
"\n" +
"}\n",
"NonNull.java",
"import java.lang.annotation.ElementType;\n" +
"import java.lang.annotation.Retention;\n" +
"import java.lang.annotation.RetentionPolicy;\n" +
"import java.lang.annotation.Target;\n" +
"\n" +
"@Retention(RetentionPolicy.CLASS)\n" +
"@Target({ ElementType.TYPE_USE })\n" +
"public @interface NonNull {\n" +
" // marker annotation with no members\n" +
"}\n",
};
runner.customOptions = getCompilerOptions();
runner.customOptions.put(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED); // bug happens due to type annotation handling
runner.runConformTest();
}
public static Class testClass() {
return LambdaRegressionTest.class;
}
}