/*******************************************************************************
 * Copyright (c) 2018, 2020 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.AbstractCompilerTest;
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;
}
@Override
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" };
}
@Override
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 {
	// Below call forces the init when the test is run independently.
	AbstractCompilerTest.getPossibleComplianceLevels();
	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");
}
public void testBug567183_1() {
	this.runNegativeTest(
			new String[] {
				"p/Item.java",
				"package p;\n"
				+ "class Item {\n"
				+ "}",
				"p/Container.java",
				"package p;\n"
				+ "import java.util.List;\n"
				+ "\n"
				+ "public class Container {\n"
				+ "  public final List<Item> items = null;\n"
				+ "}",
				"p/PublicItem.java",
				"package p;\n"
				+ "public class PublicItem extends Item {\n"
				+ "}",
				"p1/X.java",
				"package p1;\n"
				+ "import p.Container;\n"
				+ "import p.PublicItem;\n"
				+ "public class X {\n"
				+ "	public static void main(String[] args) {\n"
				+ "		var container = new Container();\n"
				+ "		for (var item : container.items) {\n"
				+ "			if (item instanceof PublicItem) {\n"
				+ "				var publicItem = (PublicItem) item;\n"
				+ "				System.out.println(publicItem);\n"
				+ "			}\n"
				+ "		}\n"
				+ "	}\n"
				+ "}\n"
				+ ""
			},
			"----------\n" +
			"1. ERROR in p1\\X.java (at line 7)\n" +
			"	for (var item : container.items) {\n" +
			"	         ^^^^\n" +
			"The type Item is not visible\n" +
			"----------\n");
}
public void testBug567183_2() {
	this.runNegativeTest(
			new String[] {
				"p/Item.java",
				"package p;\n"
				+ "class Item {\n"
				+ "}",
				"p/Container.java",
				"package p;\n"
				+ "import java.util.List;\n"
				+ "\n"
				+ "public class Container {\n"
				+ "  public final List<List<Item>> items = null;\n"
				+ "}",
				"p/PublicItem.java",
				"package p;\n"
				+ "public class PublicItem extends Item {\n"
				+ "}",
				"p1/X.java",
				"package p1;\n"
				+ "import java.util.List;\n"
				+ "import p.Container;\n"
				+ "import p.PublicItem;\n"
				+ "public class X {\n"
				+ "	public static void main(String[] args) {\n"
				+ "		var container = new Container();\n"
				+ "		for (var item : container.items) {\n"
				+ "			if (item instanceof PublicItem) {\n"
				+ "				var publicItem = (PublicItem) item;\n"
				+ "				System.out.println(publicItem);\n"
				+ "			} else if (item instanceof List) {\n"
				+ "				  for (var item2 : item) {}\n"
				+ "			}\n"
				+ "		}\n"
				+ "	}\n"
				+ "}\n"
				+ ""
			},
			"----------\n" +
			"1. ERROR in p1\\X.java (at line 13)\n" +
			"	for (var item2 : item) {}\n" +
			"	         ^^^^^\n" +
			"The type Item is not visible\n" +
			"----------\n");
}
public void testBug567183_3() {
	this.runNegativeTest(
			new String[] {
				"p/Item.java",
				"package p;\n"
				+ "class Item {\n"
				+ "}",
				"p/Container.java",
				"package p;\n"
				+ "import java.util.List;\n"
				+ "\n"
				+ "public class Container {\n"
				+ "  public final List<List<Item>> items = null;\n"
				+ "}",
				"p/PublicItem.java",
				"package p;\n"
				+ "public class PublicItem extends Item {\n"
				+ "}",
				"p1/X.java",
				"package p1;\n"
				+ "import p.Container;\n"
				+ "public class X {\n"
				+ "	public static void main(String[] args) {\n"
				+ "		var container = new Container();\n"
				+ "		for (var item : container.items) { // Javac over-eagerly reports this\n"
				+ "		}\n"
				+ "	}\n"
				+ "}\n"
				+ ""
			},
			"");
}
public void testBug567183_4() {
	this.runNegativeTest(
			new String[] {
				"p/Item.java",
				"package p;\n"
				+ "class Item {\n"
				+ "}",
				"p/Container.java",
				"package p;\n"
				+ "import java.util.List;\n"
				+ "\n"
				+ "public class Container {\n"
				+ "  public final List<List<Item>> items = null;\n"
				+ "}",
				"p/PublicItem.java",
				"package p;\n"
				+ "public class PublicItem extends Item {\n"
				+ "}",
				"p1/X.java",
				"package p1;\n"
				+ "import p.Container;\n"
				+ "public class X {\n"
				+ "	public static void main(String[] args) {\n"
				+ "		var container = new Container();\n"
				+ "		var item1 = container.items.get(0).get(0);\n"
				+ "	}\n"
				+ "}\n"
				+ ""
			},
			"----------\n" +
			"1. ERROR in p1\\X.java (at line 6)\n" +
			"	var item1 = container.items.get(0).get(0);\n" +
			"	            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
			"The type Item is not visible\n" +
			"----------\n");
}
}
