| /******************************************************************************* |
| * Copyright (c) 2018, 2019 Jesper Steen Møller 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: |
| * Jesper Steen Møller - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.core.tests.compiler.regression; |
| |
| import java.io.IOException; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.eclipse.jdt.core.tests.util.CompilerTestSetup; |
| import org.eclipse.jdt.internal.compiler.ASTVisitor; |
| import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; |
| import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; |
| import org.eclipse.jdt.internal.compiler.lookup.BlockScope; |
| import org.eclipse.jdt.internal.compiler.lookup.ClassScope; |
| import org.junit.Assert; |
| |
| import junit.framework.Test; |
| |
| @SuppressWarnings({ "unchecked", "rawtypes" }) |
| public class JEP286Test extends AbstractRegressionTest { |
| |
| public static Class testClass() { |
| return JEP286Test.class; |
| } |
| public void initialize(CompilerTestSetup setUp) { |
| super.initialize(setUp); |
| } |
| public static Test suite() { |
| return buildMinimalComplianceTestSuite(testClass(), F_10); |
| } |
| |
| public JEP286Test(String testName){ |
| super(testName); |
| } |
| static { |
| // TESTS_NAMES = new String[] { "test0018_project_variable_types" }; |
| } |
| protected Map getCompilerOptions() { |
| Map options = super.getCompilerOptions(); |
| options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_10); |
| options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_10); |
| options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_10); |
| return options; |
| } |
| private static final Map<String, String> simpleTypeNames = new HashMap<>(); |
| static { |
| simpleTypeNames.put("String", "java.lang.String"); |
| simpleTypeNames.put("Object", "java.lang.Object"); |
| simpleTypeNames.put("Bar", "X.Bar"); |
| |
| simpleTypeNames.put("AnonymousObjectSubclass", "new java.lang.Object(){}"); |
| simpleTypeNames.put("AnonymousRunnableSubclass", "new java.lang.Runnable(){}"); |
| simpleTypeNames.put("CollectionOfExtString", "Collection<? extends java.lang.String>"); |
| simpleTypeNames.put("CollectionOfSuperString", "Collection<? super java.lang.String>"); |
| simpleTypeNames.put("CollectionAny", "Collection<?>"); |
| simpleTypeNames.put("ComparableAny", "Comparable<?>"); |
| simpleTypeNames.put("CollectionExt_ComparableAny", "Collection<? extends Comparable<?>>"); |
| simpleTypeNames.put("CollectionSuperComparableAny", "Collection<? super Comparable<?>>"); |
| if (isJRE12Plus) |
| simpleTypeNames.put("IntLongFloat", "java.lang.Number & Comparable<?> & java.lang.constant.Constable & java.lang.constant.ConstantDesc"); |
| else |
| simpleTypeNames.put("IntLongFloat", "java.lang.Number & Comparable<?>"); |
| simpleTypeNames.put("ListTestAndSerializable", "List<? extends Z & java.io.Serializable>"); |
| simpleTypeNames.put("TestAndSerializable", "Z & java.io.Serializable"); |
| } |
| |
| static void assertInferredType(LocalDeclaration varDecl) { |
| String varName = new String(varDecl.name); |
| int underscoreIndex = varName.indexOf('_'); |
| Assert.assertNotEquals(-1, underscoreIndex); |
| String typeNamePart = varName.substring(underscoreIndex+1); |
| typeNamePart = typeNamePart.replaceAll("ARRAY", "[]"); // So that we assume that x_intARRAY is of type int[] |
| String expectedTypeName = simpleTypeNames.getOrDefault(typeNamePart, typeNamePart); |
| String actualTypeName = varDecl.binding.type.debugName(); |
| // System.out.println("For " + varName + ", we expect " + expectedTypeName + ", the type was: " |
| // + actualTypeName + " - " + (expectedTypeName.equals(actualTypeName) ? "❤️" : "🤡")); |
| Assert.assertEquals("Type of variable " + varName, expectedTypeName, actualTypeName); |
| } |
| |
| // This visitor visits the 'testXxx' method in the visited classes, checking for expected types of local variables (using the debug name) |
| private final static class InferredTypeVerifier extends ASTVisitor { |
| public int localsChecked = 0; |
| public InferredTypeVerifier() { } |
| |
| @Override |
| public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) { |
| return false; // Don't check Foo itself |
| } |
| |
| @Override |
| public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) { |
| if (! new String(methodDeclaration.selector).startsWith("test")) return false; |
| return super.visit(methodDeclaration, scope); |
| } |
| |
| @Override |
| public boolean visit(LocalDeclaration localDeclaration, BlockScope scope) { |
| assertInferredType(localDeclaration); |
| this.localsChecked++; |
| return super.visit(localDeclaration, scope); |
| } |
| } |
| |
| public void test0001_local_variable_inference() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public static void main(String [] args) {\n" + |
| " var x = \"SUCCESS\";\n" + |
| " System.out.println(x);\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "SUCCESS"); |
| } |
| public void test0002_inferred_for() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public static void main(String [] args) {\n" + |
| " int sum = 0;\n" + |
| " for(var n = 1; n <= 2; ++n) {\n" + |
| " sum += n;\n" + |
| " }\n" + |
| " System.out.println(\"SUCCESS \" + sum);\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "SUCCESS 3"); |
| } |
| public void test0003_inferred_enhanced_for() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public static void main(String [] args) {\n" + |
| " int sum = 0;\n" + |
| " for(var n : java.util.List.of(1, 2)) {\n" + |
| " sum += n;\n" + |
| " }\n" + |
| " System.out.println(\"SUCCESS \" + sum);\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "SUCCESS 3"); |
| } |
| public void test0004_try_with_resources() throws IOException { |
| try(java.io.Writer w = new java.io.StringWriter()) { |
| w.write("SUCCESS!\n"); |
| System.out.println(w.toString()); |
| } |
| |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public static void main(String [] args) throws Exception {\n" + |
| " try(var w = new java.io.StringWriter()) {\n" + |
| " w.write(\"SUCCESS\\n\");" + |
| " System.out.println(w.toString());\n" + |
| " }\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "SUCCESS"); |
| } |
| public void test0005_no_initializer() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public static void main(String[] argv) {\n" + |
| " var a;\n" + |
| " for(var b;;);\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 3)\n" + |
| " var a;\n" + |
| " ^\n" + |
| "Cannot use 'var' on variable without initializer\n" + |
| "----------\n" + |
| "2. ERROR in X.java (at line 4)\n" + |
| " for(var b;;);\n" + |
| " ^\n" + |
| "Cannot use 'var' on variable without initializer\n" + |
| "----------\n"); |
| } |
| public void test0006_multiple_declarators() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public static void main(String[] argv) {\n" + |
| " var a = 1, b = 2;\n" + |
| " for(var c = 1, d = 20; c<d; c++);\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 3)\n" + |
| " var a = 1, b = 2;\n" + |
| " ^\n" + |
| "'var' is not allowed in a compound declaration\n" + |
| "----------\n" + |
| "2. ERROR in X.java (at line 4)\n" + |
| " for(var c = 1, d = 20; c<d; c++);\n" + |
| " ^\n" + |
| "'var' is not allowed in a compound declaration\n" + |
| "----------\n"); |
| } |
| public void test0007_var_in_wrong_place() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " private var someField = 0;\n" + |
| " public var method() {\n" + |
| " return null;\n" + |
| " }\n" + |
| " public void main(var arg) {\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 2)\n" + |
| " private var someField = 0;\n" + |
| " ^^^\n" + |
| "'var' is not allowed here\n" + |
| "----------\n" + |
| "2. ERROR in X.java (at line 3)\n" + |
| " public var method() {\n" + |
| " ^^^\n" + |
| "'var' is not allowed here\n" + |
| "----------\n" + |
| "3. ERROR in X.java (at line 6)\n" + |
| " public void main(var arg) {\n" + |
| " ^^^\n" + |
| "'var' is not allowed here\n" + |
| "----------\n"); |
| } |
| public void test0008_null_initializer() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public void main(String[] arg) {\n" + |
| " var notMuch = null;\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 3)\n" + |
| " var notMuch = null;\n" + |
| " ^^^^^^^\n" + |
| "Cannot infer type for local variable initialized to 'null'\n" + |
| "----------\n"); |
| } |
| public void test0008_void_initializer() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public void foo() {\n" + |
| " }\n" + |
| "\n" + |
| " public void baz() {\n" + |
| " var nothingHere = foo();\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 6)\n" + |
| " var nothingHere = foo();\n" + |
| " ^^^^^^^^^^^\n" + |
| "Variable initializer is 'void' -- cannot infer variable type\n" + |
| "----------\n"); |
| } |
| public void test0009_var_as_type_name() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public enum var { V, A, R };\n" + |
| "}\n" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 2)\n" + |
| " public enum var { V, A, R };\n" + |
| " ^^^\n" + |
| "'var' is not a valid type name\n" + |
| "----------\n"); |
| } |
| public void test0010_array_initializer() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public void main(String [] args) {\n" + |
| " var myArray = { 1, 2, 3 };\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 3)\n" + |
| " var myArray = { 1, 2, 3 };\n" + |
| " ^^^^^^^\n" + |
| "Array initializer needs an explicit target-type\n" + |
| "----------\n"); |
| } |
| public void test0011_array_type() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public void main(String [] args) {\n" + |
| " var myArray[] = new int[42];\n" + |
| " var[] moreArray = new int[1337];\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 3)\n" + |
| " var myArray[] = new int[42];\n" + |
| " ^^^^^^^\n" + |
| "'var' is not allowed as an element type of an array\n" + |
| "----------\n" + |
| "2. ERROR in X.java (at line 4)\n" + |
| " var[] moreArray = new int[1337];\n" + |
| " ^^^^^^^^^\n" + |
| "'var' is not allowed as an element type of an array\n" + |
| "----------\n"); |
| } |
| public void test0012_self_reference() throws IOException { |
| |
| // BTW: This will give a VerifyError: int a = ((java.util.concurrent.Callable<Integer>)(() -> true ? 1 : a)).call(); |
| // The cases are tested. a is a simple case, with plain usage in the same scope. b is used in a nested scope. |
| // c and d are shadowed by the nested definitions. |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public void main(String [] args) {\n" + |
| " var a = 42 + a;\n" + |
| " var b = ((java.util.concurrent.Callable<Integer>)(() -> true ? 1 : b)).call();\n" + |
| " var c = new java.util.concurrent.Callable<Integer>() {\n" + |
| " public Integer call() {\n" + |
| " int c = 42; return c;\n" + |
| " }\n" + |
| " }.call();" + |
| " var d = new java.util.concurrent.Callable<Integer>() {\n" + |
| " int d = 42;\n" + |
| " public Integer call() {\n" + |
| " return d;\n" + |
| " }\n" + |
| " }.call();" + |
| " }\n" + |
| "}\n" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 3)\n" + |
| " var a = 42 + a;\n" + |
| " ^\n" + |
| "Declaration using 'var' may not contain references to itself\n" + |
| "----------\n" + |
| "2. ERROR in X.java (at line 4)\n" + |
| " var b = ((java.util.concurrent.Callable<Integer>)(() -> true ? 1 : b)).call();\n" + |
| " ^\n" + |
| "Declaration using 'var' may not contain references to itself\n" + |
| "----------\n" + |
| "3. WARNING in X.java (at line 7)\n" + |
| " int c = 42; return c;\n" + |
| " ^\n" + |
| "The local variable c is hiding another local variable defined in an enclosing scope\n" + |
| "----------\n"+ |
| "3. WARNING in X.java (at line 10)\n" + |
| " int d = 42;\n" + |
| " ^\n" + |
| "The field new Callable<Integer>(){}.d is hiding another local variable defined in an enclosing scope\n" + |
| "----------\n"); |
| } |
| public void test0013_lambda() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public void main(String [] args) {\n" + |
| " var a = (int i) -> 42;\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 3)\n" + |
| " var a = (int i) -> 42;\n" + |
| " ^\n" + |
| "Lambda expression needs an explicit target-type\n" + |
| "----------\n"); |
| } |
| public void test0014_method_reference() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public void main(String [] args) {\n" + |
| " var a = X::main;\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 3)\n" + |
| " var a = X::main;\n" + |
| " ^\n" + |
| "Method reference needs an explicit target-type\n" + |
| "----------\n"); |
| } |
| public void test0015_complain_over_first_poly_encountered() throws Exception { |
| |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public void main(String [] args) {\n" + |
| " var a = args.length > 1 ? X::main : (int i) -> 42;\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 3)\n" + |
| " var a = args.length > 1 ? X::main : (int i) -> 42;\n" + |
| " ^\n" + |
| "Method reference needs an explicit target-type\n" + |
| "----------\n"); |
| } |
| public void test0016_dont_capture_deep_poly_expressions() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public static void main(String [] args) throws Exception {\n" + |
| " var z = ((java.util.concurrent.Callable<String>)(() -> \"SUCCESS\"));\n" + |
| " var x = args.length > 1 ? \"FAILURE\" : z.call();\n" + |
| " System.out.println(x);\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "SUCCESS"); |
| } |
| //static <T extends List<? super E>, E extends List<? super Integer>> void doSomething(T[] e) { |
| // e[0] = null; |
| //} |
| |
| public void test0017_simple_variable_types() throws Exception { |
| InferredTypeVerifier typeVerifier = new InferredTypeVerifier(); |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "import java.util.List;\n" + |
| "\n" + |
| "public class X {\n" + |
| " void test() {\n" + |
| " var i_String = \"\";\n" + |
| " for (var i2_String = \"\" ; ; ) { break; }\n" + |
| " for (var i2_String : iterableOfString()) { break; }\n" + |
| " for (var i2_String : arrayOfString()) { break; }\n" + |
| " try (var i2_Bar = new Bar()) { } finally { }\n" + |
| " try (var i2_Bar = new Bar(); var i3_Bar = new Bar()) { } finally { }\n" + |
| " }\n" + |
| "\n" + |
| " Iterable<String> iterableOfString() { return null; }\n" + |
| " String[] arrayOfString() { return null; }\n" + |
| "\n" + |
| " static class Bar implements AutoCloseable {\n" + |
| " @Override\n" + |
| " public void close() { }\n" + |
| " }\n" + |
| "}\n" + |
| "\n" |
| }, |
| typeVerifier); |
| Assert.assertEquals(7, typeVerifier.localsChecked); |
| } |
| public void test0018_primitive_variable_types() throws Exception { |
| InferredTypeVerifier typeVerifier = new InferredTypeVerifier(); |
| this.runConformTest( |
| new String[] { |
| "Y.java", |
| "class Y {\n" + |
| " boolean[] booleanArray = { true };\n" + |
| " byte[] byteArray = { 1 };\n" + |
| " char[] charArray = { 'c' };\n" + |
| " short[] shortArray = { 42 };\n" + |
| " int[] intArray = { 42 };\n" + |
| " long[] longArray = { 42L };\n" + |
| " float[] floatArray = { 0.1f };\n" + |
| " double[] doubleArray = { 0.2d };\n" + |
| "\n" + |
| " void testBuiltins() {\n" + |
| " var z_boolean = false;\n" + |
| " var b_byte = (byte)0xff;\n" + |
| " var c_char = 'c';\n" + |
| " var s_short = (short)42;\n" + |
| " var i_int = 42;\n" + |
| " var l_long = 42L;\n" + |
| " var f_float = 0.25f;\n" + |
| " var d_double = 0.35d;\n" + |
| " }\n" + |
| "\n" + |
| " void testBuiltinsForEach() {\n" + |
| " for (var z_boolean : booleanArray) { System.out.print(\".\"); }\n" + |
| " for (var b_byte : byteArray) { System.out.print(\".\"); }\n" + |
| " for (var c_char : charArray) { System.out.print(\".\"); }\n" + |
| " for (var s_short : shortArray) { System.out.print(\".\"); }\n" + |
| " for (var i_int : intArray) { System.out.print(\".\"); }\n" + |
| " for (var l_long : longArray) { System.out.print(\".\"); }\n" + |
| " for (var f_float : floatArray) { System.out.print(\".\"); }\n" + |
| " for (var d_double : doubleArray) { System.out.print(\".\"); }\n" + |
| " }\n" + |
| " void testBuiltinsArray() {\n" + |
| " var z_booleanARRAY = booleanArray;\n" + |
| " var b_byteARRAY = byteArray;\n" + |
| " var c_charARRAY = charArray;\n" + |
| " var s_shortARRAY = shortArray;\n" + |
| " var i_intARRAY = intArray;\n" + |
| " var l_longARRAY = longArray;\n" + |
| " var f_floatARRAY = floatArray;\n" + |
| " var d_doubleARRAY = doubleArray;\n" + |
| " }\n" + |
| "\n" + |
| "}\n" |
| }, |
| typeVerifier); |
| Assert.assertEquals(24, typeVerifier.localsChecked); |
| } |
| public void test0018_project_variable_types() throws Exception { |
| InferredTypeVerifier typeVerifier = new InferredTypeVerifier(); |
| this.runConformTest( |
| new String[] { |
| "Z.java", |
| "import java.util.Collection;\n" + |
| "import java.util.List;\n" + |
| "import java.io.Serializable;\n" + |
| "\n" + |
| "class Z {\n" + |
| "\n" + |
| " void testExtends() {\n" + |
| " var l1_CollectionOfExtString = extendsString();\n" + |
| " for (var l2_CollectionOfExtString = extendsString() ; ; ) { break; }\n" + |
| " for (var l3_CollectionOfExtString : extendsStringArr()) { break; }\n" + |
| " for (var l4_CollectionOfExtString : extendsCollectionIterable()) { break; }\n" + |
| " for (var l5_String : extendsString()) { break; }\n" + |
| " }\n" + |
| "\n" + |
| " void testExtendsFbound() { \n" + |
| " var l1_CollectionExt_ComparableAny = extendsTBound();\n" + |
| " for (var l2_CollectionExt_ComparableAny = extendsTBound() ; ; ) { break; }\n" + |
| " for (var l3_CollectionExt_ComparableAny : extendsTBoundArray()) { break; }\n" + |
| " for (var l3_CollectionExt_ComparableAny : extendsTBoundIter()) { break; }\n" + |
| " for (var l4_ComparableAny : extendsTBound()) { break; }\n" + |
| " }\n" + |
| "\n" + |
| " void testSuperTBound() {\n" + |
| " var s_CollectionAny = superTBound();\n" + |
| " for (var s2_CollectionAny = superTBound() ; ; ) { break; }\n" + |
| " for (var s2_CollectionAny : superTBoundArray()) { break; }\n" + |
| " for (var s2_CollectionAny : superTBoundIter()) { break; }\n" + |
| " for (var s2_Object : superTBound()) { break; }\n" + |
| " }\n" + |
| "\n" + |
| " void testCollectSuper() {\n" + |
| " var s_CollectionOfSuperString = superString();\n" + |
| " for (var s2_CollectionOfSuperString = superString() ; ; ) { break; }\n" + |
| " for (var s2_CollectionOfSuperString : superStringArray()) { break; }\n" + |
| " for (var s2_CollectionOfSuperString : superCollectionIterable()) { break; }\n" + |
| " for (var s2_Object : superString()) { break; }\n" + |
| " }\n" + |
| "\n" + |
| " void testUnbound() {\n" + |
| " var s_CollectionAny = unboundedString();\n" + |
| " for (var s2_CollectionAny = unboundedString() ; ; ) { break; }\n" + |
| " for (var s2_CollectionAny : unboundedStringArray()) { break; }\n" + |
| " for (var s2_CollectionAny : unboundedCollectionIterable()) { break; }\n" + |
| " for (var s2_Object : unboundedString()) { break; }\n" + |
| " }\n" + |
| "\n" + |
| " void testTypeOfAnAnonymousClass() {\n" + |
| " var o_AnonymousObjectSubclass = new Object() { };\n" + |
| " for (var s2_AnonymousObjectSubclass = new Object() { } ; ; ) { break; }\n" + |
| " for (var s2_AnonymousObjectSubclass : arrayOf(new Object() { })) { break; }\n" + |
| " for (var s2_AnonymousObjectSubclass : listOf(new Object() { })) { break; }\n" + |
| " }\n" + |
| "\n" + |
| " void testTypeOfAnAnonymousInterface() {\n" + |
| " var r_AnonymousRunnableSubclass = new Runnable() { public void run() { } };\n" + |
| " for (var s2_AnonymousRunnableSubclass = new Runnable() { public void run() { } } ; ; ) { break; }\n" + |
| " for (var s2_AnonymousRunnableSubclass : arrayOf(new Runnable() { public void run() { } })) { break; }\n" + |
| " for (var s2_AnonymousRunnableSubclass : listOf(new Runnable() { public void run() { } })) { break; }\n" + |
| " }\n" + |
| "\n" + |
| " void testTypeOfIntersectionType() {\n" + |
| " var c_IntLongFloat = choose(1, 1L);\n" + |
| " for (var s2_IntLongFloat = choose(1, 1L) ; ;) { break; }\n" + |
| " for (var s2_IntLongFloat : arrayOf(choose(1, 1L))) { break; }\n" + |
| " for (var s2_IntLongFloat : listOf(choose(1, 1L))) { break; }\n" + |
| " }\n" + |
| "\n" + |
| " public void testProjections() {\n" + |
| " var inter_ListTestAndSerializable = getIntersections();\n" + |
| " var r_TestAndSerializable = inter_ListTestAndSerializable.get(0);\n" + |
| " }\n" + |
| "\n" + |
| " Collection<? extends String> extendsString() { return null; }\n" + |
| " Collection<? super String> superString() { return null; }\n" + |
| " Collection<?> unboundedString() { return null; }\n" + |
| "\n" + |
| " Collection<? extends String>[] extendsStringArr() { return null; }\n" + |
| " Collection<? super String>[] superStringArray() { return null; }\n" + |
| " Collection<?>[] unboundedStringArray() { return null; }\n" + |
| "\n" + |
| " Iterable<? extends Collection<? extends String>> extendsCollectionIterable() { return null; }\n" + |
| " Iterable<? extends Collection<? super String>> superCollectionIterable() { return null; }\n" + |
| " Iterable<? extends Collection<?>> unboundedCollectionIterable() { return null; }\n" + |
| "\n" + |
| " <TBound extends Comparable<TBound>> Collection<? extends TBound> extendsTBound() { return null; }\n" + |
| " <TBound extends Comparable<TBound>> Collection<? super TBound> superTBound() { return null; }\n" + |
| "\n" + |
| " <TBound extends Comparable<TBound>> Collection<? extends TBound>[] extendsTBoundArray() { return null; }\n" + |
| " <TBound extends Comparable<TBound>> Collection<? super TBound>[] superTBoundArray() { return null; }\n" + |
| "\n" + |
| " <TBound extends Comparable<TBound>> Iterable<? extends Collection<? extends TBound>> extendsTBoundIter() { return null; }\n" + |
| " <TBound extends Comparable<TBound>> Iterable<? extends Collection<? super TBound>> superTBoundIter() { return null; }\n" + |
| "\n" + |
| " <TBound> Collection<TBound> listOf(TBound b) { return null; }\n" + |
| " <TBound> TBound[] arrayOf(TBound b) { return null; }\n" + |
| "\n" + |
| " <TBound> TBound choose(TBound b1, TBound b2) { return b1; }\n" + |
| " <T extends Z & Serializable> List<? extends T> getIntersections() {\n" + |
| " return null;\n" + |
| " }\n" + |
| "}" |
| }, |
| typeVerifier); |
| Assert.assertEquals(39, typeVerifier.localsChecked); |
| } |
| public void testBug531832() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public static void main(String [] args) {\n" + |
| " for (var[] v : args) { }\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 3)\n" + |
| " for (var[] v : args) { }\n" + |
| " ^\n" + |
| "'var' is not allowed as an element type of an array\n" + |
| "----------\n"); |
| } |
| public void testBug530879() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public static void foo() { }\n" + |
| " public static void main(String [] args) {\n" + |
| " for (var v : foo()) { }\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 4)\n" + |
| " for (var v : foo()) { }\n" + |
| " ^\n" + |
| "Variable initializer is 'void' -- cannot infer variable type\n" + |
| "----------\n" + |
| "2. ERROR in X.java (at line 4)\n" + |
| " for (var v : foo()) { }\n" + |
| " ^^^^^\n" + |
| "Can only iterate over an array or an instance of java.lang.Iterable\n" + |
| "----------\n"); |
| } |
| public void testBug530879a() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public static void main(String [] args) {\n" + |
| " for (var v : null) { }\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 3)\n" + |
| " for (var v : null) { }\n" + |
| " ^\n" + |
| "Cannot infer type for local variable initialized to 'null'\n" + |
| "----------\n" + |
| "2. ERROR in X.java (at line 3)\n" + |
| " for (var v : null) { }\n" + |
| " ^^^^\n" + |
| "Can only iterate over an array or an instance of java.lang.Iterable\n" + |
| "----------\n"); |
| } |
| public void testBug532349() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public static void foo(Boolean p) {\n" + |
| " Y<? super Boolean> y = new Y<>();\n" + |
| " var v = y;\n" + |
| " Y<? super Boolean> tmp = v;\n" + |
| " }\n" + |
| "}\n" + |
| "class Y<T extends Boolean> {\n" + |
| "}" |
| }); |
| } |
| public void testBug532349a() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "import java.util.List;\n" + |
| "import java.util.ArrayList;\n" + |
| "public class X {\n" + |
| " public static void foo(Boolean p) {\n" + |
| " List<Y<? super Boolean>> l = new ArrayList<>();\n" + |
| " var dlv = l;\n" + |
| " for (var iv : dlv) {\n" + |
| " Y<? super Boolean> id = iv;\n" + |
| " }" + |
| " }\n" + |
| "}\n" + |
| "class Y<T extends Boolean> {}" |
| }); |
| } |
| public void testBug532349b() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public static void foo(Boolean p) {\n" + |
| " Y<? super Boolean> y = new Y<>();\n" + |
| " try (var v = y) {\n" + |
| " Y<? super Boolean> tmp = v;\n" + |
| " } catch (Exception e) { }\n" + |
| " }\n" + |
| "}\n" + |
| "class Y<T extends Boolean> implements AutoCloseable {\n" + |
| " @Override\n" + |
| " public void close() throws Exception {}\n" + |
| "}" |
| }); |
| } |
| public void testBug532351() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public static void foo(Boolean p) {\n" + |
| " Y<? super Number> y = new Y<Number>(); // Javac reports, ECJ accepts\n" + |
| " var v = y;\n" + |
| " Y<? super Number> tmp = v;\n" + |
| " }\n" + |
| " class Y<T extends Number> {\n" + |
| " }\n" + |
| "}" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 3)\n" + |
| " Y<? super Number> y = new Y<Number>(); // Javac reports, ECJ accepts\n" + |
| " ^^^^^^^^^^^^^^^\n" + |
| "No enclosing instance of type X is accessible. Must qualify the allocation with an enclosing instance of type X (e.g. x.new A() where x is an instance of X).\n" + |
| "----------\n"); |
| } |
| public void testBug531025() { |
| runNegativeTest( |
| new String[] { |
| "a/Ann.java", |
| "package a;\n" + |
| "public @interface Ann {}\n", |
| "a/AnnM.java", |
| "package a;\n" + |
| "import java.lang.annotation.*;\n" + |
| "@Target(ElementType.METHOD)\n" + |
| "public @interface AnnM {}\n", |
| "a/AnnD.java", |
| "package a;\n" + |
| "import java.lang.annotation.*;\n" + |
| "@Target(ElementType.LOCAL_VARIABLE)\n" + |
| "public @interface AnnD {}\n", |
| "a/AnnT.java", |
| "package a;\n" + |
| "import java.lang.annotation.*;\n" + |
| "@Target(ElementType.TYPE_USE)\n" + |
| "public @interface AnnT {}\n", |
| "a/AnnDT.java", |
| "package a;\n" + |
| "import java.lang.annotation.*;\n" + |
| "@Target({ElementType.LOCAL_VARIABLE, ElementType.TYPE_USE})\n" + |
| "public @interface AnnDT {}\n", |
| "X.java", |
| "import a.*;\n" + |
| "import java.util.*;\n" + |
| "public class X {\n" + |
| " void test(List<String> strings) {\n" + |
| " @Ann var v = strings;\n" + |
| " @AnnM var vm = strings;\n" + |
| " @AnnD var vd = strings;\n" + |
| " @AnnT var vt = \"\";\n" + |
| " @AnnDT var vdt = this;\n" + |
| " for (@AnnD var fvd : strings) {}\n" + |
| " for (@AnnT var fvt : strings) {}\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 6)\n" + |
| " @AnnM var vm = strings;\n" + |
| " ^^^^^\n" + |
| "The annotation @AnnM is disallowed for this location\n" + |
| "----------\n" + |
| "2. ERROR in X.java (at line 8)\n" + |
| " @AnnT var vt = \"\";\n" + |
| " ^^^^^\n" + |
| "The annotation @AnnT is disallowed for this location\n" + |
| "----------\n" + |
| "3. ERROR in X.java (at line 11)\n" + |
| " for (@AnnT var fvt : strings) {}\n" + |
| " ^^^^^\n" + |
| "The annotation @AnnT is disallowed for this location\n" + |
| "----------\n"); |
| } |
| public void testBug532349_001() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "class X {\n" + |
| " public static void foo() {\n" + |
| " Y<? extends Number> y = new Y<>();\n" + |
| " var v = y.t;\n" + |
| " Integer dsbType0 = v;\n" + |
| " }\n" + |
| "}\n" + |
| "class Y<T extends Integer> {\n" + |
| " public T t;\n" + |
| "}" |
| }); |
| } |
| public void testBug532349_002() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "class X {\n" + |
| " public static void foo() {\n" + |
| " Y<? extends I> y = new Y<>();\n" + |
| " var v = y.t;\n" + |
| " Integer dsbType0 = v;\n" + |
| " }\n" + |
| "}\n" + |
| "interface I { }\n" + |
| "class Y<T extends Integer> {\n" + |
| " public T t;\n" + |
| "}" |
| }); |
| } |
| public void testBug532349_003() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "class X {\n" + |
| " public static void foo(Y<? extends I> y) {\n" + |
| " var v = y.t;\n" + |
| " Integer dsbType0 = v;\n" + |
| " I i = v;\n" + |
| " }\n" + |
| "}\n" + |
| "interface I { }\n" + |
| "class Y<T extends Integer> {\n" + |
| " public T t;\n" + |
| "}" |
| }); |
| } |
| public void testBug532349_004() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "import java.io.Serializable;\n" + |
| "class X {\n" + |
| " public static void foo() {\n" + |
| " Y<? extends Integer> y = new Y<>();\n" + |
| " var v = y.t;\n" + |
| " Integer dsbType0 = v;\n" + |
| " Serializable s = v;\n" + |
| " }\n" + |
| "}\n" + |
| "class Y<T extends Number&Serializable> {\n" + |
| " public T t;\n" + |
| "}" |
| }); |
| } |
| public void testBug532349_005() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "import java.io.Serializable;\n" + |
| "class X {\n" + |
| " public static void foo() {\n" + |
| " Y<?> y = new Y<>();\n" + |
| " var v = y.t;\n" + |
| " I i = v;\n" + |
| " Serializable s = v;\n" + |
| " }\n" + |
| "}\n" + |
| "interface I { }\n" + |
| "class Y<T extends I&Serializable> {\n" + |
| " public T t;\n" + |
| "}" |
| }); |
| } |
| public void testBug532349_006() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "import java.io.Serializable;\n" + |
| "class X {\n" + |
| " public static void foo() {\n" + |
| " Y<? extends I> y = new Y<>();\n" + |
| " var v = y.t;\n" + |
| " I i = v;\n" + |
| " Serializable s = v;\n" + |
| " }\n" + |
| "}\n" + |
| "interface I { }\n" + |
| "class Y<T extends Serializable> {\n" + |
| " public T t;\n" + |
| "}", |
| }); |
| } |
| public void testBug532349_007() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "class X {\n" + |
| " public static void foo() {\n" + |
| " Z<? extends I> z = new Z<>();\n" + |
| " var v = z.t;\n" + |
| " X x = v.t;\n" + |
| " v.doSomething();\n" + |
| " }\n" + |
| "}\n" + |
| "interface I { void doSomething();}\n" + |
| "class Z<T extends Y<?>> {\n" + |
| " public T t;\n" + |
| "}\n" + |
| "class Y<T extends X> {\n" + |
| " public T t;\n" + |
| "}", |
| }); |
| } |
| public void testBug532349_008() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "class X {\n" + |
| " public static void foo() {\n" + |
| " Z<? extends Y<? extends C>> z = new Z<>();\n" + |
| " var v = z.t;\n" + |
| " C c = v.t;\n" + |
| " v.doSomething();\n" + |
| " }\n" + |
| "}\n" + |
| "interface I { void doSomething();}\n" + |
| "class C extends X{ }\n" + |
| "class Z<T extends I> {\n" + |
| " public T t;\n" + |
| "}\n" + |
| "class Y<T extends X> {\n" + |
| " public T t;\n" + |
| "}", |
| }); |
| } |
| public void testBug532349_009() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "import java.io.Serializable;\n" + |
| "class X {\n" + |
| " public static void foo() {\n" + |
| " Y<? super J> y = new Y<>();\n" + |
| " var v = y.t;\n" + |
| " I i = v;\n" + |
| " Serializable s = v;\n" + |
| " }\n" + |
| "}\n" + |
| "interface I { }\n" + |
| "interface J extends I{}" + |
| "class Y<T extends I> {\n" + |
| " public T t;\n" + |
| "}", |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 7)\n" + |
| " Serializable s = v;\n" + |
| " ^\n" + |
| "Type mismatch: cannot convert from I to Serializable\n" + |
| "----------\n"); |
| } |
| public void testBug532349_010() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "import java.io.Serializable;\n" + |
| "class X {\n" + |
| " public static void foo(C<?> c) {\n" + |
| " var v = c.t;\n" + |
| " v = (I&Serializable) new D();\n" + |
| " v.doSomething();\n" + |
| " }\n" + |
| "}\n" + |
| "interface I { void doSomething();}\n" + |
| "class C<T extends I&Serializable>{ T t;}\n" + |
| "class D implements I, Serializable { public void doSomething() {} }\n" |
| }); |
| } |
| public void testBug532349_11() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "class X {\n" + |
| " static <R extends D<? extends Y>> W<? extends R> boo() {\n" + |
| " return null;\n" + |
| " }\n" + |
| " public static void foo() {\n" + |
| " var v = boo();\n" + |
| " var var = v.t;\n" + |
| " Y y = var.r;\n" + |
| " }\n" + |
| "}\n" + |
| "class Y extends X { }\n" + |
| "class D<R extends X>{ R r;}\n" + |
| "class W<T extends D<?>> { T t; }\n" |
| }); |
| } |
| public void testBug532349_12() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "class X {\n" + |
| " public static void foo(D<?> d) {\n" + |
| " var v = d;\n" + |
| " D<? extends Y> dy = v;\n" + |
| " D<? extends X> dx = v;\n" + |
| " }\n" + |
| "}\n" + |
| "class Y extends X{ }\n" + |
| "class D<R extends Y>{ R r;}\n" |
| }); |
| } |
| public void testBug532349_13() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "class X {\n" + |
| " public static void foo(D<Y<? extends Integer>> d) {\n" + |
| " var v = d.r;\n" + |
| " Y<? extends Number> yn = v;\n" + |
| " Y<? extends Integer> yi = v;\n" + |
| " }\n" + |
| "}\n" + |
| "class Y<T extends Integer>{ }\n" + |
| "class D<R extends Y<? extends Number>>{ R r;}\n" |
| }); |
| } |
| public void testBug532349_14() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "class X {\n" + |
| " public static void foo(A<? super C> ac) {\n" + |
| " C c = new C(100);\n" + |
| " var c1 = ac;\n" + |
| " A<? super C> a1 = c1;\n" + |
| " A<? super C> a2 = new A<B>(new B());\n" + |
| " a2 = c1;\n" + |
| " }\n" + |
| "}\n" + |
| "class C<T> extends B{\n" + |
| " T t;\n" + |
| " C(T t) {\n" + |
| " this.t = t;\n" + |
| " }\n" + |
| "}\n" + |
| "class B { }\n" + |
| "class A<Q> {\n" + |
| " A(Q e) {}\n" + |
| "}" |
| }); |
| } |
| public void testBug532349_15() throws IOException { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public static <T> A<T> m(T t) {\n" + |
| " return new A(t);\n" + |
| " }\n" + |
| " public static <U extends I1<?>> A<? extends U> m2(A<? super U> u) {\n" + |
| " return new A(u);\n" + |
| " }\n" + |
| " public static void main(String argv[]) {\n" + |
| " A<?> checkValue1 = new C(10);\n" + |
| " var varValue = m2(m(checkValue1));\n" + |
| " if(!varValue.t.t.equals(10)) {\n" + |
| " System.out.println(\"Error:\");\n" + |
| " }\n" + |
| " if(varValue.t.methodOnI1() != true) {\n" + |
| " System.out.println(\"Error:\");\n" + |
| " }\n" + |
| " }" + |
| "}\n" + |
| "class A<E> {\n" + |
| " E t;\n" + |
| " A(E t) {\n" + |
| " this.t = t;\n" + |
| " }\n" + |
| " A<E> u;\n" + |
| " A (A<E> u) {\n" + |
| " this(u.t);\n" + |
| " this.u = u;\n" + |
| " }\n" + |
| "}\n" + |
| "interface I1<E> {\n" + |
| " default boolean methodOnI1() {\n" + |
| " return true;\n" + |
| " }\n" + |
| "}\n" + |
| "class C<T> extends A implements I1 {\n" + |
| " C(T t) {\n" + |
| " super(t);\n" + |
| " }\n" + |
| "}" |
| }, ""); |
| } |
| public void testBug532349_0016() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "class X {\n" + |
| " public static void foo() {\n" + |
| " Y<? extends I> yi = new Y<>();\n" + |
| " var vi = yi.t;\n" + |
| " Y<Integer> yj = new Y<>();\n" + |
| " vi = yj.t;\n" + |
| " }\n" + |
| "}\n" + |
| "interface I { }\n" + |
| "class Y<T extends Number> {\n" + |
| " public T t;\n" + |
| "}" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 6)\n" + |
| " vi = yj.t;\n" + |
| " ^^^^\n" + |
| "Type mismatch: cannot convert from Integer to Number & I\n" + |
| "----------\n"); |
| } |
| public void testBug532349_0017() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "class X {\n" + |
| " public static <Q extends Number & I> void foo(Y<? super Q> y) {\n" + |
| " var vy = y;\n" + |
| " Y<Integer> yi = new Y<>();\n" + |
| " vy = yi;\n" + |
| " }\n" + |
| "}\n" + |
| "interface I { }\n" + |
| "class Y<T extends Number> {\n" + |
| " public T t;\n" + |
| "}" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 5)\n" + |
| " vy = yi;\n" + |
| " ^^\n" + |
| "Type mismatch: cannot convert from Y<Integer> to Y<? super Q>\n" + |
| "----------\n"); |
| } |
| public void testBug532920() throws IOException { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "import java.util.Iterator;\n" + |
| "public class X {\n" + |
| " static void foo(Z<?> ef) { \n" + |
| " for (var l : ef.t) {\n" + |
| " l = new Object();\n" + |
| " }\n" + |
| " }\n" + |
| "}\n" + |
| "class I<T> {// implements Iterable<T> {\n" + |
| " T t;\n" + |
| "}\n" + |
| "class Q {}\n" + |
| "class Y extends Q{ }\n" + |
| "class Z<T extends Iterable<? super Y>> {\n" + |
| " I<T> t;\n" + |
| "}" |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 4)\n" + |
| " for (var l : ef.t) {\n" + |
| " ^^^^\n" + |
| "Can only iterate over an array or an instance of java.lang.Iterable\n" + |
| "----------\n"); |
| } |
| } |