95638
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
index 4939176..1e5bcfe 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
@@ -19670,19 +19670,20 @@
 			"class Store<F extends Key<F>> {}\n" + 
 			"\n" + 
 			"public class X<T> {\n" + 
-			"	Store<? extends Key<T>> store;\n" + 
+			"	Store<? extends Key<T>> store1;\n" + 
+			"	Store<? extends Key<? extends T>> store2;\n" + 
 			"}\n",
 		},
 		"----------\n" + 
-		"1. ERROR in X.java (at line 5)\n" + 
-		"	Store<? extends Key<T>> store;\n" + 
-		"	      ^^^^^^^^^^^^^\n" + 
-		"Bound mismatch: The type ? extends Key<T> is not a valid substitute for the bounded parameter <F extends Key<F>> of the type Store<F>\n" + 
-		"----------\n" + 
-		"2. ERROR in X.java (at line 5)\n" + 
-		"	Store<? extends Key<T>> store;\n" + 
+		"1. ERROR in X.java (at line 5)\r\n" + 
+		"	Store<? extends Key<T>> store1;\r\n" + 
 		"	                    ^\n" + 
 		"Bound mismatch: The type T is not a valid substitute for the bounded parameter <E extends Key<E>> of the type Key<E>\n" + 
+		"----------\n" + 
+		"2. ERROR in X.java (at line 6)\r\n" + 
+		"	Store<? extends Key<? extends T>> store2;\r\n" + 
+		"	                    ^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? extends T is not a valid substitute for the bounded parameter <E extends Key<E>> of the type Key<E>\n" + 
 		"----------\n");
 }	
 //check fault tolerance, in spite of bound mismatch, still pass param type for further resolving message send
@@ -19769,7 +19770,7 @@
 }	
 //https://bugs.eclipse.org/bugs/show_bug.cgi?id=95638 - variation
 public void test679() {
-	this.runNegativeTest(
+	this.runConformTest(
 		new String[] {
 			"X.java",
 			"class Key<E, F extends Key<E, F>> {}\n" + 
@@ -19779,16 +19780,11 @@
 			"	Store<K, ? extends Key<K, ?>> store;\n" + 
 			"}\n",
 		},
-		"----------\n" + 
-		"1. ERROR in X.java (at line 5)\n" + 
-		"	Store<K, ? extends Key<K, ?>> store;\n" + 
-		"	         ^^^^^^^^^^^^^\n" + 
-		"Bound mismatch: The type ? extends Key<K,?> is not a valid substitute for the bounded parameter <B extends Key<A,B>> of the type Store<A,B>\n" + 
-		"----------\n");
+		"");
 }	
 //https://bugs.eclipse.org/bugs/show_bug.cgi?id=95638 - variation
 public void test680() {
-	this.runNegativeTest(
+	this.runConformTest(
 		new String[] {
 			"X.java",
 			"import java.util.List;\n" + 
@@ -19802,16 +19798,11 @@
 			"	List<Store<K, ?, ? extends Key<K, ?, ?, ?>, ? extends State<?>>> stores;\n" + 
 			"}\n",
 		},
-		"----------\n" + 
-		"1. ERROR in X.java (at line 9)\n" + 
-		"	List<Store<K, ?, ? extends Key<K, ?, ?, ?>, ? extends State<?>>> stores;\n" + 
-		"	                 ^^^^^^^^^^^^^\n" + 
-		"Bound mismatch: The type ? extends Key<K,?,?,?> is not a valid substitute for the bounded parameter <C extends Key<A,B,C,D>> of the type Store<A,B,C,D>\n" + 
-		"----------\n");
-}
+		"");
+}	
 //https://bugs.eclipse.org/bugs/show_bug.cgi?id=95638 - variation
 public void test681() {
-	this.runNegativeTest(
+	this.runConformTest(
 		new String[] {
 			"X.java",
 			"class Key<E, K extends Key<E, K>> {\n" + 
@@ -19830,14 +19821,9 @@
 			"	Y<?, ?> y;\n" + 
 			"}\n",
 		},
-		"----------\n" + 
-		"1. ERROR in X.java (at line 7)\n" + 
-		"	Store<E, ? extends Key<E, ?>> store2;\n" + 
-		"	         ^^^^^^^^^^^^^\n" + 
-		"Bound mismatch: The type ? extends Key<E,?> is not a valid substitute for the bounded parameter <K extends Key<E,K>> of the type Store<E,K>\n" + 
-		"----------\n");
-}
-//https://bugs.eclipse.org/bugs/show_bug.cgi?id=96134
+		"");
+}	
+//https://bugs.eclipse.org/bugs/show_bug.cgi?id=95963
 public void test682() {
 	this.runNegativeTest(
 		new String[] {
@@ -19853,4 +19839,440 @@
 		"----------\n"
 	);
 }
+//https://bugs.eclipse.org/bugs/show_bug.cgi?id=96085
+public void test683() {
+	this.runConformTest(
+		new String[] {
+			"P.java",
+			"interface P<V> {\n" + 
+			"    interface A {}\n" + 
+			"}\n",
+			"P2.java",
+			"class P2 implements P.A {\n" + 
+			"    P2(P.A problem) {}\n" + 
+			"}\n",
+			"P3.java",
+			"class P3 {\n" + 
+			"    void test() {P.A o = new P2((P.A) null);}\n" + 
+			"}\n",
+		},
+		"");
+}
+public void test684() {
+	this.runNegativeTest(
+		new String[] {
+			"X.java",
+			"public class X<T> {\n" + 
+			"	<U> U foo(U u1, U u2) {\n" + 
+			"		return u1;\n" + 
+			"	}\n" + 
+			"	void bar(X<? extends Throwable> x1, X<? extends Runnable> x2) {\n" + 
+			"		X<String> x = foo(x1, x2);\n" + 
+			"	}\n" + 
+			"}\n",
+		},
+		"----------\n" + 
+		"1. ERROR in X.java (at line 6)\n" + 
+		"	X<String> x = foo(x1, x2);\n" + 
+		"	          ^\n" + 
+		"Type mismatch: cannot convert from X<capture-of ? extends Object> to X<String>\n" + 
+		"----------\n");
+}	
+public void test685() {
+	this.runNegativeTest(
+		new String[] {
+			"X.java",
+			"public class X<T> {\n" + 
+			"	<U> U foo(U u1, U u2) {\n" + 
+			"		return u1;\n" + 
+			"	}\n" + 
+			"	void bar(X<? extends Throwable> x1, X<? extends Runnable> x2) {\n" + 
+			"		X<String> x = foo(x1, x2);\n" + 
+			"	}\n" + 
+			"}\n",
+		},
+		"----------\n" + 
+		"1. ERROR in X.java (at line 6)\n" + 
+		"	X<String> x = foo(x1, x2);\n" + 
+		"	          ^\n" + 
+		"Type mismatch: cannot convert from X<capture-of ? extends Object> to X<String>\n" + 
+		"----------\n");
+}	
+// check wildcard bounds wrt variable boundCheck
+public void test686() {
+	this.runNegativeTest(
+		new String[] {
+			"X.java",
+			"import java.util.List;\n" + 
+			"class Other<T extends List<? extends Runnable>> {\n" + 
+			"}\n" + 
+			"\n" + 
+			"public class X {\n" + 
+			"	Other<? extends List<? extends Throwable>> other1;\n" + 
+			"	Other<? extends List<? super String>> other2;	\n" + 
+			"	Other<? extends List<? extends String>> other3;		\n" + 
+			"	Other<? extends List<? extends Runnable>> other7 = other1;\n" + 
+			"}\n",
+		},
+		"----------\n" + 
+		"1. ERROR in X.java (at line 7)\n" + 
+		"	Other<? extends List<? super String>> other2;	\n" + 
+		"	      ^^^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? extends List<? super String> is not a valid substitute for the bounded parameter <T extends List<? extends Runnable>> of the type Other<T>\n" + 
+		"----------\n" + 
+		"2. ERROR in X.java (at line 8)\n" + 
+		"	Other<? extends List<? extends String>> other3;		\n" + 
+		"	      ^^^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? extends List<? extends String> is not a valid substitute for the bounded parameter <T extends List<? extends Runnable>> of the type Other<T>\n" + 
+		"----------\n");
+}
+// check wildcard bounds wrt variable boundCheck
+public void test687() {
+	this.runNegativeTest(
+		new String[] {
+			"X.java",
+			"import java.util.List;\n" + 
+			"class Other<T extends List<? extends Runnable>> {\n" + 
+			"}\n" + 
+			"\n" + 
+			"public class X {\n" + 
+			"	Other<? extends List<?>> other2;\n" + 
+			"	Other<? extends List<? super Throwable>> other3;\n" + 
+			"	Other<? super List<? extends Throwable>> other4;\n" + 
+			"	Other<? super List<?>> other5;\n" + 
+			"	Other<? super List<? super Throwable>> other6;\n" + 
+			"}\n",
+		},
+		"----------\n" + 
+		"1. ERROR in X.java (at line 7)\n" + 
+		"	Other<? extends List<? super Throwable>> other3;\n" + 
+		"	      ^^^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? extends List<? super Throwable> is not a valid substitute for the bounded parameter <T extends List<? extends Runnable>> of the type Other<T>\n" + 
+		"----------\n" + 
+		"2. ERROR in X.java (at line 8)\n" + 
+		"	Other<? super List<? extends Throwable>> other4;\n" + 
+		"	      ^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? super List<? extends Throwable> is not a valid substitute for the bounded parameter <T extends List<? extends Runnable>> of the type Other<T>\n" + 
+		"----------\n" + 
+		"3. ERROR in X.java (at line 9)\n" + 
+		"	Other<? super List<?>> other5;\n" + 
+		"	      ^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? super List<?> is not a valid substitute for the bounded parameter <T extends List<? extends Runnable>> of the type Other<T>\n" + 
+		"----------\n" + 
+		"4. ERROR in X.java (at line 10)\n" + 
+		"	Other<? super List<? super Throwable>> other6;\n" + 
+		"	      ^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? super List<? super Throwable> is not a valid substitute for the bounded parameter <T extends List<? extends Runnable>> of the type Other<T>\n" + 
+		"----------\n");
+}
+// check wildcard bounds wrt variable boundCheck
+public void test688() {
+	this.runConformTest(
+		new String[] {
+			"X.java",
+			"import java.util.List;\n" + 
+			"class Other<T extends List<? extends Runnable>> {\n" + 
+			"}\n" + 
+			"\n" + 
+			"public class X {\n" + 
+			"	Other<? super List<? extends Runnable>> other5;\n" + 
+			"}\n",
+		},
+		"");
+}
+// check wildcard bounds wrt variable boundCheck
+public void test689() {
+	this.runNegativeTest(
+		new String[] {
+			"X.java",
+			"import java.util.List;\n" + 
+			"class Other<T extends List<? extends Runnable>> {\n" + 
+			"}\n" + 
+			"\n" + 
+			"public class X {\n" + 
+			"	Other<? super List<? super Runnable>> other5;\n" + 
+			"}\n",
+		},
+		"----------\n" + 
+		"1. ERROR in X.java (at line 6)\n" + 
+		"	Other<? super List<? super Runnable>> other5;\n" + 
+		"	      ^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? super List<? super Runnable> is not a valid substitute for the bounded parameter <T extends List<? extends Runnable>> of the type Other<T>\n" + 
+		"----------\n");
+}
+// check assignment rules across param types with wildcards
+public void test690() {
+	this.runNegativeTest(
+		new String[] {
+			"X.java",
+			"import java.util.List;\n" + 
+			"public class X {\n" + 
+			"	void foo(List<? extends Runnable> lr, List<?> la) {\n" + 
+			"		lr = la;\n" + 
+			"		la = lr;\n" + 
+			"	}\n" + 
+			"}         \n" + 
+			"\n",
+		},
+		"----------\n" + 
+		"1. ERROR in X.java (at line 4)\n" + 
+		"	lr = la;\n" + 
+		"	     ^^\n" + 
+		"Type mismatch: cannot convert from List<capture-of ?> to List<? extends Runnable>\n" + 
+		"----------\n");
+}
+// check that final class bound is more restrictive
+public void test691() {
+	this.runNegativeTest(
+		new String[] {
+			"XX.java",
+			"public class XX<T extends Runnable> {\n" + 
+			"	void foo(XX<?> lhs, XX<? extends String> rhs) {\n" + 
+			"		lhs = rhs;\n" + 
+			"	}\n" + 
+			"}\n",
+		},
+		"----------\n" + 
+		"1. ERROR in XX.java (at line 2)\n" + 
+		"	void foo(XX<?> lhs, XX<? extends String> rhs) {\n" + 
+		"	                       ^^^^^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? extends String is not a valid substitute for the bounded parameter <T extends Runnable> of the type XX<T>\n" + 
+		"----------\n");
+}
+// check wildcard bounds wrt variable boundCheck
+public void test692() {
+	this.runNegativeTest(
+		new String[] {
+			"X.java",
+			"import java.util.List;\n" + 
+			"\n" + 
+			"public class X<T extends List<Object>> {\n" + 
+			"	\n" + 
+			"	void foo(X<? extends List<String>> x) {\n" + 
+			"	}\n" + 
+			"}\n",
+		},
+		"----------\n" + 
+		"1. ERROR in X.java (at line 5)\n" + 
+		"	void foo(X<? extends List<String>> x) {\n" + 
+		"	           ^^^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? extends List<String> is not a valid substitute for the bounded parameter <T extends List<Object>> of the type X<T>\n" + 
+		"----------\n");
+}	
+// bound checks
+public void test693() {
+	this.runNegativeTest(
+		new String[] {
+			"X.java",
+			"public class X<T extends Runnable> {\n" + 
+			"	X<X<String>> x1;\n" + 
+			"	X<? extends String> x2;\n" + 
+			"}\n",
+		},
+		"----------\n" + 
+		"1. ERROR in X.java (at line 2)\n" + 
+		"	X<X<String>> x1;\n" + 
+		"	  ^\n" + 
+		"Bound mismatch: The type X<String> is not a valid substitute for the bounded parameter <T extends Runnable> of the type X<T>\n" + 
+		"----------\n" + 
+		"2. ERROR in X.java (at line 2)\n" + 
+		"	X<X<String>> x1;\n" + 
+		"	    ^^^^^^\n" + 
+		"Bound mismatch: The type String is not a valid substitute for the bounded parameter <T extends Runnable> of the type X<T>\n" + 
+		"----------\n" + 
+		"3. ERROR in X.java (at line 3)\n" + 
+		"	X<? extends String> x2;\n" + 
+		"	  ^^^^^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? extends String is not a valid substitute for the bounded parameter <T extends Runnable> of the type X<T>\n" + 
+		"----------\n");
+}	
+// bound checks
+public void test694() {
+	this.runNegativeTest(
+		new String[] {
+			"X.java",
+			"public class X<T extends X<T>> {\n" + 
+			"	X<X<X<String>>> x1;\n" + 
+			"	X<? extends X<? extends X<String>>> x2;\n" + 
+			"}\n",
+		},
+		"----------\n" + 
+		"1. ERROR in X.java (at line 2)\n" + 
+		"	X<X<X<String>>> x1;\n" + 
+		"	  ^\n" + 
+		"Bound mismatch: The type X<X<String>> is not a valid substitute for the bounded parameter <T extends X<T>> of the type X<T>\n" + 
+		"----------\n" + 
+		"2. ERROR in X.java (at line 2)\n" + 
+		"	X<X<X<String>>> x1;\n" + 
+		"	    ^\n" + 
+		"Bound mismatch: The type X<String> is not a valid substitute for the bounded parameter <T extends X<T>> of the type X<T>\n" + 
+		"----------\n" + 
+		"3. ERROR in X.java (at line 2)\n" + 
+		"	X<X<X<String>>> x1;\n" + 
+		"	      ^^^^^^\n" + 
+		"Bound mismatch: The type String is not a valid substitute for the bounded parameter <T extends X<T>> of the type X<T>\n" + 
+		"----------\n" + 
+		"4. ERROR in X.java (at line 3)\n" + 
+		"	X<? extends X<? extends X<String>>> x2;\n" + 
+		"	              ^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? extends X<String> is not a valid substitute for the bounded parameter <T extends X<T>> of the type X<T>\n" + 
+		"----------\n" + 
+		"5. ERROR in X.java (at line 3)\n" + 
+		"	X<? extends X<? extends X<String>>> x2;\n" + 
+		"	                          ^^^^^^\n" + 
+		"Bound mismatch: The type String is not a valid substitute for the bounded parameter <T extends X<T>> of the type X<T>\n" + 
+		"----------\n");
+}	
+// bound checks
+public void test695() {
+	this.runConformTest(
+		new String[] {
+			"I.java",
+			"interface I<T extends I<? extends T>> {\n" + 
+			"}\n",
+		},
+		"");
+}
+public void test696() {
+	this.runNegativeTest(
+		new String[] {
+			"X.java",
+			"class Key<E extends Key<E>> {}\n" + 
+			"class Store<F extends Key<F>> {}\n" + 
+			"\n" + 
+			"public class X<T> {\n" + 
+			"	Store<? extends Key<T>> store = new Store<Key<T>>();\n" + 
+			"}\n",
+		},
+		"----------\n" + 
+		"1. ERROR in X.java (at line 5)\n" + 
+		"	Store<? extends Key<T>> store = new Store<Key<T>>();\n" + 
+		"	                    ^\n" + 
+		"Bound mismatch: The type T is not a valid substitute for the bounded parameter <E extends Key<E>> of the type Key<E>\n" + 
+		"----------\n" + 
+		"2. ERROR in X.java (at line 5)\n" + 
+		"	Store<? extends Key<T>> store = new Store<Key<T>>();\n" + 
+		"	                                          ^^^\n" + 
+		"Bound mismatch: The type Key<T> is not a valid substitute for the bounded parameter <F extends Key<F>> of the type Store<F>\n" + 
+		"----------\n" + 
+		"3. ERROR in X.java (at line 5)\n" + 
+		"	Store<? extends Key<T>> store = new Store<Key<T>>();\n" + 
+		"	                                              ^\n" + 
+		"Bound mismatch: The type T is not a valid substitute for the bounded parameter <E extends Key<E>> of the type Key<E>\n" + 
+		"----------\n");
+}
+public void test697() {
+	this.runConformTest(
+		new String[] {
+			"X.java",
+			"import java.util.List;\n" + 
+			"public class X<U, V extends List<U>> {\n" + 
+			"	V v;\n" + 
+			"	\n" + 
+			"	void foo(X<String, ?> x1, X<Object, ?> x2) {\n" + 
+			"		String s =x1.v.get(0);\n" + 
+			"		Object o = x2.v.get(0);\n" + 
+			"		\n" + 
+			"	}\n" + 
+			"}\n",
+		},
+		"");
+}
+public void test698() {
+	this.runNegativeTest(
+		new String[] {
+			"X.java",
+			"import java.util.List;\n" + 
+			"\n" + 
+			"public class X<U extends List<Object>, V extends List<String>> {\n" + 
+			"	\n" + 
+			"	X<? super Exception, ? super Exception> x;\n" + 
+			"}\n",
+		},
+		"----------\n" + 
+		"1. ERROR in X.java (at line 5)\n" + 
+		"	X<? super Exception, ? super Exception> x;\n" + 
+		"	  ^^^^^^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? super Exception is not a valid substitute for the bounded parameter <U extends List<Object>> of the type X<U,V>\n" + 
+		"----------\n" + 
+		"2. ERROR in X.java (at line 5)\n" + 
+		"	X<? super Exception, ? super Exception> x;\n" + 
+		"	                     ^^^^^^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? super Exception is not a valid substitute for the bounded parameter <V extends List<String>> of the type X<U,V>\n" + 
+		"----------\n");
+}
+public void test699() {
+	this.runNegativeTest(
+		new String[] {
+			"X2.java",
+			"import java.util.List;\n" + 			
+			"class Other2<T extends List< Runnable>> {\n" + 
+			"}\n" + 
+			"\n" + 
+			"class X2 {\n" + 
+			"	Other2<? extends List<Throwable>> other1;\n" + 
+			"	Other2<? extends List<? super String>> other2;	\n" + 
+			"	Other2<? extends List<? extends String>> other3;		\n" + 
+			"	Other2<? extends List<? extends Runnable>> other7 = other1;\n" + 
+			"}\n",
+		},
+		"----------\n" + 
+		"1. ERROR in X2.java (at line 6)\n" + 
+		"	Other2<? extends List<Throwable>> other1;\n" + 
+		"	       ^^^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? extends List<Throwable> is not a valid substitute for the bounded parameter <T extends List<Runnable>> of the type Other2<T>\n" + 
+		"----------\n" + 
+		"2. ERROR in X2.java (at line 7)\n" + 
+		"	Other2<? extends List<? super String>> other2;	\n" + 
+		"	       ^^^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? extends List<? super String> is not a valid substitute for the bounded parameter <T extends List<Runnable>> of the type Other2<T>\n" + 
+		"----------\n" + 
+		"3. ERROR in X2.java (at line 8)\n" + 
+		"	Other2<? extends List<? extends String>> other3;		\n" + 
+		"	       ^^^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? extends List<? extends String> is not a valid substitute for the bounded parameter <T extends List<Runnable>> of the type Other2<T>\n" + 
+		"----------\n");
+}
+//https://bugs.eclipse.org/bugs/show_bug.cgi?id=96646
+public void test700() {
+	this.runConformTest(
+		new String[] {
+			"X.java",
+			"abstract class BaseFactory<T> {\n" + 
+			"	public T create() throws Exception {\n" + 
+			"		return getType().newInstance();\n" + 
+			"	}\n" + 
+			"	public abstract Class<T> getType();\n" + 
+			"}\n" + 
+			"interface StringFactory {\n" + 
+			"	public String create() throws Exception;\n" + 
+			"}\n" + 
+			"class X extends BaseFactory<String> implements StringFactory {\n" + 
+			"	@Override\n" + 
+			"	public Class<String> getType() {\n" + 
+			"		return String.class;\n" + 
+			"	}\n" + 
+			"	public static void main(String[] args) throws Exception {\n" + 
+			"		String emptyString = new X().create();\n" + 
+			"		System.out.printf(\"We have \'%s\' of type %s\", emptyString, emptyString.getClass());\n" + 
+			"	}\n" + 
+			"}\n",
+		},
+		"----------\n" + 
+		"1. ERROR in X2.java (at line 6)\n" + 
+		"	Other2<? extends List<Throwable>> other1;\n" + 
+		"	       ^^^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? extends List<Throwable> is not a valid substitute for the bounded parameter <T extends List<Runnable>> of the type Other2<T>\n" + 
+		"----------\n" + 
+		"2. ERROR in X2.java (at line 7)\n" + 
+		"	Other2<? extends List<? super String>> other2;	\n" + 
+		"	       ^^^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? extends List<? super String> is not a valid substitute for the bounded parameter <T extends List<Runnable>> of the type Other2<T>\n" + 
+		"----------\n" + 
+		"3. ERROR in X2.java (at line 8)\n" + 
+		"	Other2<? extends List<? extends String>> other3;		\n" + 
+		"	       ^^^^^^^^^^^^^^\n" + 
+		"Bound mismatch: The type ? extends List<? extends String> is not a valid substitute for the bounded parameter <T extends List<Runnable>> of the type Other2<T>\n" + 
+		"----------\n");
+}
 }
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
index 802bbd0..6a7aa22 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
@@ -14,7 +14,7 @@
 #Format: compiler.name = word1 word2 word3
 compiler.name = Eclipse Java Compiler
 #Format: compiler.version = 0.XXX[, other words (don't forget the comma if adding other words)]
-compiler.version = 0.558, pre-3.1.0 release candidate-1
+compiler.version = 0.559, pre-3.1.0 release candidate-1
 compiler.copyright = Copyright IBM Corp 2000, 2005. All rights reserved.
 
 ### scanning
diff --git a/org.eclipse.jdt.core/buildnotes_jdt-core.html b/org.eclipse.jdt.core/buildnotes_jdt-core.html
index 4a980cf..85b1333 100644
--- a/org.eclipse.jdt.core/buildnotes_jdt-core.html
+++ b/org.eclipse.jdt.core/buildnotes_jdt-core.html
@@ -37,6 +37,23 @@
   </tr>
 </table>
 
+<a name="v_559"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1RC1 - 26th May 2005
+<br>Project org.eclipse.jdt.core v_559
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_559">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95638">95638</a>
+[1.5][compiler] Possibly incorrect Bounds Mismatch errors for complicated bounds
+
+
 <a name="v_558"></a>
 <p><hr><h1>
 Eclipse Platform Build Notes&nbsp;<br>
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
index 0975e58..c21d890 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
@@ -40,7 +40,7 @@
 	public final static int Bit15 = 0x4000; 				// is unnecessary cast (expression)
 	public final static int Bit16 = 0x8000; 				// in javadoc comment (name ref, type ref, msg)
 	public final static int Bit17 = 0x10000; 				// compound assigned (reference lhs)
-	public final static int Bit18 = 0x20000; 
+	public final static int Bit18 = 0x20000; 				
 	public final static int Bit19 = 0x40000; 
 	public final static int Bit20 = 0x80000; 
 	public final static int Bit21 = 0x100000; 		
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
index 961ad86..ffaf552 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
@@ -285,7 +285,7 @@
 							return false;
 						}
 						// recurse on array type elements
-						return checkCastTypesCompatibility(scope, ((ArrayBinding) castType).elementsType(), exprElementType, expression);						
+						return checkCastTypesCompatibility(scope, castElementType, exprElementType, expression);
 						
 					case Binding.TYPE_PARAMETER : 
 						// ( TYPE_PARAMETER ) ARRAY
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java
index a2b82dc..e07835d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java
@@ -51,9 +51,7 @@
 			TypeVariableBinding[] typeVariables = currentType.typeVariables();
 			TypeBinding[] argTypes = parameterizedType.arguments;
 			if (argTypes != null && typeVariables != null) { // argTypes may be null in error cases
-				for (int i = 0, argLength = typeVariables.length; i < argLength; i++)
-				    if (typeVariables[i].boundCheck(parameterizedType, argTypes[i])  != TypeConstants.OK)
-						scope.problemReporter().typeMismatchError(argTypes[i], typeVariables[i], currentType, this.typeArguments[index][i]);
+				parameterizedType.boundCheck(scope, this.typeArguments[index]);
 			}
 		}
 	}
@@ -169,7 +167,6 @@
 				if (argHasError) {
 					return null;
 				}
-// TODO (philippe)	if ((this.bits & ASTNode.IsSuperType) != 0)
 				if (isClassScope)
 					if (((ClassScope) scope).detectHierarchyCycle(currentType, this, argTypes))
 						return null;
@@ -204,13 +201,10 @@
 					ParameterizedTypeBinding parameterizedType = scope.createParameterizedType((ReferenceBinding)currentType.erasure(), argTypes, qualifiedType);
 					// check argument type compatibility
 					if (checkBounds) // otherwise will do it in Scope.connectTypeVariables() or generic method resolution
-						for (int j = 0; j < argLength; j++)
-						    if (typeVariables[j].boundCheck(parameterizedType, argTypes[j]) != TypeConstants.OK)
-								scope.problemReporter().typeMismatchError(argTypes[j], typeVariables[j], currentType, args[j]);
+						parameterizedType.boundCheck(scope, args);
 					qualifiedType = parameterizedType;
 			    }
 		    } else {
-// TODO (philippe)	if ((this.bits & ASTNode.IsSuperType) != 0)
 				if (isClassScope)
 					if (((ClassScope) scope).detectHierarchyCycle(currentType, this, null))
 						return null;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
index 587c70a..9d45cc6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
@@ -37,9 +37,7 @@
 			TypeVariableBinding[] typeVariables = currentType.typeVariables();
 			TypeBinding[] argTypes = parameterizedType.arguments;
 			if (argTypes != null && typeVariables != null) { // may be null in error cases
-				for (int i = 0, argLength = typeVariables.length; i < argLength; i++)
-					if (typeVariables[i].boundCheck(parameterizedType, argTypes[i]) != TypeConstants.OK)
-						scope.problemReporter().typeMismatchError(argTypes[i], typeVariables[i], currentType, this.typeArguments[i]);
+				parameterizedType.boundCheck(scope, this.typeArguments);
 			}
 		}
 	}
@@ -140,7 +138,6 @@
 		     }
 		}
 		if (argHasError) return null;
-// TODO (philippe)	if ((this.bits & ASTNode.IsSuperType) != 0)
 		if (isClassScope)
 			if (((ClassScope) scope).detectHierarchyCycle(currentType, this, argTypes))
 				return null;
@@ -166,9 +163,7 @@
 	    	ParameterizedTypeBinding parameterizedType = scope.createParameterizedType((ReferenceBinding)currentType.erasure(), argTypes, enclosingType);
 			// check argument type compatibility
 			if (checkBounds) // otherwise will do it in Scope.connectTypeVariables() or generic method resolution
-				for (int i = 0; i < argLength; i++)
-				    if (typeVariables[i].boundCheck(parameterizedType, argTypes[i]) != TypeConstants.OK)
-						scope.problemReporter().typeMismatchError(argTypes[i], typeVariables[i], currentType, this.typeArguments[i]);
+				parameterizedType.boundCheck(scope, this.typeArguments);
 	
 			this.resolvedType = parameterizedType;
 			if (isTypeUseDeprecated(this.resolvedType, scope))
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
index ab59261..8e160e9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
@@ -69,7 +69,7 @@
 	 * Initialize capture bounds using substituted supertypes
 	 * e.g. given X<U, V extends X<U, V>>,     capture(X<E,?>) = X<E,capture>, where capture extends X<E,capture>
 	 */
-	public void initializeBounds(ParameterizedTypeBinding capturedParameterizedType) {
+	public void initializeBounds1(ParameterizedTypeBinding capturedParameterizedType) {
 		TypeVariableBinding wildcardVariable = wildcard.typeVariable();
 		ReferenceBinding originalWildcardSuperclass = wildcard.superclass();
 		// prevent cyclic capture: given X<T>, capture(X<? extends T> could yield a circular type
@@ -108,6 +108,59 @@
 				break;
 		}		
 	}
+	/**
+	 * Initialize capture bounds using substituted supertypes
+	 * e.g. given X<U, V extends X<U, V>>,     capture(X<E,?>) = X<E,capture>, where capture extends X<E,capture>
+	 */
+	public void initializeBounds(ParameterizedTypeBinding capturedParameterizedType) {
+		TypeVariableBinding wildcardVariable = wildcard.typeVariable();
+		ReferenceBinding originalVariableSuperclass = wildcardVariable.superclass;
+		// prevent cyclic capture: given X<T>, capture(X<? extends T> could yield a circular type
+		ReferenceBinding substitutedVariableSuperclass = originalVariableSuperclass.isTypeVariable() ? originalVariableSuperclass : (ReferenceBinding) Scope.substitute(capturedParameterizedType, originalVariableSuperclass);
+		ReferenceBinding[] substitutedVariableInterfaces = Scope.substitute(capturedParameterizedType, wildcardVariable.superInterfaces());
+		
+		switch (wildcard.boundKind) {
+			case Wildcard.EXTENDS :
+				if (wildcard.bound.isInterface()) {
+					this.superclass = substitutedVariableSuperclass;
+					// merge wildcard bound into variable superinterfaces using glb
+					if (substitutedVariableInterfaces == NoSuperInterfaces) {
+						this.superInterfaces = new ReferenceBinding[] { (ReferenceBinding) wildcard.bound };
+					} else {
+						int length = substitutedVariableInterfaces.length;
+						System.arraycopy(substitutedVariableInterfaces, 0, substitutedVariableInterfaces = new ReferenceBinding[length+1], 1, length);
+						substitutedVariableInterfaces[0] =  (ReferenceBinding) wildcard.bound;
+						this.superInterfaces = Scope.greaterLowerBound(substitutedVariableInterfaces);
+					}
+				} else {
+					// per construction the wildcard bound is a subtype of variable superclass
+					this.superclass = wildcard.bound.isArrayType() ? substitutedVariableSuperclass : (ReferenceBinding)wildcard.bound;
+					this.superInterfaces = substitutedVariableInterfaces;
+				}
+				TypeBinding substitutedWildcardBound = Scope.substitute(capturedParameterizedType, wildcard.bound);
+				this.firstBound =  substitutedWildcardBound;
+				if ((substitutedWildcardBound.tagBits & HasTypeVariable) == 0)
+					this.tagBits &= ~HasTypeVariable;
+				break;
+			case Wildcard.UNBOUND :
+				this.superclass = substitutedVariableSuperclass;
+				this.superInterfaces = substitutedVariableInterfaces;
+				this.tagBits &= ~HasTypeVariable;
+				break;
+			case Wildcard.SUPER :
+				this.superclass = substitutedVariableSuperclass;
+				substitutedWildcardBound = Scope.substitute(capturedParameterizedType, wildcard.bound);
+				if (wildcardVariable.firstBound == this.superclass 
+						|| substitutedWildcardBound == this.superclass) {
+					this.firstBound = this.superclass;
+				}
+				this.superInterfaces = substitutedVariableInterfaces;
+				this.lowerBound = substitutedWildcardBound;
+				if ((substitutedWildcardBound.tagBits & HasTypeVariable) == 0)
+					this.tagBits &= ~HasTypeVariable;
+				break;
+		}		
+	}
 	
 	/**
 	 * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#isCapture()
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
index 937b1b9..cb65adf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
@@ -12,6 +12,7 @@
 
 import java.util.Map;
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.ast.TypeReference;
 import org.eclipse.jdt.internal.compiler.ast.Wildcard;
 
 /**
@@ -47,6 +48,25 @@
 	}
 
 	/**
+	 * Iterate type arguments, and validate them according to corresponding variable bounds.
+	 */
+	public void boundCheck(Scope scope, TypeReference[] argumentReferences) {
+		if ((this.tagBits & PassedBoundCheck) == 0) {
+			boolean hasErrors = false;
+			TypeVariableBinding[] typeVariables = this.type.typeVariables();
+			if (this.arguments != null && typeVariables != null) { // arguments may be null in error cases
+				for (int i = 0, length = typeVariables.length; i < length; i++) {
+				    if (typeVariables[i].boundCheck(this, this.arguments[i])  != TypeConstants.OK) {
+				    	hasErrors = true;
+						scope.problemReporter().typeMismatchError(this.arguments[i], typeVariables[i], this.type, argumentReferences[i]);
+				    }
+				}
+			}	
+			if (!hasErrors) this.tagBits |= PassedBoundCheck; // no need to recheck it in the future
+		}
+	}
+	
+	/**
 	 * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#canBeInstantiated()
 	 */
 	public boolean canBeInstantiated() {
@@ -63,9 +83,10 @@
 		if ((this.tagBits & TagBits.HasDirectWildcard) == 0) 
 			return this;
 		
-		TypeBinding[] originalArguments = arguments, capturedArguments = originalArguments;
+		TypeBinding[] originalArguments = arguments;
 		int length = originalArguments.length;
-		capturedArguments = new TypeBinding[length];
+		TypeBinding[] capturedArguments = new TypeBinding[length];
+		
 		for (int i = 0; i < length; i++) {
 			TypeBinding argument = originalArguments[i];
 			if (argument.kind() == Binding.WILDCARD_TYPE) {
@@ -78,17 +99,14 @@
 				capturedArguments[i] = argument;
 			}
 		}
-		if (capturedArguments != originalArguments) {
-			ParameterizedTypeBinding capturedParameterizedType = this.environment.createParameterizedType(this.type, capturedArguments, enclosingType());
-			for (int i = 0; i < length; i++) {
-				TypeBinding argument = capturedArguments[i];
-				if (argument.isCapture()) {
-					((CaptureBinding)argument).initializeBounds(capturedParameterizedType);
-				}
+		ParameterizedTypeBinding capturedParameterizedType = this.environment.createParameterizedType(this.type, capturedArguments, enclosingType());
+		for (int i = 0; i < length; i++) {
+			TypeBinding argument = capturedArguments[i];
+			if (argument.isCapture()) {
+				((CaptureBinding)argument).initializeBounds(capturedParameterizedType);
 			}
-			return capturedParameterizedType;
 		}
-		return this;
+		return capturedParameterizedType;
 	}
 	/**
 	 * Collect the substitutes into a map for certain type variables inside the receiver type
@@ -588,6 +606,48 @@
         return false;
 	}
 
+	public boolean isIntersectingWith(TypeBinding otherType) {
+		if (this == otherType) 
+		    return true;
+	    if (otherType == null) 
+	        return false;
+	    switch(otherType.kind()) {
+	
+	    	case Binding.PARAMETERIZED_TYPE :
+	            if ((this.tagBits & HasDirectWildcard) == 0 && (otherType.tagBits & HasDirectWildcard) == 0 && (!this.isMemberType() || !otherType.isMemberType())) 
+	            	return false; // should have been identical
+	            ParameterizedTypeBinding otherParamType = (ParameterizedTypeBinding) otherType;
+	            if (this.type != otherParamType.type) 
+	                return false;
+	            if (!isStatic()) { // static member types do not compare their enclosing
+	            	ReferenceBinding enclosing = enclosingType();
+	            	if (enclosing != null) {
+	            		ReferenceBinding otherEnclosing = otherParamType.enclosingType();
+	            		if (otherEnclosing == null) return false;
+	            		if ((otherEnclosing.tagBits & HasDirectWildcard) == 0) {
+							if (enclosing != otherEnclosing) return false;
+	            		} else {
+	            			if (!enclosing.isEquivalentTo(otherParamType.enclosingType())) return false;
+	            		}
+	            	}
+	            }
+	            int length = this.arguments == null ? 0 : this.arguments.length;
+	            TypeBinding[] otherArguments = otherParamType.arguments;
+	            int otherLength = otherArguments == null ? 0 : otherArguments.length;
+	            if (otherLength != length) 
+	                return false;
+	            for (int i = 0; i < length; i++) {
+	            	if (!this.arguments[i].isTypeArgumentIntersecting(otherArguments[i]))
+	            		return false;
+	            }
+	            return true;
+	    	
+	    	case Binding.RAW_TYPE :
+	            return erasure() == otherType.erasure();
+	    }
+        return false;
+	}
+	
 	/**
 	 * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#isParameterizedType()
 	 */
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java
index bb8dfdc..e41ac49 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java
@@ -109,6 +109,22 @@
 	    }
         return false;
 	}
+    
+    public boolean isIntersectingWith(TypeBinding otherType) {
+		if (this == otherType) 
+		    return true;
+	    if (otherType == null) 
+	        return false;
+	    switch(otherType.kind()) {
+	
+	    	case Binding.GENERIC_TYPE :
+	    	case Binding.PARAMETERIZED_TYPE :
+	    	case Binding.RAW_TYPE :
+	            return erasure() == otherType.erasure();
+	    }
+        return false;
+	}
+    
 	/**
 	 * Raw type is not treated as a standard parameterized type
 	 * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#isParameterizedType()
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
index d525014..16525e5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
@@ -47,6 +47,9 @@
 	// test bit to identify if the type's hierarchy is inconsistent
 	long HierarchyHasProblems = ASTNode.Bit16;
 
+	// set for parameterized type with successfull bound check
+	long PassedBoundCheck = ASTNode.Bit23;
+	
 	// set for parameterized type NOT of the form X<?,?>
 	long IsBoundParameterizedType = ASTNode.Bit24; 
 	
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
index 8d4fcf5..e9d7bc6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
@@ -191,6 +191,12 @@
 public boolean isInterface() {
 	return false;
 }
+/**
+ * Returns true if a type is intersecting with another one,
+ */
+public boolean isIntersectingWith(TypeBinding otherType) {
+    return this == otherType;
+}
 public final boolean isLocalType() {
 	return (tagBits & IsLocalType) != 0;
 }
@@ -321,11 +327,11 @@
 				lowerBound = null;
 				break;
 			case Wildcard. SUPER :
-				upperBound = wildcard.typeVariable();
+				upperBound = wildcard;
 				lowerBound = wildcard.bound;
 				break;
 			case Wildcard.UNBOUND :
-				upperBound = wildcard.typeVariable();
+				upperBound = wildcard;
 				lowerBound = null;
 		}
 	}
@@ -334,9 +340,11 @@
 		if (otherWildcard.otherBounds != null) return false; // not a true wildcard (intersection type)
 		switch(otherWildcard.boundKind) {
 			case Wildcard.EXTENDS:
+				if (otherWildcard.bound == this) return true; // ? extends T  <=  ? extends ? extends T
 				return upperBound != null && upperBound.isCompatibleWith(otherWildcard.bound);
 
 			case Wildcard.SUPER :
+				if (otherWildcard.bound == this) return true; // ? super T  <=  ? super ? super T
 				return lowerBound != null && otherWildcard.bound.isCompatibleWith(lowerBound);
 
 			case Wildcard.UNBOUND :
@@ -347,6 +355,101 @@
 }
 
 /**
+ * Returns false if two given types could not intersect as argument types:
+ * List<Throwable> & List<Runnable> --> false
+ * List<? extends Throwable> & List<? extends Runnable> --> true
+ * List<? extends String> & List<? extends Runnable> --> false
+ */
+public boolean isTypeArgumentIntersecting(TypeBinding otherArgument) {
+	if (this == otherArgument)
+		return true;
+	if (this.isTypeVariable() || otherArgument.isTypeVariable())
+		return true;
+	if (this.isWildcard()) {
+		if (!otherArgument.isWildcard()) {
+			WildcardBinding wildcard = (WildcardBinding) this;
+			switch(wildcard.boundKind) {
+				case Wildcard.EXTENDS :
+					return otherArgument.isCompatibleWith(wildcard.bound);
+				case Wildcard. SUPER :
+					return wildcard.bound.isCompatibleWith(otherArgument);
+				case Wildcard.UNBOUND :
+				default:
+					return true;
+			}
+		}
+	} else if (otherArgument.isWildcard()) {
+		WildcardBinding otherWildcard = (WildcardBinding) otherArgument;
+		switch(otherWildcard.boundKind) {
+			case Wildcard.EXTENDS :
+				return this.isCompatibleWith(otherWildcard.bound);
+			case Wildcard. SUPER :
+				return otherWildcard.bound.isCompatibleWith(this);
+			case Wildcard.UNBOUND :
+			default:
+				return true;
+		}
+	}
+	TypeBinding lowerBound1 = null;
+	TypeBinding upperBound1 = null;
+	WildcardBinding wildcard = (WildcardBinding) this;
+	switch(wildcard.boundKind) {
+		case Wildcard.EXTENDS :
+			upperBound1 = wildcard.bound;
+			break;
+		case Wildcard. SUPER :
+			lowerBound1 = wildcard.bound;
+			break;
+		case Wildcard.UNBOUND :
+	}
+
+	TypeBinding lowerBound2 = null;
+	TypeBinding upperBound2 = null;
+	WildcardBinding otherWildcard = (WildcardBinding) otherArgument;
+	switch(otherWildcard.boundKind) {
+		case Wildcard.EXTENDS :
+			upperBound2 = otherWildcard.bound;
+			break;
+		case Wildcard. SUPER :
+			lowerBound2 = otherWildcard.bound;
+			break;
+		case Wildcard.UNBOUND :
+	}
+	if (lowerBound1 != null) {
+		if (lowerBound2 != null) {
+			return true; // Object could always be a candidate
+			
+		} else if (upperBound2 != null) {
+			return lowerBound1.isCompatibleWith(upperBound2);
+		} else {
+			return true;
+		}
+	} else if (upperBound1 != null) {
+		if (lowerBound2 != null) {
+			return lowerBound2.isCompatibleWith(upperBound1);
+
+		} else if (upperBound2 != null) {
+			if (upperBound1.isInterface()) {
+				if (upperBound2.isInterface())
+					return true;
+				if (upperBound2.isArrayType() || ((upperBound2 instanceof ReferenceBinding) && ((ReferenceBinding)upperBound2).isFinal())) {
+					return upperBound2.isCompatibleWith(upperBound1);
+				}
+				return true;
+			} else if (upperBound2.isInterface()) {
+				if (upperBound1.isArrayType() || ((upperBound1 instanceof ReferenceBinding) && ((ReferenceBinding)upperBound1).isFinal())) {
+					return upperBound1.isCompatibleWith(upperBound2);
+				}
+			}
+			return true;
+		} else {
+			return true;
+		}
+	} else {
+		return true;
+	}
+}
+/**
  * Returns true if the type was declared as a type variable
  */
 public boolean isTypeVariable() {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java
index 9190c16..d64fa65 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java
@@ -56,19 +56,58 @@
 		if (!(argumentType instanceof ReferenceBinding || argumentType.isArrayType()))
 			return TypeConstants.MISMATCH;	
 		
-	    if (argumentType.isWildcard()) {
-	        WildcardBinding wildcard = (WildcardBinding) argumentType;
-	        switch (wildcard.boundKind) {
-	        	case Wildcard.SUPER :
-//		            if (boundCheck(substitution, wildcard.bound) != TypeConstants.OK) return TypeConstants.MISMATCH;
-//		            break;
-		            return boundCheck(substitution, wildcard.bound); // only check the lower bound
+		if (argumentType.isWildcard()) {
+			WildcardBinding wildcard = (WildcardBinding) argumentType;
+			switch(wildcard.boundKind) {
+				case Wildcard.EXTENDS :
+					ReferenceBinding superclassBound = (ReferenceBinding)Scope.substitute(substitution, this.superclass());
+					TypeBinding wildcardBound = wildcard.bound;
+					boolean isArrayBound = wildcardBound.isArrayType();
+					if (!wildcardBound.isInterface()) {
+						if (isArrayBound) {
+							if (!wildcardBound.isCompatibleWith(superclassBound))
+								return TypeConstants.MISMATCH;
+						} else {
+							ReferenceBinding match = ((ReferenceBinding)wildcardBound).findSuperTypeErasingTo((ReferenceBinding)superclassBound.erasure());
+							if (match != null) {
+								if (!match.isIntersectingWith(superclassBound)) {
+									return TypeConstants.MISMATCH;
+								}
+							} else {
+								return TypeConstants.MISMATCH;
+							}
+						}
+					}
+					ReferenceBinding[] superInterfaceBounds = Scope.substitute(substitution, this.superInterfaces());
+					int length = superInterfaceBounds.length;
+					boolean mustImplement = isArrayBound || ((ReferenceBinding)wildcardBound).isFinal();
+					for (int i = 0; i < length; i++) {
+						TypeBinding superInterfaceBound = superInterfaceBounds[i];
+						if (isArrayBound) {
+							if (!wildcardBound.isCompatibleWith(superInterfaceBound))
+									return TypeConstants.MISMATCH;
+						} else {
+							ReferenceBinding match = ((ReferenceBinding)wildcardBound).findSuperTypeErasingTo((ReferenceBinding)superInterfaceBound.erasure());
+							if (match != null) {
+								if (!match.isIntersectingWith(superInterfaceBound)) {
+									return TypeConstants.MISMATCH;
+								}
+							} else if (mustImplement) {
+									return TypeConstants.MISMATCH; // cannot be extended further to satisfy missing bounds
+							}
+						}
+
+					}
+					break;
+					
+				case Wildcard.SUPER :
+					return boundCheck(substitution, wildcard.bound);
+					
 				case Wildcard.UNBOUND :
-					if (this == wildcard.typeVariable()) 
-						return TypeConstants.OK;
-					break;	        		
-	        }
-	    }
+					break;
+			}
+			return TypeConstants.OK;
+		}
 		boolean unchecked = false;
 		if (this.superclass.id != T_JavaLangObject) {
 			TypeBinding substitutedSuperType = hasSubstitution ? Scope.substitute(substitution, this.superclass) : this.superclass;
@@ -83,7 +122,7 @@
 					if (match.isRawType() && (substitutedSuperType.isGenericType()||substitutedSuperType.isBoundParameterizedType()))
 						unchecked = true;
 				}
-			}
+			} 
 		}
 	    for (int i = 0, length = this.superInterfaces.length; i < length; i++) {
 			TypeBinding substitutedSuperType = hasSubstitution ? Scope.substitute(substitution, this.superInterfaces[i]) : this.superInterfaces[i];
@@ -326,13 +365,7 @@
 		}
 		return false;
 	}
-	/**
-	 * Returns true if the type was declared as a type variable
-	 */
-	public boolean isTypeVariable() {
-	    return true;
-	}
-
+	
 	/**
 	 * Returns true if the 2 variables are playing exact same role: they have
 	 * the same bounds, providing one is substituted with the other: <T1 extends
@@ -375,6 +408,13 @@
 				return false;
 		return true;
 	}
+	
+	/**
+	 * Returns true if the type was declared as a type variable
+	 */
+	public boolean isTypeVariable() {
+	    return true;
+	}
 
 	/** 
 	 * Returns the original type variable for a given variable.
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java
index 97e0a6d..ed0d3e2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java
@@ -80,6 +80,7 @@
 		// cannot be asked per construction
 		return false;
 	}
+	
 	/**
 	 * Collect the substitutes into a map for certain type variables inside the receiver type
 	 * e.g.   Collection<T>.collectSubstitutes(Collection<List<X>>, Map), will populate Map with: T --> List<X>
@@ -347,7 +348,7 @@
         }
         return false;
     }
-
+    
     /**
 	 * Returns true if the type is a wildcard
 	 */
@@ -460,7 +461,7 @@
     /* (non-Javadoc)
      * @see org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding#superclass()
      */
-    public ReferenceBinding superclass() {
+    public ReferenceBinding superclass1() {
 		if (this.superclass == null) {
 			TypeBinding superType = null;
 			if (this.boundKind == Wildcard.EXTENDS && !this.bound.isInterface()) {
@@ -476,10 +477,34 @@
 
 		return this.superclass;
     }
+    
+    public ReferenceBinding superclass() {
+		if (this.superclass == null) {
+			TypeBinding superType = (this.boundKind == Wildcard.EXTENDS && !this.bound.isInterface()) 
+				? this.bound
+				: null;
+			this.superclass = superType instanceof ReferenceBinding && !superType.isInterface()
+				? (ReferenceBinding) superType
+				: environment.getType(JAVA_LANG_OBJECT);
+			
+//			TypeBinding superType = null;
+//			if (this.boundKind == Wildcard.EXTENDS && !this.bound.isInterface()) {
+//				superType = this.bound;
+//			} else {
+//				TypeVariableBinding variable = this.typeVariable();
+//				if (variable != null) superType = variable.firstBound;
+//			}
+//			this.superclass = superType instanceof ReferenceBinding && !superType.isInterface()
+//				? (ReferenceBinding) superType
+//				: environment.getType(JAVA_LANG_OBJECT);
+		}
+
+		return this.superclass;
+    }
     /* (non-Javadoc)
      * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#superInterfaces()
      */
-    public ReferenceBinding[] superInterfaces() {
+    public ReferenceBinding[] superInterfaces1() {
         if (this.superInterfaces == null) {
         	if (this.typeVariable() != null) {
         		this.superInterfaces = this.typeVariable.superInterfaces();
@@ -507,6 +532,31 @@
         return this.superInterfaces;
     }
 
+    public ReferenceBinding[] superInterfaces() {
+        if (this.superInterfaces == null) {
+        	if (this.boundKind == Wildcard.EXTENDS) {
+        		if (this.bound.isInterface()) {
+        			if (this.otherBounds != null) {
+						// augment super interfaces with the wildcard otherBounds (interfaces per construction)
+						int otherLength = this.otherBounds.length;
+						System.arraycopy(this.otherBounds, 0, this.superInterfaces = new ReferenceBinding[otherLength+1], 1, otherLength);
+						this.superInterfaces[0] = (ReferenceBinding) this.bound;
+        			} else {
+        				this.superInterfaces = new ReferenceBinding[] { (ReferenceBinding) this.bound };
+        			}
+        		} else if (this.otherBounds != null) {
+					int otherLength = this.otherBounds.length;
+        			System.arraycopy(this.otherBounds, 0, this.superInterfaces = new ReferenceBinding[otherLength], 0, otherLength);
+        		} else {
+        			this.superInterfaces = NoSuperInterfaces;
+        		}
+        	} else { 
+        		this.superInterfaces = NoSuperInterfaces;
+        	}
+        }
+        return this.superInterfaces;
+    }
+
 	public void swapUnresolved(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType, LookupEnvironment env) {
 		boolean affected = false;
 		if (this.genericType == unresolvedType) {