Update jdt.core & tests to I20130807-2000
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java
index dd8c568..bcc0eb7 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java
@@ -13,6 +13,7 @@
  *								bug 401456 - Code compiles from javac/intellij, but fails from eclipse
  *								bug 405706 - Eclipse compiler fails to give compiler error when return type is a inferred generic
  *								Bug 408441 - Type mismatch using Arrays.asList with 3 or more implementations of an interface with the interface type as the last parameter
+ *								Bug 413958 - Function override returning inherited Generic Type
  *******************************************************************************/
 package org.eclipse.jdt.core.tests.compiler.regression;
 
@@ -33,8 +34,8 @@
 	// Static initializer to specify tests subset using TESTS_* static variables
 	// All specified tests which does not belong to the class are skipped...
 	static {
-//		TESTS_NAMES = new String[] { "testBug408441" };
-//		TESTS_NAMES = new String[] { "test1464" };
+//		TESTS_NAMES = new String[] { "testBug405706" };
+//		TESTS_NAMES = new String[] { "testBug413958" };
 //		TESTS_NUMBERS = new int[] { 1465 };
 //		TESTS_RANGE = new int[] { 1097, -1 };
 	}
@@ -1165,43 +1166,6 @@
 			true,
 			customOptions);
 }
-// https://bugs.eclipse.org/bugs/show_bug.cgi?id=334622 (private access - different packages)
-public void test334622a() {
-	this.runNegativeTest(
-			new String[] {
-					"p/X.java",
-					"package p;\n" +
-					"public class X {\n" +
-					"    private Object foo;\n" +
-					"}\n",
-					"q/Y.java",
-					"package q;\n" +
-					"import p.X;\n" +
-					"public class Y {\n" +
-					"    public <T extends X> void test(T t) {\n" +
-					"        System.out.println(t.foo);\n" +
-					"    }\n" +
-					"    Zork z;\n" +
-					"}\n"
-			},
-			"----------\n" + 
-			"1. WARNING in p\\X.java (at line 3)\n" + 
-			"	private Object foo;\n" + 
-			"	               ^^^\n" + 
-			"The value of the field X.foo is not used\n" + 
-			"----------\n" + 
-			"----------\n" + 
-			"1. ERROR in q\\Y.java (at line 5)\n" + 
-			"	System.out.println(t.foo);\n" + 
-			"	                     ^^^\n" + 
-			"The field X.foo is not visible\n" + 
-			"----------\n" + 
-			"2. ERROR in q\\Y.java (at line 7)\n" + 
-			"	Zork z;\n" + 
-			"	^^^^\n" + 
-			"Zork cannot be resolved to a type\n" + 
-			"----------\n");
-}
 //https://bugs.eclipse.org/bugs/show_bug.cgi?id=338350 (unchecked cast - only unavoidable on raw expression)
 public void test338350() {
 	String[] testFiles = new String[] {
@@ -1226,8 +1190,9 @@
 			"		list.toArray((L[]) Array.newInstance(Integer.class, 2));\n" + 
 			"	}\n" + 
 			"	void bar() {\n" + 
-			"		List<String> l = Bar.getRawList();\n" + 
-			"		ArrayList<String> l2 = (ArrayList<String>) Bar.getRawList();\n" + 
+			"		List<String> l = (List<String>) Bar.getObject();\n" + 
+			"		List<String> l2 = Bar.getRawList();\n" + 
+			"		ArrayList<String> l3 = (ArrayList<String>) Bar.getRawList();\n" + 
 			"	}\n" + 
 			"}\n",
 			"Bar.java",
@@ -1287,12 +1252,17 @@
 			"Type safety: Unchecked cast from Object to L[]\n" + 
 			"----------\n" + 
 			"8. WARNING in Try.java (at line 21)\n" + 
-			"	List<String> l = Bar.getRawList();\n" + 
-			"	                 ^^^^^^^^^^^^^^^^\n" + 
-			"Type safety: The expression of type List needs unchecked conversion to conform to List<String>\n" + 
+			"	List<String> l = (List<String>) Bar.getObject();\n" + 
+			"	                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: Unchecked cast from Object to List<String>\n" + 
 			"----------\n" + 
 			"9. WARNING in Try.java (at line 22)\n" + 
-			"	ArrayList<String> l2 = (ArrayList<String>) Bar.getRawList();\n" + 
+			"	List<String> l2 = Bar.getRawList();\n" + 
+			"	                  ^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: The expression of type List needs unchecked conversion to conform to List<String>\n" + 
+			"----------\n" + 
+			"10. WARNING in Try.java (at line 23)\n" + 
+			"	ArrayList<String> l3 = (ArrayList<String>) Bar.getRawList();\n" + 
 			"	                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
 			"Type safety: Unchecked cast from List to ArrayList<String>\n" + 
 			"----------\n" + 
@@ -1314,57 +1284,99 @@
 	this.runNegativeTest(
 			testFiles,
 			"----------\n" + 
-					"1. WARNING in Try.java (at line 6)\n" + 
-					"	takeObj((E) Bar.getObject());\n" + 
-					"	        ^^^^^^^^^^^^^^^^^^^\n" + 
-					"Type safety: Unchecked cast from Object to E\n" + 
-					"----------\n" + 
-					"2. WARNING in Try.java (at line 7)\n" + 
-					"	takeObj((E) Bar.getArray());\n" + 
-					"	        ^^^^^^^^^^^^^^^^^^\n" + 
-					"Type safety: Unchecked cast from Object[] to E\n" + 
-					"----------\n" + 
-					"3. WARNING in Try.java (at line 8)\n" + 
-					"	takeObj((E) Array.newInstance(Integer.class, 2));\n" + 
-					"	        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
-					"Type safety: Unchecked cast from Object to E\n" + 
-					"----------\n" + 
-					"4. WARNING in Try.java (at line 12)\n" + 
-					"	takeArray((E[]) Bar.getArray());\n" + 
-					"	          ^^^^^^^^^^^^^^^^^^^^\n" + 
-					"Type safety: Unchecked cast from Object[] to E[]\n" + 
-					"----------\n" + 
-					"5. WARNING in Try.java (at line 13)\n" + 
-					"	takeArray((E[]) Array.newInstance(Integer.class, 2));\n" + 
-					"	          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
-					"Type safety: Unchecked cast from Object to E[]\n" + 
-					"----------\n" + 
-					"6. WARNING in Try.java (at line 17)\n" + 
-					"	list.toArray((L[]) Bar.getArray());\n" + 
-					"	             ^^^^^^^^^^^^^^^^^^^^\n" + 
-					"Type safety: Unchecked cast from Object[] to L[]\n" + 
-					"----------\n" + 
-					"7. WARNING in Try.java (at line 18)\n" + 
-					"	list.toArray((L[]) Array.newInstance(Integer.class, 2));\n" + 
-					"	             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
-					"Type safety: Unchecked cast from Object to L[]\n" + 
-					"----------\n" + 
-					"----------\n" + 
-					"1. WARNING in Bar.java (at line 11)\n" + 
-					"	public static List getRawList() {\n" + 
-					"	              ^^^^\n" + 
-					"List is a raw type. References to generic type List<E> should be parameterized\n" + 
-					"----------\n" + 
-					"2. WARNING in Bar.java (at line 12)\n" + 
-					"	return new ArrayList();\n" + 
-					"	           ^^^^^^^^^\n" + 
-					"ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized\n" + 
-					"----------\n",
-					null,
-					true,
-					customOptions);
+			"1. WARNING in Try.java (at line 6)\n" + 
+			"	takeObj((E) Bar.getObject());\n" + 
+			"	        ^^^^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: Unchecked cast from Object to E\n" + 
+			"----------\n" + 
+			"2. WARNING in Try.java (at line 7)\n" + 
+			"	takeObj((E) Bar.getArray());\n" + 
+			"	        ^^^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: Unchecked cast from Object[] to E\n" + 
+			"----------\n" + 
+			"3. WARNING in Try.java (at line 8)\n" + 
+			"	takeObj((E) Array.newInstance(Integer.class, 2));\n" + 
+			"	        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: Unchecked cast from Object to E\n" + 
+			"----------\n" + 
+			"4. WARNING in Try.java (at line 12)\n" + 
+			"	takeArray((E[]) Bar.getArray());\n" + 
+			"	          ^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: Unchecked cast from Object[] to E[]\n" + 
+			"----------\n" + 
+			"5. WARNING in Try.java (at line 13)\n" + 
+			"	takeArray((E[]) Array.newInstance(Integer.class, 2));\n" + 
+			"	          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: Unchecked cast from Object to E[]\n" + 
+			"----------\n" + 
+			"6. WARNING in Try.java (at line 17)\n" + 
+			"	list.toArray((L[]) Bar.getArray());\n" + 
+			"	             ^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: Unchecked cast from Object[] to L[]\n" + 
+			"----------\n" + 
+			"7. WARNING in Try.java (at line 18)\n" + 
+			"	list.toArray((L[]) Array.newInstance(Integer.class, 2));\n" + 
+			"	             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: Unchecked cast from Object to L[]\n" + 
+			"----------\n" + 
+			"8. WARNING in Try.java (at line 21)\n" + 
+			"	List<String> l = (List<String>) Bar.getObject();\n" + 
+			"	                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: Unchecked cast from Object to List<String>\n" + 
+			"----------\n" + 
+			"----------\n" + 
+			"1. WARNING in Bar.java (at line 11)\n" + 
+			"	public static List getRawList() {\n" + 
+			"	              ^^^^\n" + 
+			"List is a raw type. References to generic type List<E> should be parameterized\n" + 
+			"----------\n" + 
+			"2. WARNING in Bar.java (at line 12)\n" + 
+			"	return new ArrayList();\n" + 
+			"	           ^^^^^^^^^\n" + 
+			"ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized\n" + 
+			"----------\n",
+			null,
+			true,
+			customOptions);
 }
 
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=334622 (private access - different packages)
+public void test334622a() {
+	this.runNegativeTest(
+			new String[] {
+					"p/X.java",
+					"package p;\n" +
+					"public class X {\n" +
+					"    private Object foo;\n" +
+					"}\n",
+					"q/Y.java",
+					"package q;\n" +
+					"import p.X;\n" +
+					"public class Y {\n" +
+					"    public <T extends X> void test(T t) {\n" +
+					"        System.out.println(t.foo);\n" +
+					"    }\n" +
+					"    Zork z;\n" +
+					"}\n"
+			},
+			"----------\n" + 
+			"1. WARNING in p\\X.java (at line 3)\n" + 
+			"	private Object foo;\n" + 
+			"	               ^^^\n" + 
+			"The value of the field X.foo is not used\n" + 
+			"----------\n" + 
+			"----------\n" + 
+			"1. ERROR in q\\Y.java (at line 5)\n" + 
+			"	System.out.println(t.foo);\n" + 
+			"	                     ^^^\n" + 
+			"The field X.foo is not visible\n" + 
+			"----------\n" + 
+			"2. ERROR in q\\Y.java (at line 7)\n" + 
+			"	Zork z;\n" + 
+			"	^^^^\n" + 
+			"Zork cannot be resolved to a type\n" + 
+			"----------\n");
+}
 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=334622 (private access - same package)
 public void test334622b() {
 	this.runNegativeTest(
@@ -3112,4 +3124,146 @@
 			"}\n"
 		});
 }
+
+// https://bugs.eclipse.org/413958 - Function override returning inherited Generic Type
+public void testBug413958_1() {
+	runConformTest(
+		new String[] {
+			"TestA.java",
+			"public class TestA { }\n",
+			"TestB.java",
+			"public class TestB { }\n",
+			"ReadOnlyWrapper.java",
+			"@SuppressWarnings(\"unchecked\")\n" +
+			"public class ReadOnlyWrapper<A extends TestA, B extends TestB> {\n" +
+			"    protected A a;\n" +
+			"    protected B b;\n" +
+			"    public ReadOnlyWrapper(A ax,B bx){\n" +
+			"        this.a = ax;\n" +
+			"        this.b = bx;\n" +
+			"    }\n" +
+			"    public <X extends ReadOnlyWrapper<A,B>> X copy() {\n" +
+			"        return (X) new ReadOnlyWrapper<A,B>(a,b);\n" +
+			"    }\n" +
+			"    public <TA extends TestA,TB extends TestB,X extends ReadOnlyWrapper<TA,TB>> X icopy() {\n" +
+			"        return (X) new ReadOnlyWrapper<A,B>(a,b);\n" +
+			"    }\n" +
+			"    public A getA() {\n" +
+			"        return this.a;\n" +
+			"    }\n" +
+			"    public B getB() {\n" +
+			"        return this.b;\n" +
+			"    }\n" +
+			"}",
+			"WritableWrapper.java",
+			"@SuppressWarnings(\"unchecked\")\n" +
+			"public class WritableWrapper<A extends TestA, B extends TestB> extends ReadOnlyWrapper<A, B> {\n" +
+			"    public WritableWrapper(A ax,B bx){\n" +
+			"        super(ax,bx);\n" +
+			"    }\n" +
+			"    @Override\n" +
+			"    public <X extends ReadOnlyWrapper<A,B>> X copy() {\n" +
+			"        return (X) new WritableWrapper<A, B>(a,b);\n" +
+			"    }\n" +
+			"    @Override\n" +
+			"    public <TA extends TestA,TB extends TestB,X extends ReadOnlyWrapper<TA,TB>> X icopy() {\n" +
+			"        // Works in Indigo, Fails in Kepler\n" +
+			"        return (X) new WritableWrapper<A,B>(a,b);\n" +
+			"    }\n" +
+			"    public void setA(A ax) {\n" +
+			"        this.a = ax;\n" +
+			"    }\n" +
+			"    public void setB(B bx) {\n" +
+			"        this.b = bx;\n" +
+			"    }\n" +
+			"}\n",
+			"TestGenerics.java",
+			"public class TestGenerics {\n" +
+			"    public static void main(String [] args) {\n" +
+			"        final WritableWrapper<TestA, TestB> v1 = new WritableWrapper<TestA, TestB>(new TestA(), new TestB());\n" +
+			"        final WritableWrapper<TestA,TestB> v2 = v1.copy();\n" +
+			"        final WritableWrapper<TestA,TestB> v3 = v1.icopy();\n" +
+			"    }\n" +
+			"}\n"
+		});
+}
+// https://bugs.eclipse.org/413958 - Function override returning inherited Generic Type
+// variation showing different inference with / without a method parameter
+public void testBug413958_2() {
+	runNegativeTest(
+		new String[] {
+			"TestA.java",
+			"public class TestA { }\n",
+			"TestB.java",
+			"public class TestB { }\n",
+			"TestA2.java",
+			"public class TestA2 extends TestA { }\n",
+			"ReadOnlyWrapper.java",
+			"@SuppressWarnings(\"unchecked\")\n" +
+			"public class ReadOnlyWrapper<A extends TestA, B extends TestB> {\n" +
+			"    protected A a;\n" +
+			"    protected B b;\n" +
+			"    public ReadOnlyWrapper(A ax,B bx){\n" +
+			"        this.a = ax;\n" +
+			"        this.b = bx;\n" +
+			"    }\n" +
+			"    public <X extends ReadOnlyWrapper<A,B>> X copy() {\n" +
+			"        return (X) new ReadOnlyWrapper<A,B>(a,b);\n" +
+			"    }\n" +
+			"    public <TA extends TestA,TB extends TestB,X extends ReadOnlyWrapper<TA,TB>> X icopy() {\n" +
+			"        return (X) new ReadOnlyWrapper<A,B>(a,b);\n" +
+			"    }\n" +
+			"    public <TA extends TestA,TB extends TestB,X extends ReadOnlyWrapper<TA,TB>> X icopy2(TA in) {\n" +
+			"        return (X) new ReadOnlyWrapper<A,B>(a,b);\n" +
+			"    }\n" +
+			"    public A getA() {\n" +
+			"        return this.a;\n" +
+			"    }\n" +
+			"    public B getB() {\n" +
+			"        return this.b;\n" +
+			"    }\n" +
+			"}",
+			"WritableWrapper.java",
+			"@SuppressWarnings(\"unchecked\")\n" +
+			"public class WritableWrapper<A extends TestA, B extends TestB> extends ReadOnlyWrapper<A, B> {\n" +
+			"    public WritableWrapper(A ax,B bx){\n" +
+			"        super(ax,bx);\n" +
+			"    }\n" +
+			"    @Override\n" +
+			"    public <X extends ReadOnlyWrapper<A,B>> X copy() {\n" +
+			"        return (X) new WritableWrapper<A, B>(a,b);\n" +
+			"    }\n" +
+			"    @Override\n" +
+			"    public <TA extends TestA,TB extends TestB,X extends ReadOnlyWrapper<TA,TB>> X icopy() {\n" +
+			"        return (X) new WritableWrapper<A,B>(a,b);\n" +
+			"    }\n" +
+			"    @Override\n" +
+			"    public <TA extends TestA,TB extends TestB,X extends ReadOnlyWrapper<TA,TB>> X icopy2(TA in) {\n" +
+			"        return (X) new WritableWrapper<A,B>(a,b);\n" +
+			"    }\n" +
+			"    public void setA(A ax) {\n" +
+			"        this.a = ax;\n" +
+			"    }\n" +
+			"    public void setB(B bx) {\n" +
+			"        this.b = bx;\n" +
+			"    }\n" +
+			"}\n",
+			"TestGenerics.java",
+			"public class TestGenerics {\n" +
+			"    public static void main(String [] args) {\n" +
+			"        final WritableWrapper<TestA, TestB> v1 = new WritableWrapper<TestA, TestB>(new TestA(), new TestB());\n" +
+			"        final WritableWrapper<TestA,TestB> v2 = v1.copy();\n" +
+			"        final WritableWrapper<TestA,TestB> v3 = v1.icopy();\n" +
+			"        final WritableWrapper<TestA2,TestB> v4 = v1.icopy();\n" +
+			"        final WritableWrapper<TestA2,TestB> v5 = v1.icopy2(new TestA2());\n" +
+			"    }\n" +
+			"}\n"
+		},
+		"----------\n" +
+		"1. ERROR in TestGenerics.java (at line 6)\n" +
+		"	final WritableWrapper<TestA2,TestB> v4 = v1.icopy();\n" +
+		"	                                         ^^^^^^^^^^\n" +
+		"Type mismatch: cannot convert from ReadOnlyWrapper<TestA,TestB> to WritableWrapper<TestA2,TestB>\n" +
+		"----------\n");
+}
 }
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
index 7dccd2c..4063d3e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2013 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -11,6 +11,7 @@
  *     Stephan Herrmann - Contributions for
  *								bug 186342 - [compiler][null] Using annotations for null checking
  *								bug 395002 - Self bound generic class doesn't resolve bounds properly for wildcards for certain parametrisation.
+ *								bug 413958 - Function override returning inherited Generic Type
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.lookup;
 
@@ -290,7 +291,7 @@
 					if (substitute != null) continue nextTypeParameter; // already inferred previously
 					TypeBinding [] bounds = inferenceContext.getSubstitutes(current, TypeConstants.CONSTRAINT_EXTENDS);
 					if (bounds == null) continue nextTypeParameter;
-					TypeBinding[] glb = Scope.greaterLowerBound(bounds, scope);
+					TypeBinding[] glb = Scope.greaterLowerBound(bounds, scope, scope.environment());
 					TypeBinding mostSpecificSubstitute = null;
 					// https://bugs.eclipse.org/bugs/show_bug.cgi?id=341795 - Per 15.12.2.8, we should fully apply glb
 					if (glb != null) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
index fad4e0f..c62668d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
@@ -18,6 +18,7 @@
  *								bug 401271 - StackOverflowError when searching for a methods references
  *								bug 405706 - Eclipse compiler fails to give compiler error when return type is a inferred generic
  *								Bug 408441 - Type mismatch using Arrays.asList with 3 or more implementations of an interface with the interface type as the last parameter
+ *								Bug 413958 - Function override returning inherited Generic Type
  *     Jesper S Moller - Contributions for
  *								Bug 378674 - "The method can be declared as static" is wrong
  *******************************************************************************/
@@ -360,7 +361,7 @@
 	}
 
 	// 5.1.10
-	public static TypeBinding[] greaterLowerBound(TypeBinding[] types, /*@Nullable*/ Scope scope) {
+	public static TypeBinding[] greaterLowerBound(TypeBinding[] types, /*@Nullable*/ Scope scope, LookupEnvironment environment) {
 		if (types == null) return null;
 		int length = types.length;
 		if (length == 0) return null;
@@ -382,10 +383,34 @@
 				} else if (!jType.isCompatibleWith(iType, scope)) {
 					// avoid creating unsatisfiable intersection types (see https://bugs.eclipse.org/405706):
 					if (iType.isParameterizedType() && jType.isParameterizedType()) {
-						if (iType.original().isCompatibleWith(jType.original(), scope)
-								|| jType.original().isCompatibleWith(iType.original(), scope)) 
-						{
-							// parameterized types are incompatible due to incompatible type arguments => unsatisfiable
+						// if the wider of the two types (judged by originals) has type variables
+						// substitute those with their upper bounds and re-check (see https://bugs.eclipse.org/413958):
+						ParameterizedTypeBinding wideType, narrowType;
+						if (iType.original().isCompatibleWith(jType.original(), scope)) {
+							wideType = (ParameterizedTypeBinding) jType;
+							narrowType = (ParameterizedTypeBinding) iType;
+						} else if (jType.original().isCompatibleWith(iType.original(), scope)) {
+							wideType = (ParameterizedTypeBinding) iType;
+							narrowType = (ParameterizedTypeBinding) jType;
+						} else {
+							continue;
+						}
+						if (wideType.arguments == null)
+							continue; // assume we already have an error here
+						int numTypeArgs = wideType.arguments.length;
+						TypeBinding[] bounds = new TypeBinding[numTypeArgs];
+						for (int k = 0; k < numTypeArgs; k++) {
+							TypeBinding argument = wideType.arguments[k];
+							bounds[k] = argument.isTypeVariable() ? ((TypeVariableBinding)argument).upperBound() : argument;
+						}
+						ReferenceBinding wideOriginal = (ReferenceBinding) wideType.original();
+						TypeBinding substitutedWideType =
+								environment.createParameterizedType(wideOriginal, bounds, wideOriginal.enclosingType());
+						// if the narrow type is compatible with the substituted wide type, we keep silent, 
+						// substituting type variables with proper types can still satisfy all constraints,
+						// otherwise ... 
+						if (!narrowType.isCompatibleWith(substitutedWideType, scope)) {
+							// ... parameterized types are incompatible due to incompatible type arguments => unsatisfiable
 							return null;
 						}
 					}
@@ -507,7 +532,7 @@
 			    			TypeBinding [] bounds = new TypeBinding[1 + substitutedOtherBounds.length];
 			    			bounds[0] = substitutedBound;
 			    			System.arraycopy(substitutedOtherBounds, 0, bounds, 1, substitutedOtherBounds.length);
-			    			TypeBinding[] glb = Scope.greaterLowerBound(bounds, null); // re-evaluate
+			    			TypeBinding[] glb = Scope.greaterLowerBound(bounds, null, substitution.environment()); // re-evaluate
 			    			if (glb != null && glb != bounds) {
 			    				substitutedBound = glb[0];
 		    					if (glb.length == 1) {
@@ -3751,7 +3776,7 @@
 					case Wildcard.SUPER :
 						// ? super U, ? super V
 						if (wildU.boundKind == Wildcard.SUPER) {
-							TypeBinding[] glb = greaterLowerBound(new TypeBinding[]{wildU.bound,wildV.bound}, this);
+							TypeBinding[] glb = greaterLowerBound(new TypeBinding[]{wildU.bound,wildV.bound}, this, this.environment());
 							if (glb == null) return null;
 							return environment().createWildcard(genericType, rank, glb[0], null /*no extra bound*/, Wildcard.SUPER);	// TODO (philippe) need to capture entire bounds
 						}
@@ -3767,7 +3792,7 @@
 						return environment().createWildcard(genericType, rank, lub, null /*no extra bound*/, Wildcard.EXTENDS);
 					// U, ? super V
 					case Wildcard.SUPER :
-						TypeBinding[] glb = greaterLowerBound(new TypeBinding[]{u,wildV.bound}, this);
+						TypeBinding[] glb = greaterLowerBound(new TypeBinding[]{u,wildV.bound}, this, this.environment());
 						if (glb == null) return null;
 						return environment().createWildcard(genericType, rank, glb[0], null /*no extra bound*/, Wildcard.SUPER);	// TODO (philippe) need to capture entire bounds
 					case Wildcard.UNBOUND :
@@ -3785,7 +3810,7 @@
 					return environment().createWildcard(genericType, rank, lub, null /*no extra bound*/, Wildcard.EXTENDS);
 				// U, ? super V
 				case Wildcard.SUPER :
-					TypeBinding[] glb = greaterLowerBound(new TypeBinding[]{wildU.bound, v}, this);
+					TypeBinding[] glb = greaterLowerBound(new TypeBinding[]{wildU.bound, v}, this, this.environment());
 					if (glb == null) return null;
 					return environment().createWildcard(genericType, rank, glb[0], null /*no extra bound*/, Wildcard.SUPER); // TODO (philippe) need to capture entire bounds
 				case Wildcard.UNBOUND :