Update jdt.core to I20141029-2000 for Mars M3
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java
index 5321ace..12d01da 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CastTest.java
@@ -3115,6 +3115,75 @@
 		},
 		customOptions);
 }
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448112, [compiler] Compiler crash (ArrayIndexOutOfBoundsException at StackMapFrame.addStackItem()) with unused variable
+public void test448112() throws Exception {
+	if (this.complianceLevel < ClassFileConstants.JDK1_7)
+		return;
+	Map customOptions = getCompilerOptions();
+	customOptions.put(CompilerOptions.OPTION_PreserveUnusedLocal, CompilerOptions.OPTIMIZE_OUT);
+	this.runConformTest(
+		new String[] {
+			"X.java",
+			"public class X {\n" + 
+			"\n" + 
+			"  static class Y {\n" + 
+			"	  public Object getAttribute(String name) {\n" + 
+			"	  	return new Long(100L);\n" + 
+			"	  }\n" + 
+			"	}\n" + 
+			"	public static void foo2(Y y) {\n" + 
+			"\n" + 
+			"		try {\n" + 
+			"			long v1 = (Long) y.getAttribute(\"v1\");\n" + 
+			"			long v2 = (Long) y.getAttribute(\"v2\");\n" + 
+			"\n" + 
+			"			System.out.println(String.valueOf(v1));\n" + 
+			"\n" + 
+			"		} catch (java.lang.Throwable t) {}\n" + 
+			"	}\n" + 
+			"	\n" + 
+			"	public static void main(String args[]) {\n" + 
+			"		foo2(new Y());\n" + 
+			"  }\n" + 
+			"}",
+		},
+		"100", customOptions);
+	ClassFileBytesDisassembler disassembler = ToolFactory.createDefaultClassFileBytesDisassembler();
+	byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(new File(OUTPUT_DIR + File.separator  +"X.class"));
+	String actualOutput =
+		disassembler.disassemble(
+			classFileBytes,
+			"\n",
+			ClassFileBytesDisassembler.DETAILED);
+
+	String expectedOutput =
+			"  public static void foo2(X.Y y);\n" + 
+			"     0  aload_0 [y]\n" + 
+			"     1  ldc <String \"v1\"> [16]\n" + 
+			"     3  invokevirtual X$Y.getAttribute(java.lang.String) : java.lang.Object [18]\n" + 
+			"     6  checkcast java.lang.Long [24]\n" + 
+			"     9  invokevirtual java.lang.Long.longValue() : long [26]\n" + 
+			"    12  lstore_1 [v1]\n" + 
+			"    13  aload_0 [y]\n" + 
+			"    14  ldc <String \"v2\"> [30]\n" + 
+			"    16  invokevirtual X$Y.getAttribute(java.lang.String) : java.lang.Object [18]\n" + 
+			"    19  checkcast java.lang.Long [24]\n" + 
+			"    22  pop\n" + 
+			"    23  getstatic java.lang.System.out : java.io.PrintStream [32]\n" + 
+			"    26  lload_1 [v1]\n" + 
+			"    27  invokestatic java.lang.String.valueOf(long) : java.lang.String [38]\n" + 
+			"    30  invokevirtual java.io.PrintStream.println(java.lang.String) : void [44]\n" + 
+			"    33  goto 37\n" + 
+			"    36  pop\n" + 
+			"    37  return\n";
+	int index = actualOutput.indexOf(expectedOutput);
+	if (index == -1 || expectedOutput.length() == 0) {
+		System.out.println(Util.displayString(actualOutput, 2));
+	}
+	if (index == -1) {
+		assertEquals("Wrong contents", expectedOutput, actualOutput);
+	}
+}
 public static Class testClass() {
 	return CastTest.class;
 }
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 ab233ba..0e1225e 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
@@ -2553,13 +2553,8 @@
 			"    K extends EntityKey<I>> {\n" +
 			"  }\n" +
 			"}\n";
-	if (this.complianceLevel < ClassFileConstants.JDK1_8) {
-		this.runConformTest(
-			new String[] { "X.java", source },
-			"");
-	} else {
-		// see https://bugs.eclipse.org/425031
-		runNegativeTest(
+	
+	runNegativeTest(
 			new String[] { "X.java", source },
 			"----------\n" + 
 			"1. WARNING in X.java (at line 3)\n" + 
@@ -2567,12 +2562,11 @@
 			"	^^^^^^^^^\n" + 
 			"X.EntityKey is a raw type. References to generic type X.EntityKey<I> should be parameterized\n" + 
 			"----------\n" + 
-			"2. ERROR in X.java (at line 4)\n" + 
+			"2. WARNING in X.java (at line 4)\n" + 
 			"	new EntityCondenser().condense(entityKey);  \n" + 
-			"	                      ^^^^^^^^\n" + 
-			"The method condense(K) in the type X.EntityCondenser is not applicable for the arguments (X.EntityKey)\n" + 
+			"	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: Unchecked invocation condense(X.EntityKey) of the generic method condense(K) of type X.EntityCondenser\n" + 
 			"----------\n");
-	}
 }
 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=347600
 public void test347600() {
@@ -4577,60 +4571,62 @@
 			"  }\n" + 
 			"\n" + 
 			"}\n";
-	if (this.complianceLevel < ClassFileConstants.JDK1_8) {
-		runConformTest(
-			new String[] {
-				"X.java",
-				source
-			});
-	} else {
 		runNegativeTest(
 			new String[] {
 				"X.java",
 				source
 			},
 			"----------\n" + 
-			"1. ERROR in X.java (at line 8)\n" + 
+			"1. WARNING in X.java (at line 8)\n" + 
 			"	doSomethingWithFoo( any( Foo.class ), any( Foo.class ) );\n" + 
-			"	^^^^^^^^^^^^^^^^^^\n" + 
-			"The method doSomethingWithFoo(X.Foo<T>, X.Foo<T>) in the type X is not applicable for the arguments (X.Foo, X.Foo)\n" + 
+			"	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: Unchecked invocation doSomethingWithFoo(X.Foo, X.Foo) of the generic method doSomethingWithFoo(X.Foo<T>, X.Foo<T>) of type X\n" + 
 			"----------\n" + 
-			"2. WARNING in X.java (at line 12)\n" + 
+			"2. WARNING in X.java (at line 8)\n" + 
+			"	doSomethingWithFoo( any( Foo.class ), any( Foo.class ) );\n" + 
+			"	                    ^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: The expression of type X.Foo needs unchecked conversion to conform to X.Foo<Object>\n" + 
+			"----------\n" + 
+			"3. WARNING in X.java (at line 8)\n" + 
+			"	doSomethingWithFoo( any( Foo.class ), any( Foo.class ) );\n" + 
+			"	                                      ^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: The expression of type X.Foo needs unchecked conversion to conform to X.Foo<Object>\n" + 
+			"----------\n" + 
+			"4. WARNING in X.java (at line 12)\n" + 
 			"	Foo foo = any( Foo.class );\n" + 
 			"	^^^\n" + 
 			"X.Foo is a raw type. References to generic type X.Foo<T> should be parameterized\n" + 
 			"----------\n" + 
-			"3. WARNING in X.java (at line 13)\n" + 
+			"5. WARNING in X.java (at line 13)\n" + 
 			"	doSomethingWithFoo( foo, foo );\n" + 
 			"	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
 			"Type safety: Unchecked invocation doSomethingWithFoo(X.Foo, X.Foo) of the generic method doSomethingWithFoo(X.Foo<T>, X.Foo<T>) of type X\n" + 
 			"----------\n" + 
-			"4. WARNING in X.java (at line 13)\n" + 
+			"6. WARNING in X.java (at line 13)\n" + 
 			"	doSomethingWithFoo( foo, foo );\n" + 
 			"	                    ^^^\n" + 
 			"Type safety: The expression of type X.Foo needs unchecked conversion to conform to X.Foo<Object>\n" + 
 			"----------\n" + 
-			"5. WARNING in X.java (at line 13)\n" + 
+			"7. WARNING in X.java (at line 13)\n" + 
 			"	doSomethingWithFoo( foo, foo );\n" + 
 			"	                         ^^^\n" + 
 			"Type safety: The expression of type X.Foo needs unchecked conversion to conform to X.Foo<Object>\n" + 
 			"----------\n" + 
-			"6. WARNING in X.java (at line 17)\n" + 
+			"8. WARNING in X.java (at line 17)\n" + 
 			"	this.<Object>doSomethingWithFoo( any( Foo.class ), any( Foo.class ) );\n" + 
 			"	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
 			"Type safety: Unchecked invocation doSomethingWithFoo(X.Foo, X.Foo) of the generic method doSomethingWithFoo(X.Foo<T>, X.Foo<T>) of type X\n" + 
 			"----------\n" + 
-			"7. WARNING in X.java (at line 17)\n" + 
+			"9. WARNING in X.java (at line 17)\n" + 
 			"	this.<Object>doSomethingWithFoo( any( Foo.class ), any( Foo.class ) );\n" + 
 			"	                                 ^^^^^^^^^^^^^^^^\n" + 
 			"Type safety: The expression of type X.Foo needs unchecked conversion to conform to X.Foo<Object>\n" + 
 			"----------\n" + 
-			"8. WARNING in X.java (at line 17)\n" + 
+			"10. WARNING in X.java (at line 17)\n" + 
 			"	this.<Object>doSomethingWithFoo( any( Foo.class ), any( Foo.class ) );\n" + 
 			"	                                                   ^^^^^^^^^^^^^^^^\n" + 
 			"Type safety: The expression of type X.Foo needs unchecked conversion to conform to X.Foo<Object>\n" + 
 			"----------\n");
-	}
 }
 public void _testBug430686() {
 	runConformTest(
@@ -5471,7 +5467,6 @@
 }
 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=440019, [1.8][compiler] Type mismatch error with autoboxing/scalar types (works with 1.6)
 public void test440019() {
-	if (this.complianceLevel <= ClassFileConstants.JDK1_7)
 		this.runConformTest(
 		   new String[] {
 			   "A.java",
@@ -5486,9 +5481,8 @@
 		   "");
 }
 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=443596, [1.8][compiler] Failure for overload resolution in case of Generics and Varags 
-public void _test443596() {
-	if (this.complianceLevel >= ClassFileConstants.JDK1_7)
-		this.runNegativeTest(
+public void test443596() {
+	this.runNegativeTest(
 		   new String[] {
 			   "X.java",
 			   "public final class X {\n" +
@@ -5502,6 +5496,8 @@
 			   "    }\n" +
 			   "}\n",
 		   },
+		   this.complianceLevel < ClassFileConstants.JDK1_7 ?
+		   "" : 	   
 		   "----------\n" + 
 			"1. WARNING in X.java (at line 4)\n" + 
 			"	public static <T> Predicate<T> and(Predicate<? super T>... arg) { return null; }\n" + 
@@ -5509,5 +5505,261 @@
 			"Type safety: Potential heap pollution via varargs parameter arg\n" + 
 			"----------\n");
 }
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=446235, Java8 generics and boxing 
+public void test446235() {
+		this.runConformTest(
+		   new String[] {
+			   "IntegerLongBug.java",
+			   "public class IntegerLongBug {\n" +
+			   "	public static void main(String ar[]) {\n" +
+			   "		Integer number = 1000;\n" +
+			   "		long numberLong = number; //compiles fine\n" +
+			   "		long num = getNumber(5000); // compilation error\n" +
+			   "	}\n" +
+			   "	public static <T> T getNumber(T num) {\n" +
+			   "		return num;\n" +
+			   "	}\n" +
+			   "}\n",
+		   },
+		   "");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=440019, [1.8][compiler] Type mismatch error with autoboxing/scalar types (works with 1.6) 
+public void test440019_c9() {
+		this.runConformTest(
+		   new String[] {
+			   "X.java",
+			   "public class X {\n" +
+			   "    public static final int CORE_POOL_SIZE = 3;\n" +
+			   "    public static final int KEEP_ALIVE_TIME = 60; // seconds\n" +
+			   "    X(final int size, final long ttl){\n" +
+			   "        System.out.println(\"size: \" + size + \" \" + \" ttl: \" + ttl);\n" +
+			   "    }\n" +
+			   "    public static void main(String[] args) {\n" +
+			   "        new X(CORE_POOL_SIZE, get(KEEP_ALIVE_TIME)); // [1]\n" +
+			   "    }\n" +
+			   "    public static <T> T get(T value) {\n" +
+			   "        return value;\n" +
+			   "    }\n" +
+			   "}\n",
+		   },
+		   "size: 3  ttl: 60");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=446223, [1.8][compiler] Java8 generics eclipse doesn't compile  
+public void test446223() {
+		this.runNegativeTest(
+		   new String[] {
+			   "X.java",
+			   "public class X {\n" +
+			   "	public static void main(String ar[]) {\n" +
+			   "		System.out.println(\"hi\");\n" +
+			   "		DoNothing();\n" +
+			   "	}\n" +
+			   "	public interface Interface1 {\n" +
+			   "		public void go();\n" +
+			   "	}\n" +
+			   "	public interface Interface2<X> {\n" +
+			   "		public X go2();\n" +
+			   "	}\n" +
+			   "	private static <X, T extends Interface2<X> & Interface1> void DoNothing() {\n" +
+			   "		return;\n" +
+			   "	}\n" +
+			   "}\n",
+		   },
+		   "----------\n" + 
+			"1. WARNING in X.java (at line 9)\n" + 
+			"	public interface Interface2<X> {\n" + 
+			"	                            ^\n" + 
+			"The type parameter X is hiding the type X\n" + 
+			"----------\n" + 
+			"2. WARNING in X.java (at line 12)\n" + 
+			"	private static <X, T extends Interface2<X> & Interface1> void DoNothing() {\n" + 
+			"	                ^\n" + 
+			"The type parameter X is hiding the type X\n" + 
+			"----------\n");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=444334,  [1.8][compiler] Compiler generates error instead of warning on unchecked conversion 
+public void test444334() {
+		this.runNegativeTest(
+		   new String[] {
+			   "X.java",
+			   "import java.util.ArrayList;\n" +
+			   "import java.util.List;\n" +
+			   "public class X {\n" +
+			   "    public static void Main(String[] args) {\n" +
+			   "        doSomething(returnClassType(Class.class));\n" +
+			   "        doSomething(returnListType(new ArrayList<List>()));\n" +
+			   "    }\n" +
+			   "    public static <T> void doSomething(Class<T> clazz) {\n" +
+			   "        System.out.println(clazz.getSimpleName());\n" +
+			   "    }\n" +
+			   "    public static <T> T returnClassType(Class<T> clazz) {\n" +
+			   "        return null;\n" +
+			   "    }\n" +
+			   "    public static <T> void doSomething(List<T> list) {\n" +
+			   "        System.out.println(list.getClass().getSimpleName());\n" +
+			   "    }\n" +
+			   "    public static <T> T returnListType(List<T> list) {\n" +
+			   "        return null;\n" +
+			   "    }\n" +
+			   "}\n",
+		   },
+		   "----------\n" + 
+			"1. WARNING in X.java (at line 5)\n" + 
+			"	doSomething(returnClassType(Class.class));\n" + 
+			"	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: Unchecked invocation doSomething(Class) of the generic method doSomething(Class<T>) of type X\n" + 
+			"----------\n" + 
+			"2. WARNING in X.java (at line 5)\n" + 
+			"	doSomething(returnClassType(Class.class));\n" + 
+			"	            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: The expression of type Class needs unchecked conversion to conform to Class<Object>\n" + 
+			"----------\n" + 
+			"3. WARNING in X.java (at line 6)\n" + 
+			"	doSomething(returnListType(new ArrayList<List>()));\n" + 
+			"	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: Unchecked invocation doSomething(List) of the generic method doSomething(List<T>) of type X\n" + 
+			"----------\n" + 
+			"4. WARNING in X.java (at line 6)\n" + 
+			"	doSomething(returnListType(new ArrayList<List>()));\n" + 
+			"	            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Type safety: The expression of type List needs unchecked conversion to conform to List<Object>\n" + 
+			"----------\n" + 
+			"5. WARNING in X.java (at line 6)\n" + 
+			"	doSomething(returnListType(new ArrayList<List>()));\n" + 
+			"	                                         ^^^^\n" + 
+			"List is a raw type. References to generic type List<E> should be parameterized\n" + 
+			"----------\n");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=438246, [1.8][compiler] Java 8 static methods compilation error  
+public void test438246() {
+		if (this.complianceLevel < ClassFileConstants.JDK1_7)
+			return;
+		this.runNegativeTest(
+		   new String[] {
+			   "Foo.java",
+			   "import java.util.List;\n" +
+			   "public abstract class Foo<C>\n" +
+			   "{\n" +
+			   "  @SuppressWarnings(\"unchecked\")\n" +
+			   "  public static <C> void doit( List<Foo<C>> workers )\n" +
+			   "  {\n" +
+			   "    doit(  workers.toArray( new Foo[workers.size()] ) );\n" +
+			   "  }\n" +
+			   "  public static <C> void doit( Foo<C>... workers )\n" +
+			   "  {\n" +
+			   "  }\n" +
+			   "}\n",
+		   },
+		   "----------\n" + 
+			"1. WARNING in Foo.java (at line 9)\n" + 
+			"	public static <C> void doit( Foo<C>... workers )\n" + 
+			"	                                       ^^^^^^^\n" + 
+			"Type safety: Potential heap pollution via varargs parameter workers\n" + 
+			"----------\n");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448795, [1.8][compiler] Inference should discriminate between strict and loose modes   
+public void test448795() {
+		this.runNegativeTest(
+		   new String[] {
+			   "X.java",
+			   "public class X<T> {\n" +
+			   "	static <T> T element(T [] ta) {\n" +
+			   "		return ta[0];\n" +
+			   "	}\n" +
+			   "	public static void main(String[] args) {\n" +
+			   "		int x = element(new int [] { 1234 });\n" +  // check that autoboxing does not kick in for arrays, i.e engine should not slip into loose mode.
+			   "	}\n" +
+			   "}\n",
+		   },
+		   "----------\n" + 
+			"1. ERROR in X.java (at line 6)\n" + 
+			"	int x = element(new int [] { 1234 });\n" + 
+			"	        ^^^^^^^\n" + 
+			"The method element(T[]) in the type X<T> is not applicable for the arguments (int[])\n" + 
+			"----------\n");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448795, [1.8][compiler] Inference should discriminate between strict and loose modes   
+public void test448795a() {
+		this.runConformTest(
+		   new String[] {
+			   "X.java",
+			   "public class X<T> {\n" +
+			   "	static <T> T element(int x, T t) {\n" +
+			   "		System.out.println(\"Strict\");\n" +
+			   "		return t;\n" +
+			   "	}\n" +
+			   "	static <T> T element(T t1, T t2) {\n" +
+			   "		System.out.println(\"Loose\");\n" +
+			   "		return t2;\n" +
+			   "	}\n" +
+			   "	public static void main(String[] args) {\n" +
+			   "		int x = element(10, new Integer(20));\n" +
+			   "	}\n" +
+			   "}\n",
+		   },
+		   "Strict");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448795, [1.8][compiler] Inference should discriminate between strict and loose modes   
+public void test448795b() {
+		this.runConformTest(
+		   new String[] {
+			   "X.java",
+			   "public class X<T> {\n" +
+			   "	static int element(int x, Integer t) {\n" +
+			   "		System.out.println(\"non-generic\");\n" +
+			   "		return t;\n" +
+			   "	}\n" +
+			   "	static <T> T element(int t1, T t2) {\n" +
+			   "		System.out.println(\"generic\");\n" +
+			   "		return t2;\n" +
+			   "	}\n" +
+			   "	public static void main(String[] args) {\n" +
+			   "		int x = element(10, new Integer(20));\n" +
+			   "	}\n" +
+			   "}\n",
+		   },
+		   "non-generic");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448795, [1.8][compiler] Inference should discriminate between strict and loose modes   
+public void test448795c() {
+		this.runConformTest(
+		   new String[] {
+			   "X.java",
+			   "public class X<T> {\n" +
+			   "	static int element(Integer x, Integer t) {\n" +
+			   "		System.out.println(\"non-generic\");\n" +
+			   "		return t;\n" +
+			   "	}\n" +
+			   "	static <T> T element(int t1, T t2) {\n" +
+			   "		System.out.println(\"generic\");\n" +
+			   "		return t2;\n" +
+			   "	}\n" +
+			   "	public static void main(String[] args) {\n" +
+			   "		int x = element(10, new Integer(20));\n" +
+			   "	}\n" +
+			   "}\n",
+		   },
+		   "generic");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=434118, [1.8][compiler] Compilation error on generic capture/type inference   
+public void test434118() {
+		this.runConformTest(
+		   new String[] {
+			   "X.java",
+			   "public class X {\n" +
+			   "    public Object convertFails(Class<?> clazz, String value) {\n" +
+			   "        return Enum.valueOf(clazz.asSubclass(Enum.class), value);\n" +
+			   "    }\n" +
+			   "    public Object convertCompiles(Class<?> clazz, String value) {\n" +
+			   "        return Enum.valueOf(clazz.<Enum>asSubclass(Enum.class), value);\n" +
+			   "    }\n" +
+			   "    public Object convertCompiles2(Class<?> clazz, String value) {\n" +
+			   "        Class<? extends Enum> enumType = clazz.asSubclass(Enum.class);\n" +
+			   "        return Enum.valueOf(enumType, value);\n" +
+			   "    }\n" +
+			   "}\n",
+		   },
+		   "");
+}
 }
 
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_7.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_7.java
index be9a8bf..dbc14e9 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_7.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_7.java
@@ -2677,6 +2677,85 @@
 		},
 		"Expected CCE");
 }
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448028, [1.8] 1.8 cannot infer type arguments where 1.7 does 
+public void test448028() {
+	Map customOptions = getCompilerOptions();
+	customOptions.put(CompilerOptions.OPTION_ReportRedundantSpecificationOfTypeArguments, CompilerOptions.ERROR);	
+	this.runNegativeTest(
+		   new String[] {
+			   "X.java",
+			   "public class X {\n" +
+			   "\n" +
+			   "  public static interface I {/*empty*/}\n" +
+			   "\n" +
+			   "  public static class C\n" +
+			   "    implements I {/*empty*/}\n" +
+			   "\n" +
+			   "  public static class W<T extends I>\n" +
+			   "    implements I {\n" +
+			   "\n" +
+			   "    // --- problem is triggered only, when there is a vararg-parameter\n" +
+			   "    public W(final T t, final Object... o) {\n" +
+			   "      super();\n" +
+			   "    }\n" +
+			   "  }\n" +
+			   "\n" +
+			   "  // --- needed to trigger problem\n" +
+			   "  public static final <T> T inspect(final T t) {\n" +
+			   "    return t;\n" +
+			   "  }\n" +
+			   "\n" +
+			   "  // --- this compiles ok when having JDK Compilance set to 1.7 !\n" +
+			   "  public static final W<C> err1() {\n" +
+			   "    final C c = new C();\n" +
+			   "    final Object o = new Object();\n" +
+			   "    return inspect(new W<>(c, o)); // - ERROR: Cannot infer type arguments for W<> F.java\n" +
+			   "  }\n" +
+			   "\n" +
+			   "  public static final W<C> wrn1() {\n" +
+			   "    final C c = new C();\n" +
+			   "    final Object o = new Object();\n" +
+			   "    // --- giving the type-parameter yields a warning\n" +
+			   "    // --- comparing that to the error of method err1() it does not make much sense\n" +
+			   "    return inspect(new W<C>(c, o)); // - WARNING: Redundant specification of type arguments <F.C> F.java\n" +
+			   "  }\n" +
+			   "\n" +
+			   "  public static final W<C> ok1() {\n" +
+			   "    final C c = new C();\n" +
+			   "    // --- no extra vararg-paramaeter\n" +
+			   "    return inspect(new W<>(c)); // - OK\n" +
+			   "  }\n" +
+			   "\n" +
+			   "  public static final W<C> ok2() {\n" +
+			   "    final C c = new C();\n" +
+			   "    final Object o = new Object();\n" +
+			   "    // --- no check-method\n" +
+			   "    return new W<>(c, o); // - OK\n" +
+			   "  }\n" +
+			   "\n" +
+			   "  public static final W<C> ok3() {\n" +
+			   "    final C c = new C();\n" +
+			   "    // --- no check-method\n" +
+			   "    return new W<>(c); // - OK\n" +
+			   "  }\n" +
+			   "\n" +
+			   "  public static final W<C> ok4() {\n" +
+			   "    final C c = new C();\n" +
+			   "    final Object o = new Object();\n" +
+			   "    // --- this also compiles (my solution for now)\n" +
+			   "    final W<C> w = new W<>(c, o);\n" +
+			   "    return inspect(w);\n" +
+			   "  }\n" +
+			   "}\n",
+		   },
+		   "----------\n" + 
+			"1. ERROR in X.java (at line 34)\n" + 
+			"	return inspect(new W<C>(c, o)); // - WARNING: Redundant specification of type arguments <F.C> F.java\n" + 
+			"	                   ^\n" + 
+			"Redundant specification of type arguments <X.C>\n" + 
+			"----------\n", 
+			null, false, customOptions);
+}
 public static Class testClass() {
 	return GenericsRegressionTest_1_7.class;
 }
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java
index 02b2ffd..86a9f90 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java
@@ -4680,4 +4680,116 @@
 		}, 
 		"");
 }
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=434394, [1.8] inference fails in some cases when conditional expression is involved
+public void test434394() {
+	this.runConformTest(
+		new String[] {
+			"X.java",
+			"import java.util.ArrayList;\n" +
+			"import java.util.Collections;\n" +
+			"import java.util.Comparator;\n" +
+			"import java.util.List;\n" +
+			"public class X {\n" +
+			"  public void bla() {\n" +
+			"    boolean b = Boolean.TRUE.booleanValue();\n" +
+			"    List<String> c1 = new ArrayList<>();\n" +
+			"    Collections.sort(c1, new Foo(new State<>((b ? new Val<>(\"AAAA\") : new Val<>(\"BBBB\"))))); // Cannot infer type arguments for State\n" +
+			"    Collections.sort(c1,new Foo(b ? new State<>(new Val<>(\"AAAA\")) : new State<>(new Val<>(\"BBBB\")))); // this is fine\n" +
+			"  }\n" +
+			"  static class Foo implements Comparator<String>{\n" +
+			"	  public Foo(State<String> st) {\n" +
+			"		  //\n" +
+			"	  }\n" +
+			"	@Override\n" +
+			"	public int compare(String o1, String o2) {\n" +
+			"		// TODO Auto-generated method stub\n" +
+			"		return 0;\n" +
+			"	}\n" +
+			"  }\n" +
+			"	static class State<R> {\n" +
+			"		State(Val<?> o) {\n" +
+			"		}\n" +
+			"	}\n" +
+			"	static class Val<T> {\n" +
+			"		Val(T t) {}\n" +
+			"	}\n" +
+			"}\n",
+		}, 
+		"");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=445725,  [1.8][inference] Type inference not occurring with lambda expression and constructor reference
+public void test445725() {
+	this.runConformTest(
+		new String[] {
+			"X.java",
+			"import java.util.ArrayList;\n" +
+			"import java.util.Arrays;\n" +
+			"import java.util.Collection;\n" +
+			"import java.util.function.Function;\n" +
+			"import java.util.stream.Collectors;\n" +
+			"import java.util.stream.Stream;\n" +
+			"public class X {\n" +
+			"/**\n" +
+			"   * Takes a collection, applies a mapper to it, and then passes the result into the finishing\n" +
+			"   * function\n" +
+			"   */\n" +
+			"  public static <FROM, TO, RESULT> RESULT mapped(Collection<FROM> collection,\n" +
+			"                                                 Function<? super FROM, ? extends TO> mapper,\n" +
+			"                                                 Function<? super Collection<TO>, RESULT> finisher)\n" +
+			"  {\n" +
+			"    return mapped(collection.stream(), mapper, finisher);\n" +
+			"  }\n" +
+			"  /**\n" +
+			"   * Takes a stream, applies a mapper to it, and then passes the result into the finishing function\n" +
+			"   */\n" +
+			"  public static <FROM, TO, RESULT> RESULT mapped(Stream<FROM> stream,\n" +
+			"                                                 Function<? super FROM, ? extends TO> mapper,\n" +
+			"                                                 Function<? super Collection<TO>, RESULT> finisher)\n" +
+			"  {\n" +
+			"    return finisher.apply(stream.map(mapper).collect(Collectors.toList()));\n" +
+			"  }\n" +
+			"  public static void example()\n" +
+			"  {\n" +
+			"    mapped(Stream.of(\"1, 2, 3\"), Integer::parseInt, ArrayList<Integer>::new);\n" +
+			"    mapped(Arrays.asList(\"1, 2, 3\"), Integer::parseInt, ArrayList<Integer>::new);\n" +
+			"\n" +
+			"    mapped(Stream.of(\"1, 2, 3\"), Integer::parseInt, IntCollection::new);\n" +
+			"    mapped(Arrays.asList(\"1, 2, 3\"), Integer::parseInt, IntCollection::new);\n" +
+			"  }\n" +
+			"  public static class IntCollection extends ArrayList<Integer>\n" +
+			"  {\n" +
+			"    public IntCollection(Collection<Integer> numbers)\n" +
+			"    {\n" +
+			"      super(numbers);\n" +
+			"    }\n" +
+			"  }\n" +
+			"}\n",
+		}, 
+		"");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=447767, [1.8][compiler] Spurious method not applicable error due to interaction between overload resolution and type inference
+public void test447767() {
+	this.runConformTest(
+		new String[] {
+			"X.java",
+			"interface I {\n" +
+			"	void bar(String t);\n" +
+			"}\n" +
+			"public class X<T> {\n" +
+			"	X(String x) {}\n" +
+			"	X(T x) { \n" +
+			"		System.out.println(\"Here\");\n" +
+			"	}\n" +
+			"	X(T x, String ...strings) {}\n" +
+			"	public void one(X<I> c){}\n" +
+			"	public void two() {\n" +
+			"		one(new X<>((String s) -> { }));\n" +
+			"	}\n" +
+			"	public static void main(String[] args) {\n" +
+			"		new X(\"\").two();\n" +
+			"	}\n" +
+			"}\n",
+		}, 
+		"Here");
+}
 }
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaRegressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaRegressionTest.java
index b289c37..9623df9 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaRegressionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaRegressionTest.java
@@ -149,7 +149,189 @@
 			"}"
 	});
 }
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=448724, [1.8] [compiler] Wrong resolution of overloaded method when irrelevant type parameter is present and lambda is used as parameter
+public void test448724() {
+	this.runConformTest(
+		new String[] {
+			"X.java", 
+			"import java.util.concurrent.Callable;\n" +
+			"public class X {\n" +
+			"	public void mismatchRunnableCallable() throws Exception {\n" +
+			"		//Resolves to case1(Runnable) method invocation; lambda with block\n" +
+			"		case1(() -> {\"abc\".length();});\n" +
+			"		//Resolves to case1(Callable) method invocation, resulting in type mismatch; block removed - lambda with expression\n" +
+			"                case1(() -> \"abc\".length());\n" +
+			"	}\n" +
+			"	public void noSuchMismatch() throws Exception {\n" +
+			"		//no difference to case1 \n" +
+			"		case2(() -> {\"abc\".length();});\n" +
+			"		//the only difference to case 1 is the missing irrelevant <T> type parameter. Properly resolves to case2(Runnable) here\n" +
+			"		case2(() -> \"abc\".length());\n" +
+			"	}\n" +
+			"	public void case1(final Runnable r) {\n" +
+			"		System.out.println(\"case1: Runnable\");\n" +
+			"	}\n" +
+			"	public <T> void case1(Callable<Boolean> c) {\n" +
+			"		System.out.println(\"case1: Callable\");\n" +
+			"	}\n" +
+			"	public void case2(final Runnable supplier) {\n" +
+			"		System.out.println(\"case2: Runnable\");\n" +
+			"	}\n" +
+			"	public void case2(Callable<Boolean> conditionEvaluator) {\n" +
+			"		System.out.println(\"case2: Callable\");\n" +
+			"	}\n" +
+			"	public static void main(String[] args) throws Exception {\n" +
+			"		new X().mismatchRunnableCallable();\n" +
+			"		new X().noSuchMismatch();\n" +
+			"	}\n" +
+			"}\n"
+	},
+	"case1: Runnable\n" + 
+	"case1: Runnable\n" + 
+	"case2: Runnable\n" + 
+	"case2: Runnable");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=447767, [1.8][compiler] Spurious method not applicable error due to interaction between overload resolution and type inference 
+public void test447767() {
+	this.runConformTest(
+		new String[] {
+			"X.java", 
+			"interface I<T, U, V> {\n" +
+			"	T goo(U u, V v);\n" +
+			"}\n" +
+			"public class X {\n" +
+			"	static <T, U, V> T foo(T t, U u, V v) {\n" +
+			"       System.out.println(\"Wrong!\");\n" +
+			"       return null;\n" +
+			"   }\n" +
+			"	static <T, U, V> V foo(T t, U u, I<T, U, V> i) {\n" +
+			"		System.out.println(\"Right!\");\n" +
+			"       return null;\n" +
+			"	}\n" +
+			"	public static void main(String[] args) {\n" +
+			"		String s = goo(foo(\"String\", \"String\", (u, v) -> v));\n" +
+			"	}\n" +
+			"	static <T> T goo(T t) {\n" +
+			"	    return t;	\n" +
+			"	}\n" +
+			"}\n"
+	},
+	"Right!");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=447767, [1.8][compiler] Spurious method not applicable error due to interaction between overload resolution and type inference 
+public void test447767a() {
+	this.runNegativeTest(
+		new String[] {
+			"X.java", 
+			"interface I<T, U, V> {\n" +
+			"	T goo(U u, V v);\n" +
+			"}\n" +
+			"public class X {\n" +
+			"	static <T, U, V> T foo(T t, U u, I<T, U, V> i) {\n" +
+			"		return null;\n" +
+			"	}\n" +
+			"	public static void main(String[] args) {\n" +
+			"		String s = goo(foo(\"String\", \"String\", (u, v) -> v));\n" +
+			"	}\n" +
+			"	static <T> T goo(T t) {\n" +
+			"	    return t;	\n" +
+			"	}\n" +
+			"}\n"
+	},
+	"----------\n" + 
+	"1. ERROR in X.java (at line 9)\n" + 
+	"	String s = goo(foo(\"String\", \"String\", (u, v) -> v));\n" + 
+	"	                                                 ^\n" + 
+	"Type mismatch: cannot convert from Object to String\n" + 
+	"----------\n");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=447767, [1.8][compiler] Spurious method not applicable error due to interaction between overload resolution and type inference 
+public void test447767b() {
+	this.runConformTest(
+		new String[] {
+			"X.java", 
+			"interface I<T, U, V> {\n" +
+			"	T goo(U u, V v);\n" +
+			"}\n" +
+			"public class X {\n" +
+			"	static String goo(String s, String s2) {\n" +
+			"		return null;\n" +
+			"	}\n" +
+			"	static <T, U, V> V foo(T t, U u, I<T, U, V> i) {\n" +
+			"		System.out.println(\"Right!\");\n" +
+			"		return null;\n" +
+			"	}\n" +
+			"	public static void main(String[] args) {\n" +
+			"		String s = goo(foo(\"String\", \"String\", X::goo));\n" +
+			"	}\n" +
+			"	static <T> T goo(T t) {\n" +
+			"	    return t;	\n" +
+			"	}\n" +
+			"}\n"
+	},
+	"Right!");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=447767, [1.8][compiler] Spurious method not applicable error due to interaction between overload resolution and type inference 
+public void test447767c() {
+	this.runConformTest(
+		new String[] {
+			"X.java", 
+			"interface I<T, U, V> {\n" +
+			"	T goo(U u, V v);\n" +
+			"}\n" +
+			"public class X {\n" +
+			"	static String goo(String s, String s2) {\n" +
+			"		return null;\n" +
+			"	}\n" +
+			"	static <T, U, V> T foo(T t, U u, V v) {\n" +
+			"       System.out.println(\"Wrong!\");\n" +
+			"       return null;\n" +
+			"   }\n" +
+			"	static <T, U, V> V foo(T t, U u, I<T, U, V> i) {\n" +
+			"		System.out.println(\"Right!\");\n" +
+			"		return null;\n" +
+			"	}\n" +
+			"	public static void main(String[] args) {\n" +
+			"		String s = goo(foo(\"String\", \"String\", X::goo));\n" +
+			"	}\n" +
+			"	static <T> T goo(T t) {\n" +
+			"	    return t;	\n" +
+			"	}\n" +
+			"}\n"
+	},
+	"Right!");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=447767, [1.8][compiler] Spurious method not applicable error due to interaction between overload resolution and type inference 
+public void test447767d() {
+	this.runConformTest(
+		new String[] {
+			"X.java", 
+			"interface I<T, U, V> {\n" +
+			"	T goo(U u, V v);\n" +
+			"}\n" +
+			"public class X {\n" +
+			"	static String goo(String s, String s2) {\n" +
+			"		return null;\n" +
+			"	}\n" +
+			"	static <T, U, V> T foo(T t, U u, V v) {\n" +
+			"        System.out.println(\"Wrong!\");\n" +
+			"        return null;\n" +
+			"   }\n" +
+			"	static <T, U, V> V foo(T t, U u, I<T, U, V> i) {\n" +
+			"		System.out.println(\"Right!\");\n" +
+			"		return null;\n" +
+			"	}\n" +
+			"	public static void main(String[] args) {\n" +
+			"		String s = goo(foo(\"String\", \"String\", X::goo));\n" +
+			"	}\n" +
+			"	static <T> T goo(T t) {\n" +
+			"	    return t;	\n" +
+			"	}\n" +
+			"}\n"
+	},
+	"Right!");
+}
 public static Class testClass() {
 	return LambdaRegressionTest.class;
 }
-}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java
index ead8f60..0800e28 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java
@@ -8482,7 +8482,7 @@
 		"");
 }
 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=428177, - [1.8][compiler] Insistent capture issues
-public void _test428177() {
+public void test428177() {
 	runNegativeTest(
 		new String[] {
 			"X.java",
@@ -8533,7 +8533,32 @@
 			"  }\n" +
 			"}\n"
 		},
-		"valid error messages go here - some are expected since javac also complains");
+		"----------\n" + 
+		"1. ERROR in X.java (at line 19)\n" + 
+		"	Stream<String> stream2 = entries.map(toName).distinct(); // ERROR\n" + 
+		"	                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+		"Type mismatch: cannot convert from Stream<capture#7-of ? extends String> to Stream<String>\n" + 
+		"----------\n" + 
+		"2. ERROR in X.java (at line 20)\n" + 
+		"	withoutWildcard(entries.map(toName).distinct()); // ERROR\n" + 
+		"	^^^^^^^^^^^^^^^\n" + 
+		"The method withoutWildcard(Stream<String>) in the type InsistentCapture is not applicable for the arguments (Stream<capture#9-of ? extends String>)\n" + 
+		"----------\n" + 
+		"3. ERROR in X.java (at line 21)\n" + 
+		"	withoutWildcard(stream); // ERROR\n" + 
+		"	^^^^^^^^^^^^^^^\n" + 
+		"The method withoutWildcard(Stream<String>) in the type InsistentCapture is not applicable for the arguments (Stream<capture#10-of ? extends String>)\n" + 
+		"----------\n" + 
+		"4. ERROR in X.java (at line 36)\n" + 
+		"	if(\"1\" == \"\") { return stream.collect(Collectors.toList()).stream(); // ERROR\n" + 
+		"	                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+		"Type mismatch: cannot convert from Stream<capture#14-of ? extends String> to Stream<String>\n" + 
+		"----------\n" + 
+		"5. ERROR in X.java (at line 38)\n" + 
+		"	return stream.collect(Collectors.toList()); // NO ERROR\n" + 
+		"	       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+		"Type mismatch: cannot convert from List<capture#19-of ? extends String> to Stream<String>\n" + 
+		"----------\n");
 }
 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=428795, - [1.8]Internal compiler error: java.lang.NullPointerException at org.eclipse.jdt.internal.compiler.ast.MessageSend.analyseCode
 public void test428795() {
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java
index f14cfec..afd507b 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java
@@ -81,6 +81,7 @@
 import org.eclipse.jdt.internal.core.search.indexing.IndexRequest;
 import org.eclipse.jdt.internal.core.search.matching.AndPattern;
 import org.eclipse.jdt.internal.core.search.matching.MatchLocator;
+import org.eclipse.jdt.internal.core.search.matching.MethodPattern;
 import org.eclipse.jdt.internal.core.search.matching.PatternLocator;
 import org.eclipse.jdt.internal.core.search.matching.TypeDeclarationPattern;
 
@@ -13434,5 +13435,805 @@
 			"src/b400919/X.java b400919.X2 [Marker] EXACT_MATCH" 
 	);	
 }
-// Add new tests in JavaSearchBugsTests2
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_001() throws CoreException {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+			"interface I { \n" +
+			"    public void query(Foo.InnerKey key);// Search result of method query(Foo.InnerKey) returns the method query(Bar.InnerKey) too \n" +
+			"    public void query(Bar.InnerKey key);\n" +
+			"}\n" +
+			"\n" +
+			"class Foo { \n" +
+			"    static class InnerKey  {}\n" +
+			"}\n" +
+			"class Bar {\n" +
+			"    static class InnerKey {}\n" +
+			"}\n" +
+			"\n" +
+			"class X {\n" +
+			"	public static void foo(I i, Foo.InnerKey key) {\n" +
+			"		i.query(key);\n" +
+			"	}\n" +
+			"	public static void bar(I i, Bar.InnerKey key) {\n" +
+			"		i.query(key);\n" +
+			"	}\n" +
+			"	public static I getInstance() {\n" +
+			"		return null;\n" +
+			"	}\n" +
+			"}\n"
+	);
+
+	String str = this.workingCopies[0].getSource();
+	String selection = "query";
+	int start = str.indexOf(selection);
+	int length = selection.length();
+
+	IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+	MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], REFERENCES, EXACT_RULE | ERASURE_RULE);
+
+	new SearchEngine(this.workingCopies).search(pattern,
+			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+			getJavaSearchWorkingCopiesScope(),
+			this.resultCollector,
+			null);
+	assertSearchResults(
+			"src/X.java void X.foo(I, Foo.InnerKey) [query(key)] EXACT_MATCH"
+	);
+}
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_002() throws CoreException {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+			"interface I { \n" +
+			"    public void query(Foo.InnerKey key);// Search result of method query(Foo.InnerKey) returns the method query(Bar.InnerKey) too \n" +
+			"    public void query(Bar.InnerKey key);\n" +
+			"}\n" +
+			"\n" +
+			"class Foo { \n" +
+			"    static class InnerKey  {}\n" +
+			"}\n" +
+			"class Bar {\n" +
+			"    static class InnerKey {}\n" +
+			"}\n" +
+			"\n" +
+			"class X {\n" +
+			"	public static void foo(I i, Foo.InnerKey key) {\n" +
+			"		i.query(key);\n" +
+			"	}\n" +
+			"	public static void bar(I i, Bar.InnerKey key) {\n" +
+			"		i.query(key);\n" +
+			"	}\n" +
+			"	public static I getInstance() {\n" +
+			"		return null;\n" +
+			"	}\n" +
+			"}\n"
+	);
+
+	String str = this.workingCopies[0].getSource();
+	String selection = "query";
+	int start = str.indexOf(selection);
+	int length = selection.length();
+
+	IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+	MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE  | ERASURE_RULE);
+
+	new SearchEngine(this.workingCopies).search(pattern,
+			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+			getJavaSearchWorkingCopiesScope(),
+			this.resultCollector,
+			null);
+	assertSearchResults( "src/X.java void I.query(Foo.InnerKey) [query] EXACT_MATCH\n" +
+			"src/X.java void X.foo(I, Foo.InnerKey) [query(key)] EXACT_MATCH"
+	);
+}
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_003() throws CoreException {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+			"interface I { \n" +
+			"    public void query(Foo.InnerKey key);// Search result of method query(Foo.InnerKey) returns the method query(Bar.InnerKey) too \n" +
+			"    public void query/*here*/(Bar.InnerKey key);\n" +
+			"}\n" +
+			"\n" +
+			"class Foo { \n" +
+			"    static class InnerKey  {}\n" +
+			"}\n" +
+			"class Bar {\n" +
+			"    static class InnerKey {}\n" +
+			"}\n" +
+			"\n" +
+			"class X {\n" +
+			"	public static void foo(I i, Foo.InnerKey key) {\n" +
+			"		i.query(key);\n" +
+			"	}\n" +
+			"	public static void bar(I i, Bar.InnerKey key) {\n" +
+			"		i.query(key);\n" +
+			"	}\n" +
+			"	public static I getInstance() {\n" +
+			"		return null;\n" +
+			"	}\n" +
+			"}\n"
+	);
+
+	String str = this.workingCopies[0].getSource();
+	String selection = "query/*here*/";
+	int start = str.indexOf(selection);
+	int length = "query".length();
+
+	IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+	MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE | ERASURE_RULE);
+
+	new SearchEngine(this.workingCopies).search(pattern,
+			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+			getJavaSearchWorkingCopiesScope(),
+			this.resultCollector,
+			null);
+	assertSearchResults("src/X.java void I.query(Bar.InnerKey) [query] EXACT_MATCH\n" + 
+			"src/X.java void X.bar(I, Bar.InnerKey) [query(key)] EXACT_MATCH"
+	);
+}
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_004() throws CoreException {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+			"// --\n" +
+			"interface I { \n" +
+			"    public void query/*here*/(Foo.Key key);// Search result of method query(Foo.Key) returns the method query(Bar.Key) too \n" +
+			"    public void query(Key key);\n" +
+			"}\n" +
+			"\n" +
+			"class Foo { \n" +
+			"	static class Key  {	\n" +
+			"	}\n" +
+			"	public static void foo(I i, Key key) {\n" +
+			"		i.query(key);\n" +
+			"	}\n" +
+			"	\n" +
+			"}\n" +
+			"\n" +
+			"class Key {\n" +
+			"	\n" +
+			"}\n" +
+			"class Bar {\n" +
+			"    \n" +
+			"    public static void bar(I i, Key key) {\n" +
+			"		i.query(key);\n" +
+			"    }\n" +
+			"}\n" +
+			"\n" +
+			"public class X {\n" +
+			"	public static I getInstance() {\n" +
+			"		return null;\n" +
+			"	}\n" +
+			"}\n"
+	);
+
+	String str = this.workingCopies[0].getSource();
+	String selection = "query/*here*/";
+	int start = str.indexOf(selection);
+	int length = "query".length();
+
+	IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+	MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE | ERASURE_RULE);
+
+	new SearchEngine(this.workingCopies).search(pattern,
+			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+			getJavaSearchWorkingCopiesScope(),
+			this.resultCollector,
+			null);
+	assertSearchResults(
+			"src/X.java void I.query(Foo.Key) [query] EXACT_MATCH\n" + 
+			"src/X.java void Foo.foo(I, Key) [query(key)] EXACT_MATCH"
+	);
+}
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_005() throws CoreException {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+			"// --\n" +
+			"interface I { \n" +
+			"    public void query(Foo.Key key);// Search result of method query(Foo.Key) returns the method query(Bar.Key) too \n" +
+			"    public void query/*here*/(Key key);\n" +
+			"}\n" +
+			"\n" +
+			"class Foo { \n" +
+			"	static class Key  {	\n" +
+			"	}\n" +
+			"	public static void foo(I i, Key key) {\n" +
+			"		i.query(key);\n" +
+			"	}\n" +
+			"	\n" +
+			"}\n" +
+			"\n" +
+			"class Key {\n" +
+			"	\n" +
+			"}\n" +
+			"class Bar {\n" +
+			"    \n" +
+			"    public static void bar(I i, Key key) {\n" +
+			"		i.query(key);\n" +
+			"    }\n" +
+			"}\n" +
+			"\n" +
+			"public class X {\n" +
+			"	public static I getInstance() {\n" +
+			"		return null;\n" +
+			"	}\n" +
+			"}\n"
+	);
+
+	String str = this.workingCopies[0].getSource();
+	String selection = "query/*here*/";
+	int start = str.indexOf(selection);
+	int length = "query".length();
+
+	IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+	MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE | ERASURE_RULE);
+
+	new SearchEngine(this.workingCopies).search(pattern,
+			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+			getJavaSearchWorkingCopiesScope(),
+			this.resultCollector,
+			null);
+	assertSearchResults(
+			"src/X.java void I.query(Key) [query] EXACT_MATCH\n" + 
+			"src/X.java void Bar.bar(I, Key) [query(key)] EXACT_MATCH"
+	);
+}
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_006() throws CoreException {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+			"// --\n" +
+			"interface I { \n" +
+			"    public void query/*here*/(Foo.Key key);// Search result of method query(Foo.Key) returns the method query(Bar.Key) too \n" +
+			"    public void query(Key key);\n" +
+			"    public void query(Bar.Key key);\n" +
+			"}\n" +
+			"\n" +
+			"class Foo { \n" +
+			"	static class Key  {	\n" +
+			"	}\n" +
+			"	public static void foo(I i, Key key) {\n" +
+			"		i.query(key);\n" +
+			"	}\n" +
+			"	\n" +
+			"}\n" +
+			"\n" +
+			"class Key {\n" +
+			"	\n" +
+			"}\n" +
+			"class Bar {\n" +
+			"	static class Key {\n" +
+			"		\n" +
+			"	}    \n" +
+			"    public static void bar(I i, Key key) {\n" +
+			"		i.query(key);\n" +
+			"    }\n" +
+			"}\n" +
+			"\n" +
+			"public class X {\n" +
+			"	public static I getInstance() {\n" +
+			"		return null;\n" +
+			"	}\n" +
+			"    public static void bar(I i, Key key) {\n" +
+			"		i.query(key);\n" +
+			"    }\n" +
+			"}\n"
+	);
+
+	String str = this.workingCopies[0].getSource();
+	String selection = "query/*here*/";
+	int start = str.indexOf(selection);
+	int length = "query".length();
+
+	IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+	MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE | ERASURE_RULE);
+
+	new SearchEngine(this.workingCopies).search(pattern,
+			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+			getJavaSearchWorkingCopiesScope(),
+			this.resultCollector,
+			null);
+	assertSearchResults(
+			"src/X.java void I.query(Foo.Key) [query] EXACT_MATCH\n" + 
+			"src/X.java void Foo.foo(I, Key) [query(key)] EXACT_MATCH"
+	);
+}
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_007() throws CoreException {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+			"// --\n" +
+			"interface I { \n" +
+			"    public void query(Foo.Key key);// Search result of method query(Foo.Key) returns the method query(Bar.Key) too \n" +
+			"    public void query/*here*/(Key key);\n" +
+			"    public void query(Bar.Key key);\n" +
+			"}\n" +
+			"\n" +
+			"class Foo { \n" +
+			"	static class Key  {	\n" +
+			"	}\n" +
+			"	public static void foo(I i, Key key) {\n" +
+			"		i.query(key);\n" +
+			"	}\n" +
+			"	\n" +
+			"}\n" +
+			"\n" +
+			"class Key {\n" +
+			"	\n" +
+			"}\n" +
+			"class Bar {\n" +
+			"	static class Key {\n" +
+			"		\n" +
+			"	}    \n" +
+			"    public static void bar(I i, Key key) {\n" +
+			"		i.query(key);\n" +
+			"    }\n" +
+			"}\n" +
+			"\n" +
+			"public class X {\n" +
+			"	public static I getInstance() {\n" +
+			"		return null;\n" +
+			"	}\n" +
+			"    public static void bar(I i, Key key) {\n" +
+			"		i.query(key);\n" +
+			"    }\n" +
+			"}\n"
+	);
+
+	String str = this.workingCopies[0].getSource();
+	String selection = "query/*here*/";
+	int start = str.indexOf(selection);
+	int length = "query".length();
+
+	IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+	MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE | ERASURE_RULE);
+
+	new SearchEngine(this.workingCopies).search(pattern,
+			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+			getJavaSearchWorkingCopiesScope(),
+			this.resultCollector,
+			null);
+	assertSearchResults(
+			"src/X.java void I.query(Key) [query] EXACT_MATCH\n" + 
+			"src/X.java void X.bar(I, Key) [query(key)] EXACT_MATCH"
+	);
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_008() throws CoreException {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+			"// --\n" +
+			"interface I { \n" +
+			"    public void query(Foo.Key key);// Search result of method query(Foo.Key) returns the method query(Bar.Key) too \n" +
+			"    public void query(Key key);\n" +
+			"    public void query/*here*/(Bar.Key key);\n" +
+			"}\n" +
+			"\n" +
+			"class Foo { \n" +
+			"	static class Key  {	\n" +
+			"	}\n" +
+			"	public static void foo(I i, Key key) {\n" +
+			"		i.query(key);\n" +
+			"	}\n" +
+			"	\n" +
+			"}\n" +
+			"\n" +
+			"class Key {\n" +
+			"	\n" +
+			"}\n" +
+			"class Bar {\n" +
+			"	static class Key {\n" +
+			"		\n" +
+			"	}    \n" +
+			"    public static void bar(I i, Key key) {\n" +
+			"		i.query(key);\n" +
+			"    }\n" +
+			"}\n" +
+			"\n" +
+			"public class X {\n" +
+			"	public static I getInstance() {\n" +
+			"		return null;\n" +
+			"	}\n" +
+			"    public static void bar(I i, Key key) {\n" +
+			"		i.query(key);\n" +
+			"    }\n" +
+			"}\n"
+	);
+
+	String str = this.workingCopies[0].getSource();
+	String selection = "query/*here*/";
+	int start = str.indexOf(selection);
+	int length = "query".length();
+
+	IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+	MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE | ERASURE_RULE);
+
+	new SearchEngine(this.workingCopies).search(pattern,
+			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+			getJavaSearchWorkingCopiesScope(),
+			this.resultCollector,
+			null);
+	assertSearchResults(
+			"src/X.java void I.query(Bar.Key) [query] EXACT_MATCH\n" + 
+			"src/X.java void Bar.bar(I, Key) [query(key)] EXACT_MATCH"
+	);
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_009() throws CoreException {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+		"interface MyIF { \n" +
+		"    public void query(Foo.InnerKey fk, Bar.InnerKey bk, String s); \n" +
+		"    public void query/*here*/(Bar.InnerKey fk, Bar.InnerKey bk, String s);\n" +
+		"}\n" +
+		"\n" +
+		"class Foo { \n" +
+		"    static class InnerKey  {    \n" +
+		"    }\n" +
+		"\n" +
+		"}\n" +
+		"\n" +
+		"class Bar {\n" +
+		"    static class InnerKey {\n" +
+		"    }\n" +
+		"    public static void bar(MyIF i, Foo.InnerKey fk, Bar.InnerKey bk) {\n" +
+		"        i.query(fk, bk, \"\");\n" +
+		"    }\n" +
+		"}\n" +
+		"public class X {}\n" 
+	);
+
+	String str = this.workingCopies[0].getSource();
+	String selection = "query/*here*/";
+	int start = str.indexOf(selection);
+	int length = "query".length();
+
+	IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+	MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], REFERENCES, EXACT_RULE | ERASURE_RULE);
+
+	new SearchEngine(this.workingCopies).search(pattern,
+			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+			getJavaSearchWorkingCopiesScope(),
+			this.resultCollector,
+			null);
+	assertSearchResults(""
+	);
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_010() throws CoreException {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+		"interface MyIF { \n" +
+		"    public void query(Foo.InnerKey fk,  String s); \n" +
+		"    public void query/*here*/(Bar.InnerKey fk,  String s);\n" +
+		"}\n" +
+		"\n" +
+		"class Foo { \n" +
+		"    static class InnerKey  {}\n" +
+		"}\n" +
+		"\n" +
+		"class Bar {\n" +
+		"    static class InnerKey {}\n" +
+		"    public static void bar(MyIF i, Foo.InnerKey fk) {\n" +
+		"        i.query(fk, \"\");\n" +
+		"    }\n" +
+		"}\n" +
+		"public class X {}\n"
+	);
+
+	String str = this.workingCopies[0].getSource();
+	String selection = "query/*here*/";
+	int start = str.indexOf(selection);
+	int length = "query".length();
+
+	IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+	MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], REFERENCES, EXACT_RULE | ERASURE_RULE);
+
+	new SearchEngine(this.workingCopies).search(pattern,
+			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+			getJavaSearchWorkingCopiesScope(),
+			this.resultCollector,
+			null);
+	assertSearchResults(""
+	);
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_011() throws CoreException {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+		"interface MyIF { \n" +
+		"   public void query(String s, Foo.InnerKey fk); \n" +
+		"}\n" +
+		"\n" +
+		"class Foo { \n" +
+		"	static class InnerKey  {}\n" +
+		"}\n" +
+		"\n" +
+		"class Bar {\n" +
+		"	static class InnerKey {}\n" +
+		"	public static void bar(MyIF i, Foo.InnerKey fk) {\n" +
+		"		i.query(\"\", fk);\n" +
+		"    }\n" +
+		"}\n" +
+		"public class X {}\n" 
+	);
+
+	String nonExistentPattern = "MyIF.query(String, Bar.InnerKey)";
+	MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(nonExistentPattern, IJavaSearchConstants.METHOD, REFERENCES, EXACT_RULE | ERASURE_RULE);
+
+	new SearchEngine(this.workingCopies).search(pattern,
+			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+			getJavaSearchWorkingCopiesScope(),
+			this.resultCollector,
+			null);
+	assertSearchResults(""
+	);
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_012() throws CoreException {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+		"interface MyIF { \n" +
+		"    public void query/*here*/(Foo.InnerKey fk, Bar.InnerKey bk, String s); \n" +
+		"    public void query(Bar.InnerKey fk, Bar.InnerKey bk, String s);\n" +
+		"}\n" +
+		"\n" +
+		"class Foo { \n" +
+		"	static class InnerKey  {	\n" +
+		"	}\n" +
+		"	\n" +
+		"}\n" +
+		"\n" +
+		"class Bar {\n" +
+		"	static class InnerKey extends Foo.InnerKey {\n" +
+		"	}\n" +
+		"	public static void bar(MyIF i, Foo.InnerKey fk, Bar.InnerKey bk) {\n" +
+		"		i.query(fk, bk, \"\");\n" +
+		"    }\n" +
+		"}\n" +
+		"public class X {}\n" 
+	);
+
+	String str = this.workingCopies[0].getSource();
+	String selection = "query/*here*/";
+	int start = str.indexOf(selection);
+	int length = "query".length();
+
+	IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+	MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE | ERASURE_RULE);
+
+	new SearchEngine(this.workingCopies).search(pattern,
+			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+			getJavaSearchWorkingCopiesScope(),
+			this.resultCollector,
+			null);
+	assertSearchResults("src/X.java void MyIF.query(Foo.InnerKey, Bar.InnerKey, String) [query] EXACT_MATCH\n" + 
+			"src/X.java void Bar.bar(MyIF, Foo.InnerKey, Bar.InnerKey) [query(fk, bk, \"\")] EXACT_MATCH"
+	);
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_013() throws CoreException {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+		"interface MyIF { \n" +
+		"    public void query/*here*/(Foo.InnerKey key); \n" +
+		"    public void query(Bar.InnerKey key);\n" +
+		"}\n" +
+		"\n" +
+		"class Foo { \n" +
+		"	static class InnerKey  {	\n" +
+		"	}\n" +
+		"	\n" +
+		"}\n" +
+		"\n" +
+		"class Bar {\n" +
+		"	static class InnerKey{}\n" +
+		"}\n" +
+		"public class X {}\n" 
+	);
+
+	String str = this.workingCopies[0].getSource();
+	String selection = "query/*here*/";
+	int start = str.indexOf(selection);
+	int length = "query".length();
+
+	IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+	MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], ALL_OCCURRENCES, EXACT_RULE | ERASURE_RULE);
+
+	new SearchEngine(this.workingCopies).search(pattern,
+			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+			getJavaSearchWorkingCopiesScope(),
+			this.resultCollector,
+			null);
+	assertSearchResults("src/X.java void MyIF.query(Foo.InnerKey) [query] EXACT_MATCH"
+	);
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_014() throws CoreException {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/X.java",
+		"interface MyIF { \n" +
+		"    public void query/*here*/(Foo.InnerKey key); \n" +
+		"    public void query(Bar.InnerKey key);\n" +
+		"}\n" +
+		"\n" +
+		"class Foo { \n" +
+		"	static class InnerKey  {	\n" +
+		"	}\n" +
+		"	\n" +
+		"}\n" +
+		"\n" +
+		"class Bar {\n" +
+		"	static class InnerKey{}\n" +
+		"}\n" +
+		"public class X {}\n" 
+	);
+
+	String str = this.workingCopies[0].getSource();
+	String selection = "query/*here*/";
+	int start = str.indexOf(selection);
+	int length = "query".length();
+
+	IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+	MethodPattern pattern = (MethodPattern) SearchPattern.createPattern(elements[0], DECLARATIONS, EXACT_RULE | ERASURE_RULE);
+
+	new SearchEngine(this.workingCopies).search(pattern,
+			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
+			getJavaSearchWorkingCopiesScope(),
+			this.resultCollector,
+			null);
+	assertSearchResults("src/X.java void MyIF.query(Foo.InnerKey) [query] EXACT_MATCH");
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void testBug431357_015() throws CoreException {
+	String folder = "/JavaSearchBugs/src/testBug431357_015";
+	String filename = folder + "/" + "X.java";
+	try {
+		String contents =
+		"package testBug431357_015;\n" +
+		"interface MyIF { \n" +
+		"    public void query/*here*/(Foo.InnerKey key); \n" +
+		"    public void query(Bar.InnerKey key);\n" +
+		"}\n" +
+		"\n" +
+		"class Foo { \n" +
+		"	static class InnerKey  {	\n" +
+		"	}\n" +
+		"	\n" +
+		"}\n" +
+		"\n" +
+		"class Bar {\n" +
+		"	static class InnerKey{}\n" +
+		"}\n" +
+		"public class X {}\n";
+		// create files
+		createFolder(folder);
+		createFile(filename, contents);
+		waitUntilIndexesReady();
+		
+		// search
+		IType[] types = getCompilationUnit(filename).getTypes();
+		IMethod method = types[0].getMethods()[0];
+		search(method, DECLARATIONS | IJavaSearchConstants.IGNORE_DECLARING_TYPE | IJavaSearchConstants.IGNORE_RETURN_TYPE, ERASURE_RULE);
+		assertSearchResults("src/testBug431357_015/X.java void testBug431357_015.MyIF.query(Foo.InnerKey) [query] EXACT_MATCH");
+	}
+	finally {
+		// delete files
+		deleteFolder(folder);
+	}
+}
+
+/** @bug 431357
+ * [search] Search API got wrong result, when searching for method references, where the parameter is a member type of another type.
+ * enable this once 88997 is fixed
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=431357"
+ */
+public void _testBug431357_016() throws CoreException {
+	String folder = "/JavaSearchBugs/src/testBug431357_016";
+	String filename = folder + "/" + "X.java";
+	try {
+		String contents =
+			"package testBug431357_016;\n" +
+			"interface I { \n " +
+			"    public void query(Foo.Key key);\n" +
+			"    public void query/*here*/(Key key);\n " +
+			"}\n " +
+			"\n " +
+			"class Foo { \n " +
+			"	static class Key  {	\n " +
+			"	}\n " +
+			"	public static void foo(I i, Key key) {\n " +
+			"		i.query(key);\n " +
+			"	}\n " +
+			"	\n " +
+			"}\n " +
+			"\n " +
+			"class Key {\n " +
+			"	\n " +
+			"}\n " +
+			"class Bar {\n " +
+			"    \n " +
+			"    public static void bar(I i, Key key) {\n " +
+			"		i.query(key);\n " +
+			"    }\n " +
+			"}\n " +
+			"\n " +
+			"public class X {\n " +
+			"	public static I getInstance() {\n " +
+			"		return null;\n " +
+			"	}\n " +
+			"}\n ";
+		// create files
+		createFolder(folder);
+		createFile(filename, contents);
+		waitUntilIndexesReady();
+		
+		// search
+		IType[] types = getCompilationUnit(filename).getTypes();
+		IMethod method = types[0].getMethods()[1];
+		search(method, DECLARATIONS | IJavaSearchConstants.IGNORE_DECLARING_TYPE | IJavaSearchConstants.IGNORE_RETURN_TYPE, ERASURE_RULE);
+		assertSearchResults("src/testBug431357_016/X.java void testBug431357_016.I.query(Key) [query] EXACT_MATCH");
+	}
+	finally {
+		// delete files
+		deleteFolder(folder);
+	}
+}
+
 }
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java
index b41b949..2b4f750 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java
@@ -1794,7 +1794,7 @@
 	);
 }
 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=424198, [1.8][hover] IAE in Signature.createCharArrayTypeSignature when hovering on variable of wildcard type, plus compile errors
-public void _test424198a() throws JavaModelException {
+public void test424198a() throws JavaModelException {
 	this.wc = getWorkingCopy(
 			"/Resolve/src/X.java",
 			"import java.io.IOException;\n" +
@@ -1853,13 +1853,13 @@
 	IJavaElement[] elements = this.wc.codeSelect(start, length);
 	assertElementsEqual(
 		"Unexpected elements",
-		"v2 [in apply(? extends java.lang.String) [in <lambda #1> [in processJar(Path) [in InsistentCapture [in [Working copy] X.java [in <default> [in src [in Resolve]]]]]]]]",
+		"v2 [in apply(capture-of ? extends java.lang.String) [in <lambda #1> [in processJar(Path) [in InsistentCapture [in [Working copy] X.java [in <default> [in src [in Resolve]]]]]]]]",
 		elements,
 		true
 	);
 }
 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=424198, [1.8][hover] IAE in Signature.createCharArrayTypeSignature when hovering on variable of wildcard type, plus compile errors
-public void _test424198b() throws JavaModelException {
+public void test424198b() throws JavaModelException {
 	this.wc = getWorkingCopy(
 			"/Resolve/src/X.java",
 			"import java.io.IOException;\n" +
@@ -1918,7 +1918,7 @@
 	IJavaElement[] elements = this.wc.codeSelect(start, length);
 	assertElementsEqual(
 		"Unexpected elements",
-		"s1 [in accept(? extends java.lang.String) [in <lambda #1> [in withWildcard(Stream<? extends String>) [in InsistentCapture [in [Working copy] X.java [in <default> [in src [in Resolve]]]]]]]]",
+		"s1 [in accept(capture-of ? extends java.lang.String) [in <lambda #1> [in withWildcard(Stream<? extends String>) [in InsistentCapture [in [Working copy] X.java [in <default> [in src [in Resolve]]]]]]]]",
 		elements,
 		true
 	);
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalExtendedCompletionContext.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalExtendedCompletionContext.java
index d0f8ad9..e1fb0ac 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalExtendedCompletionContext.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalExtendedCompletionContext.java
@@ -285,7 +285,7 @@
 				local.declarationSourceEnd,
 				local.sourceStart,
 				local.sourceEnd,
-				local.type == null ? Signature.createTypeSignature(binding.type.readableName(), true) : Util.typeSignature(local.type),
+				local.type == null ? Signature.createTypeSignature(binding.type.signableName(), true) : Util.typeSignature(local.type),
 				binding.declaration.annotations,
 				local.modifiers,
 				local.getKind() == AbstractVariableDeclaration.PARAMETER);
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 b754261..2df2cb4 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
@@ -708,6 +708,8 @@
 	/**
 	 * After method lookup has produced 'methodBinding' but when poly expressions have been seen as arguments,
 	 * inspect the arguments to trigger another round of resolving with improved target types from the methods parameters.
+	 * If this resolving produces better types for any arguments, update the 'argumentTypes' array in-place as an
+	 * intended side effect that will feed better type information in checkInvocationArguments() and others. 
 	 * @param invocation the outer invocation which is being resolved
 	 * @param method the method produced by lookup (possibly involving type inference).
 	 * @param argumentTypes the argument types as collected from first resolving the invocation arguments and as used for the method lookup.
@@ -730,7 +732,7 @@
 			TypeBinding parameterType = InferenceContext18.getParameter(parameters, i, variableArity);
 			if (parameterType == null)
 				continue; // not much we can do without a target type, assume it only happens after some resolve error
-			if (argumentTypes[i].isPolyType()) {
+			if (argumentTypes[i] != null && argumentTypes[i].isPolyType()) {
 				argument.setExpectedType(parameterType);
 				TypeBinding updatedArgumentType = argument.resolveType(scope); 
 				if (argument instanceof LambdaExpression) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
index 6b89407..621fc3d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
@@ -710,8 +710,18 @@
 	// Given the allocation type and the arguments to the constructor, see if we can infer the constructor of the elided parameterized type.
 	MethodBinding factory = scope.getStaticFactory(allocationType, enclosingType, argumentTyps, this);
 	if (factory instanceof ParameterizedGenericMethodBinding && factory.isValidBinding()) {
-		SyntheticFactoryMethodBinding original = (SyntheticFactoryMethodBinding) factory.original();
-		return original.applyTypeArgumentsOnConstructor(((ParameterizedTypeBinding)factory.returnType).arguments);
+		SyntheticFactoryMethodBinding sfmb = (SyntheticFactoryMethodBinding) factory.original();
+		TypeVariableBinding[] constructorTypeVariables = sfmb.getConstructor().typeVariables();
+		TypeBinding [] constructorTypeArguments = constructorTypeVariables != null ? new TypeBinding[constructorTypeVariables.length] : Binding.NO_TYPES;
+		if (constructorTypeArguments.length > 0)
+			System.arraycopy(((ParameterizedGenericMethodBinding)factory).typeArguments, sfmb.typeVariables().length - constructorTypeArguments.length , 
+												constructorTypeArguments, 0, constructorTypeArguments.length);
+		MethodBinding constructor = sfmb.applyTypeArgumentsOnConstructor(((ParameterizedTypeBinding)factory.returnType).arguments, constructorTypeArguments);
+		if (constructor instanceof ParameterizedGenericMethodBinding && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8) {
+			// force an inference context to be established, but avoid tunneling through overload resolution. We know this is the MSMB.
+			return ParameterizedGenericMethodBinding.computeCompatibleMethod18(constructor.shallowOriginal(), argumentTyps, scope, this);
+		}
+		return constructor;
 	}
 	return null;
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
index c5f85a8..07f61e3 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
@@ -558,9 +558,8 @@
 	}
 	if (valueRequired) {
 		codeStream.generateImplicitConversion(this.implicitConversion);
-	} else if (needRuntimeCheckcast) {
-		boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0;
-		switch (isUnboxing ? postConversionType(currentScope).id : this.resolvedType.id) {
+	} else if (annotatedCast || needRuntimeCheckcast) {
+		switch (this.resolvedType.id) {
 			case T_long :
 			case T_double :
 				codeStream.pop2();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
index 7f0ccbf..7caa2ff 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
@@ -719,7 +719,7 @@
 	
 	public boolean isPertinentToApplicability(TypeVariableBinding typeVariable, MethodBinding method) {
 		return this.valueIfTrue.isPertinentToApplicability(typeVariable, method) 
-				&& this.valueIfFalse.isPertinentToApplicability(typeVariable, method); // not perfect.
+				&& this.valueIfFalse.isPertinentToApplicability(typeVariable, method);
 	}
 	
 	public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method) {
@@ -729,7 +729,7 @@
 	
 	@Override
 	public boolean isFunctionalType() {
-		return this.valueIfTrue.isFunctionalType() || this.valueIfFalse.isFunctionalType();
+		return this.valueIfTrue.isFunctionalType() || this.valueIfFalse.isFunctionalType(); // Even if only one arm is functional type, this will require a functional interface target
 	}
 	
 	public boolean isPolyExpression() throws UnsupportedOperationException {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
index 1db2668..60a8cda 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
@@ -694,6 +694,14 @@
 
 	/** During inference: Try to find an applicable method binding without causing undesired side-effects. */
 	public MethodBinding findCompileTimeMethodTargeting(TypeBinding targetType, Scope scope) {
+		if (this.exactMethodBinding != null) {
+			MethodBinding functionType = targetType.getSingleAbstractMethod(scope, true);
+			if (functionType == null)
+				return null;
+			int n = functionType.parameters.length;
+			int k = this.exactMethodBinding.parameters.length;
+			return (n == k || n == k + 1) ? this.exactMethodBinding : null;
+		}
 		MethodBinding targetMethod = internalResolveTentatively(targetType, scope);
 		if (targetMethod == null || !targetMethod.isValidBinding())
 			return null;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
index 2110b8b..9860d08 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
@@ -422,7 +422,13 @@
 		}
 		return hasProperBound;
 	}
-
+	
+	public void addBounds(BoundSet that, LookupEnvironment environment) {
+		if (that == null || environment == null)
+			return;
+		addBounds(that.flatten(), environment);
+	}
+	
 	public boolean isInstantiated(InferenceVariable inferenceVariable) {
 		ThreeSets three = this.boundsPerVariable.get(inferenceVariable.prototype());
 		if (three != null)
@@ -594,9 +600,7 @@
 		while (captIter.hasNext()) {
 			Entry<ParameterizedTypeBinding, ParameterizedTypeBinding> capt = captIter.next();
 			ParameterizedTypeBinding gAlpha = capt.getKey();
-			// We come in with capture(gA), we need to work with gA below. It was necessary to establish capture at the call site.
-			ParameterizedTypeBinding cgA = capt.getValue();
-			ParameterizedTypeBinding gA = (ParameterizedTypeBinding) cgA.uncapture(context.scope);
+			ParameterizedTypeBinding gA = capt.getValue();
 			ReferenceBinding g = (ReferenceBinding) gA.original();
 			final TypeVariableBinding[] parameters = g.typeVariables();
 			// construct theta = [P1:=alpha1,...]
@@ -615,7 +619,6 @@
 				addBounds(pi.getTypeBounds(alpha, theta), context.environment);
 
 				TypeBinding ai = gA.arguments[i];
-				TypeBinding cai = cgA.arguments[i];
 				if (ai instanceof WildcardBinding) {
 					WildcardBinding wildcardBinding = (WildcardBinding)ai;
 					TypeBinding t = wildcardBinding.bound;
@@ -627,14 +630,11 @@
 							it = three.sameBounds.iterator();
 							while (it.hasNext()) {
 								TypeBound bound = it.next();
-								/* With the expected type's declared type being Collector<? super T, A, R> and gAlpha being Collector<T#0,?#1,List<T#0>#2> and cgA being
-								   Collector<T#0,capture#1-of ?,List<T#0>>, without the constraint reduction below - we will never discover A to be capture#1-of ? and
-								   claim A is jlO. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=437444#c24 - #27
-								*/
-								if (!reduceOneConstraint(context, ConstraintTypeFormula.create(bound.right, cai, ReductionResult.SAME)))
-									return false;
-								// Our = reduction transitively adds a new bound that necessitates the check below for capture. 
-								if (!(bound.right instanceof InferenceVariable) && !bound.right.isCapture())
+								if (InferenceContext18.SHOULD_WORKAROUND_BUG_JDK_8054721) {
+									if (bound.right instanceof CaptureBinding && bound.right.isProperType(true))
+										continue;
+								}
+								if (!(bound.right instanceof InferenceVariable))
 									return false;
 							}
 						}
@@ -656,7 +656,7 @@
 										ReferenceBinding[] allBounds = new ReferenceBinding[n];
 										allBounds[0] = (ReferenceBinding) bi1; // TODO is this safe?
 										System.arraycopy(otherBounds, 0, allBounds, 1, n-1);
-										bi = new IntersectionCastTypeBinding(allBounds, context.environment);
+										bi = context.environment.createIntersectionCastType(allBounds);
 									}
 									addTypeBoundsFromWildcardBound(context, theta, wildcardBinding.boundKind, t, r, bi);
 									//										if (otherBounds != null) {
@@ -978,21 +978,6 @@
 		if (three == null) return null;
 		return three.findSingleWrapperType();
 	}
-
-	private TypeBinding applyInstantiations(TypeBinding type) {
-		if (type.isProperType(true))
-			return type;
-	
-		Iterator<InferenceVariable> variableIt = this.boundsPerVariable.keySet().iterator();
-		while (variableIt.hasNext()) {
-			InferenceVariable inferenceVariable = variableIt.next();
-			TypeBinding instantiation = getInstantiation(inferenceVariable, null);
-			if (instantiation != null)
-				type = type.substituteInferenceVariable(inferenceVariable, instantiation);
-		}
-		return type;
-	}
-	
 	// this condition is just way too complex to check it in-line:
 	public boolean condition18_5_2_bullet_3_3_1(InferenceVariable alpha, TypeBinding targetType) {
 		// T is a reference type, but is not a wildcard-parameterized type, and either 
@@ -1032,10 +1017,9 @@
 						/* HashMap<K#8,V#9> and HashMap<K#8,ArrayList<T>> with an instantiation for V9 = ArrayList<T> already in the 
 						   bound set should not be seen as two different parameterizations of the same generic class or interface.
 						   See https://bugs.eclipse.org/bugs/show_bug.cgi?id=432626 for a test that triggers this condition.
+						   See https://bugs.openjdk.java.net/browse/JDK-8056092: recommendation is to check for proper types.
 						*/
-						supers[0] = applyInstantiations(supers[0]);
-						supers[1] = applyInstantiations(supers[1]);
-						if (!TypeBinding.equalsEquals(supers[0], supers[1]))
+						if (supers[0].isProperType(true) && supers[1].isProperType(true) && !TypeBinding.equalsEquals(supers[0], supers[1]))
 							return true;
 					}
 				}
@@ -1075,7 +1059,8 @@
 	private boolean superOnlyRaw(TypeBinding g, TypeBinding s, LookupEnvironment env) {
 		if (s instanceof InferenceVariable)
 			return false; // inference has no super types
-		if (s.findSuperTypeOriginatingFrom(g) == null)
+		final TypeBinding superType = s.findSuperTypeOriginatingFrom(g);
+		if (superType != null && !superType.isParameterizedType())
 			return s.isCompatibleWith(env.convertToRawType(g, false));
 		return false;
 	}
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 f35a24c..0cc500d 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
@@ -291,6 +291,20 @@
 		}
 		return super.readableName();
 	}
+	
+	public char[] signableName() {
+		if (this.wildcard != null) {
+			StringBuffer buffer = new StringBuffer(10);
+			buffer
+				.append(TypeConstants.WILDCARD_CAPTURE_SIGNABLE_NAME_SUFFIX)
+				.append(this.wildcard.readableName());
+			int length = buffer.length();
+			char[] name = new char[length];
+			buffer.getChars(0, length, name, 0);
+			return name;
+		}
+		return super.readableName();
+	}
 
 	public char[] shortReadableName() {
 		if (this.wildcard != null) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding18.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding18.java
index 9fe42d1..3eaf2db 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding18.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding18.java
@@ -93,7 +93,7 @@
 			}
 			if (!multipleErasures)
 				return erasures[0];
-			return new IntersectionCastTypeBinding(erasures, this.environment);
+			return this.environment.createIntersectionCastType(erasures);
 		}
 		return super.erasure();
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java
index 2820638..783210e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java
@@ -83,20 +83,32 @@
 					if (previousMethod instanceof ParameterizedGenericMethodBinding) {
 						// find the previous inner inference context to see what inference kind this invocation needs:
 						InferenceContext18 innerCtx = invocation.getInferenceContext((ParameterizedGenericMethodBinding) previousMethod);
-						if (innerCtx == null) { // no inference -> assume it wasn't really poly after all
+						if (innerCtx == null || innerCtx.stepCompleted >= InferenceContext18.TYPE_INFERRED) { 
+							/* No inference context -> the method was likely manufactured by Scope.findExactMethod -> assume it wasn't really poly after all.
+							   Otherwise, either the constraints and initial bounds that would effectively reduce to b3 are already transferred to current context 
+							   during C Set construction. Otherwise all that is relevant is to relate the return type with expected type.
+							*/
 							TypeBinding exprType = this.left.resolvedType;
 							if (exprType == null || !exprType.isValidBinding())
 								return FALSE;
 							return ConstraintTypeFormula.create(exprType, this.right, COMPATIBLE, this.isSoft);
 						}
-						if (innerCtx.stepCompleted >= InferenceContext18.TYPE_INFERRED) {
-							// The constraints and initial bounds that would effectively reduce to b3 are already transferred to current context during C Set construction.
-							return TRUE;
+						if (innerCtx.stepCompleted >= InferenceContext18.APPLICABILITY_INFERRED) {
+							inferenceContext.currentBounds.addBounds(innerCtx.b2, inferenceContext.environment);
+							inferenceContext.inferenceVariables = innerCtx.inferenceVariables;
+							inferenceContext.inferenceKind = innerCtx.inferenceKind;
+							innerCtx.outerContext = inferenceContext;
+							inferenceContext.usesUncheckedConversion = innerCtx.usesUncheckedConversion;
+						} else {
+							return FALSE; // should not reach here.
 						}
-						inferenceContext.inferenceKind = innerCtx.inferenceKind;
+						// b2 has been lifted, inferring poly invocation type amounts to lifting b3.
+					} else {
+						inferenceContext.inferenceKind = inferenceContext.getInferenceKind(previousMethod, argumentTypes);
+						boolean isDiamond = method.isConstructor() && this.left.isPolyExpression(method);
+						inferInvocationApplicability(inferenceContext, method, argumentTypes, isDiamond, inferenceContext.inferenceKind);
+						// b2 has been lifted, inferring poly invocation type amounts to lifting b3.
 					}
-					boolean isDiamond = method.isConstructor() && this.left.isPolyExpression(method);
-					inferInvocationApplicability(inferenceContext, method, argumentTypes, isDiamond, inferenceContext.inferenceKind);
 					if (!inferPolyInvocationType(inferenceContext, invocation, this.right, method))
 						return FALSE;
 					return null; // already incorporated
@@ -214,9 +226,11 @@
 		MethodBinding functionType = t.getSingleAbstractMethod(inferenceContext.scope, true);
 		if (functionType == null)
 			return FALSE;
-
+		// potentially-applicable method for the method reference when targeting T (15.13.1),
+		MethodBinding potentiallyApplicable = reference.findCompileTimeMethodTargeting(t, inferenceContext.scope);
+		if (potentiallyApplicable == null)
+			return FALSE;
 		if (reference.isExactMethodReference()) {
-			MethodBinding potentiallyApplicable = reference.getExactMethod(); 
 			List<ConstraintFormula> newConstraints = new ArrayList<ConstraintFormula>();
 			TypeBinding[] p = functionType.parameters;
 			int n = p.length;
@@ -226,8 +240,6 @@
 			if (n == k+1) {
 				newConstraints.add(ConstraintTypeFormula.create(p[0], reference.lhs.resolvedType, COMPATIBLE));
 				offset = 1;
-			} else if (n != k) {
-				return FALSE;
 			}
 			for (int i = offset; i < n; i++)
 				newConstraints.add(ConstraintTypeFormula.create(p[i], pPrime[i-offset], COMPATIBLE));
@@ -241,10 +253,6 @@
 			}
 			return newConstraints.toArray(new ConstraintFormula[newConstraints.size()]);
 		} else { // inexact
-			MethodBinding potentiallyApplicable = reference.findCompileTimeMethodTargeting(t, inferenceContext.scope); // // potentially-applicable method for the method reference when targeting T (15.13.1),
-			if (potentiallyApplicable == null)
-				return FALSE;
-			
 			int n = functionType.parameters.length;
 			for (int i = 0; i < n; i++)
 				if (!functionType.parameters[i].isProperType(true))
@@ -331,7 +339,7 @@
 			if (returnType == TypeBinding.VOID)
 				throw new InferenceFailureException("expression has no value"); //$NON-NLS-1$
 
-			if (inferenceContext.usesUncheckedConversion()) {
+			if (inferenceContext.usesUncheckedConversion) {
 				// spec says erasure, but we don't really have compatibility rules for erasure, use raw type instead:
 				TypeBinding erasure = inferenceContext.environment.convertToRawType(returnType, false);
 				ConstraintTypeFormula newConstraint = ConstraintTypeFormula.create(erasure, targetType, COMPATIBLE);
@@ -348,18 +356,29 @@
 				InferenceVariable[] betas = inferenceContext.addTypeVariableSubstitutions(arguments);
 				ParameterizedTypeBinding gbeta = inferenceContext.environment.createParameterizedType(
 						parameterizedType.genericType(), betas, parameterizedType.enclosingType(), parameterizedType.getTypeAnnotations());
-				inferenceContext.currentBounds.captures.put(gbeta, parameterizedType.capture(inferenceContext.scope, invocationSite.sourceEnd())); // established: both types have nonnull arguments
+				inferenceContext.currentBounds.captures.put(gbeta, parameterizedType); // established: both types have nonnull arguments
+				if (InferenceContext18.SHOULD_WORKAROUND_BUG_JDK_8054721) {
+					parameterizedType = parameterizedType.capture(inferenceContext.scope, invocationSite.sourceEnd());
+					arguments = parameterizedType.arguments;
+					for (int i = 0, length = arguments.length; i < length; i++) {
+						if (arguments[i].isCapture() && arguments[i].isProperType(true)) {
+							CaptureBinding capture = (CaptureBinding) arguments[i];
+							inferenceContext.currentBounds.addBound(new TypeBound(betas[i], capture, SAME), inferenceContext.environment);
+						}
+					}
+				}
 				ConstraintTypeFormula newConstraint = ConstraintTypeFormula.create(gbeta, targetType, COMPATIBLE);
 				return inferenceContext.reduceAndIncorporate(newConstraint);
 			}
-			if (rTheta instanceof InferenceVariable) {
-				InferenceVariable alpha = (InferenceVariable) rTheta;
+			if (rTheta.leafComponentType() instanceof InferenceVariable) { // https://bugs.openjdk.java.net/browse/JDK-8062082
+				InferenceVariable alpha = (InferenceVariable) rTheta.leafComponentType();
+				TypeBinding targetLeafType = targetType.leafComponentType();
 				boolean toResolve = false;
-				if (inferenceContext.currentBounds.condition18_5_2_bullet_3_3_1(alpha, targetType)) {
+				if (inferenceContext.currentBounds.condition18_5_2_bullet_3_3_1(alpha, targetLeafType)) {
 					toResolve = true;
-				} else if (inferenceContext.currentBounds.condition18_5_2_bullet_3_3_2(alpha, targetType, inferenceContext)) {
+				} else if (inferenceContext.currentBounds.condition18_5_2_bullet_3_3_2(alpha, targetLeafType, inferenceContext)) {
 					toResolve = true;
-				} else if (targetType.isPrimitiveType()) {
+				} else if (targetLeafType.isPrimitiveType()) {
 					TypeBinding wrapper = inferenceContext.currentBounds.findWrapperTypeBound(alpha);
 					if (wrapper != null)
 						toResolve = true;
@@ -369,6 +388,9 @@
 					if (solution == null)
 						return false;
 					TypeBinding u = solution.getInstantiation(alpha, null).capture(inferenceContext.scope, invocationSite.sourceEnd());
+					if (rTheta.dimensions() != 0) {
+						u = inferenceContext.environment.createArrayType(u, rTheta.dimensions());
+					}
 					ConstraintTypeFormula newConstraint = ConstraintTypeFormula.create(u, targetType, COMPATIBLE);
 					return inferenceContext.reduceAndIncorporate(newConstraint);
 				}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintFormula.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintFormula.java
index acd0260..1b5eba7 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintFormula.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintFormula.java
@@ -30,26 +30,6 @@
 
 	public abstract Object reduce(InferenceContext18 inferenceContext) throws InferenceFailureException;
 
-	/** 5.3: compatibility check which includes the option of boxing/unboxing. */
-	protected boolean isCompatibleWithInLooseInvocationContext(TypeBinding one, TypeBinding two, InferenceContext18 context) {
-		if (one.isCompatibleWith(two, context.scope))
-			return true;
-		if (one.isBaseType() == two.isBaseType()) // this also protects against comparing null & primitive
-			return false;
-		if (one.isPrimitiveType()) {
-			if (!two.isBaseType()) {
-				TypeBinding boxingType = context.environment.computeBoxingType(one);
-				if (boxingType != one) //$IDENTITY-COMPARISON$ just checking if boxing could help
-					return boxingType.isCompatibleWith(two, context.scope);
-			}
-		} else if (two.isPrimitiveType()) {
-			TypeBinding boxingType = context.environment.computeBoxingType(two);
-			if (boxingType != two) //$IDENTITY-COMPARISON$ just checking if boxing could help
-				return one.isCompatibleWith(boxingType, context.scope);
-		}
-		return false;
-	}
-
 	Collection<InferenceVariable> inputVariables(InferenceContext18 context) {
 		return EMPTY_VARIABLE_LIST;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintTypeFormula.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintTypeFormula.java
index 20ba95e..4e7994a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintTypeFormula.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintTypeFormula.java
@@ -61,15 +61,17 @@
 		case COMPATIBLE:
 			// 18.2.2:
 			if (this.left.isProperType(true) && this.right.isProperType(true)) {
-				if (isCompatibleWithInLooseInvocationContext(this.left, this.right, inferenceContext))
-					return TRUE;
-				return FALSE;
+				return this.left.isCompatibleWith(this.right, inferenceContext.scope) || this.left.isBoxingCompatibleWith(this.right, inferenceContext.scope) ? TRUE : FALSE;
 			}
 			if (this.left.isPrimitiveType()) {
+				if (inferenceContext.inferenceKind == InferenceContext18.CHECK_STRICT)
+					inferenceContext.inferenceKind = InferenceContext18.CHECK_LOOSE;
 				TypeBinding sPrime = inferenceContext.environment.computeBoxingType(this.left);
 				return ConstraintTypeFormula.create(sPrime, this.right, COMPATIBLE, this.isSoft);
 			}
 			if (this.right.isPrimitiveType()) {
+				if (inferenceContext.inferenceKind == InferenceContext18.CHECK_STRICT)
+					inferenceContext.inferenceKind = InferenceContext18.CHECK_LOOSE;
 				TypeBinding tPrime = inferenceContext.environment.computeBoxingType(this.right);
 				return ConstraintTypeFormula.create(this.left, tPrime, SAME, this.isSoft);
 			}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
index 32bf11d..8f2268a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
@@ -79,11 +79,11 @@
  * <dt>18.5.1 Invocation Applicability Inference</dt>
  * <dd>{@link #inferInvocationApplicability(MethodBinding, TypeBinding[], boolean)}. Prepare the initial state for
  * 	inference of a generic invocation - no target type used at this point.
- *  Need to call {@link #solve()} afterwards to produce the intermediate result.<br/>
+ *  Need to call {@link #solve(boolean)} with true afterwards to produce the intermediate result.<br/>
  *  Called indirectly from {@link Scope#findMethod(ReferenceBinding, char[], TypeBinding[], InvocationSite, boolean)} et al
  *  to select applicable methods into overload resolution.</dd>
  * <dt>18.5.2 Invocation Type Inference</dt>
- * <dd>{@link InferenceContext18#inferInvocationType(BoundSet, TypeBinding, InvocationSite, MethodBinding)}. After a
+ * <dd>{@link InferenceContext18#inferInvocationType(TypeBinding, InvocationSite, MethodBinding)}. After a
  * 	most specific method has been picked, and given a target type determine the final generic instantiation.
  *  As long as a target type is still unavailable this phase keeps getting deferred.</br>
  *  Different wrappers exist for the convenience of different callers.</dd>
@@ -106,6 +106,12 @@
 
 	/** to conform with javac regarding https://bugs.openjdk.java.net/browse/JDK-8026527 */
 	static final boolean SIMULATE_BUG_JDK_8026527 = true;
+	
+	/** Temporary workaround until we know fully what to do with https://bugs.openjdk.java.net/browse/JDK-8054721 
+	 *  It looks likely that we have a bug independent of this JLS bug in that we clear the capture bounds eagerly.
+	*/
+	static final boolean SHOULD_WORKAROUND_BUG_JDK_8054721 = true; // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=437444#c24 onwards
+	
 	/**
 	 * Detail flag to control the extent of {@link #SIMULATE_BUG_JDK_8026527}.
 	 * A setting of 'false' implements the advice from http://mail.openjdk.java.net/pipermail/lambda-spec-experts/2013-December/000447.html
@@ -148,11 +154,14 @@
 	
 	/** Signals whether any type compatibility makes use of unchecked conversion. */
 	public List<ConstraintFormula> constraintsWithUncheckedConversion;
-
+	public boolean usesUncheckedConversion;
+	public InferenceContext18 outerContext;
 	Scope scope;
 	LookupEnvironment environment;
 	ReferenceBinding object; // java.lang.Object
+	public BoundSet b2;
 	
+	public static final int CHECK_UNKNOWN = 0;
 	public static final int CHECK_STRICT = 1;
 	public static final int CHECK_LOOSE = 2;
 	public static final int CHECK_VARARG = 3;
@@ -162,11 +171,13 @@
 		Expression[] invocationArguments;
 		InferenceVariable[] inferenceVariables;
 		int inferenceKind;
-		SuspendedInferenceRecord(InvocationSite site, Expression[] invocationArguments, InferenceVariable[] inferenceVariables, int inferenceKind) {
+		boolean usesUncheckedConversion;
+		SuspendedInferenceRecord(InvocationSite site, Expression[] invocationArguments, InferenceVariable[] inferenceVariables, int inferenceKind, boolean usesUncheckedConversion) {
 			this.site = site;
 			this.invocationArguments = invocationArguments;
 			this.inferenceVariables = inferenceVariables;
 			this.inferenceKind = inferenceKind;
+			this.usesUncheckedConversion = usesUncheckedConversion;
 		}
 	}
 	
@@ -224,7 +235,6 @@
 
 	/** JLS 18.5.1: compute bounds from formal and actual parameters. */
 	public void createInitialConstraintsForParameters(TypeBinding[] parameters, boolean checkVararg, TypeBinding varArgsType, MethodBinding method) {
-		// TODO discriminate strict vs. loose invocations
 		if (this.invocationArguments == null)
 			return;
 		int len = checkVararg ? parameters.length - 1 : Math.min(parameters.length, this.invocationArguments.length);
@@ -326,17 +336,14 @@
 	}
 
 	/** JLS 18.5.2 Invocation Type Inference 
-	 * @param b1 "the bound set produced by reduction in order to demonstrate that m is applicable in 18.5.1"
 	 */
-	public BoundSet inferInvocationType(BoundSet b1, TypeBinding expectedType, InvocationSite invocationSite, MethodBinding method)
-			throws InferenceFailureException 
+	public BoundSet inferInvocationType(TypeBinding expectedType, InvocationSite invocationSite, MethodBinding method) throws InferenceFailureException 
 	{
 		// not JLS: simply ensure that null hints from the return type have been seen even in standalone contexts:
 		if (expectedType == null && method.returnType != null)
 			substitute(method.returnType); // result is ignore, the only effect is on InferenceVariable.nullHints
-		//
-		BoundSet previous = this.currentBounds.copy();
-		this.currentBounds = b1;
+		
+		this.currentBounds = this.b2.copy();
 		try {
 			// bullets 1&2: definitions only.
 			if (expectedType != null
@@ -392,7 +399,7 @@
 			// 6. bullet: solve
 			BoundSet solution = solve();
 			if (solution == null || !isResolved(solution)) {
-				this.currentBounds = previous; // don't let bounds from unsuccessful attempt leak into subsequent attempts
+				this.currentBounds = this.b2; // don't let bounds from unsuccessful attempt leak into subsequent attempts
 				return null;
 			}
 			// we're done, start reporting:
@@ -433,11 +440,6 @@
 
 	private boolean addConstraintsToC_OneExpr(Expression expri, Set<ConstraintFormula> c, TypeBinding fsi, TypeBinding substF, MethodBinding method, boolean interleaved) throws InferenceFailureException {
 		
-		// See https://bugs.openjdk.java.net/browse/JDK-8052325 for exclusion of poly expressions targeting proper types. CEF.reduce validates 
-		// that they are compatible in a loose invocation context against the target type. They contribute nothing further to solving the formulas.
-		if (substF.isProperType(true))
-			return true;
-		
 		// For all i (1 ≤ i ≤ k), if ei is not pertinent to applicability, the set contains ⟨ei → θ Fi⟩.
 		if (!expri.isPertinentToApplicability(fsi, method)) {
 			c.add(new ConstraintExpressionFormula(expri, substF, ReductionResult.COMPATIBLE, ARGUMENT_CONSTRAINTS_ARE_SOFT));
@@ -466,23 +468,32 @@
 				}
 			}
 		} else if (expri instanceof Invocation && expri.isPolyExpression()) {
+			
+			if (substF.isProperType(true)) // https://bugs.openjdk.java.net/browse/JDK-8052325 
+				return true;
+			
 			Invocation invocation = (Invocation) expri;
 			MethodBinding innerMethod = invocation.binding(substF, this.scope);
 			if (innerMethod == null)
 				return true; 		  // -> proceed with no new C set elements.
 			
+			Expression[] arguments = invocation.arguments();
+			TypeBinding[] argumentTypes = arguments == null ? Binding.NO_PARAMETERS : new TypeBinding[arguments.length];
+			for (int i = 0; i < argumentTypes.length; i++)
+				argumentTypes[i] = arguments[i].resolvedType;
+			int applicabilityKind;
+			InferenceContext18 innerContext = null;
+			if (innerMethod instanceof ParameterizedGenericMethodBinding)
+				 innerContext = invocation.getInferenceContext((ParameterizedGenericMethodBinding) innerMethod);
+			applicabilityKind = innerContext != null ? innerContext.inferenceKind : getInferenceKind(innerMethod, argumentTypes);
+			
 			if (interleaved) {
 				MethodBinding shallowMethod = innerMethod.shallowOriginal();
 				SuspendedInferenceRecord prevInvocation = enterPolyInvocation(invocation, invocation.arguments());
 				try {
-					Expression[] arguments = invocation.arguments();
-					TypeBinding[] argumentTypes = arguments == null ? Binding.NO_PARAMETERS : new TypeBinding[arguments.length];
-					for (int i = 0; i < argumentTypes.length; i++)
-						argumentTypes[i] = arguments[i].resolvedType;
-					if (innerMethod instanceof ParameterizedGenericMethodBinding) {
-						InferenceContext18 innerCtx = invocation.getInferenceContext((ParameterizedGenericMethodBinding) innerMethod);
-						this.inferenceKind = innerCtx.inferenceKind;
-					}
+					this.inferenceKind = applicabilityKind;
+					if (innerContext != null)
+						innerContext.outerContext = this;
 					inferInvocationApplicability(shallowMethod, argumentTypes, shallowMethod.isConstructor());
 					if (!ConstraintExpressionFormula.inferPolyInvocationType(this, invocation, substF, shallowMethod))
 						return false;
@@ -490,13 +501,6 @@
 					resumeSuspendedInference(prevInvocation);
 				}
 			}
-			int applicabilityKind = CHECK_LOOSE;  // FIXME, for <> resolving to a non-generic method, this need to be computed.
-			if (innerMethod instanceof ParameterizedGenericMethodBinding) {
-				InferenceContext18 innerCtx = invocation.getInferenceContext((ParameterizedMethodBinding) innerMethod);
-				if (innerCtx != null) {
-					applicabilityKind = innerCtx.inferenceKind;
-				}
-			}
 			return addConstraintsToC(invocation.arguments(), c, innerMethod.genericMethod(), applicabilityKind, interleaved);
 		} else if (expri instanceof ConditionalExpression) {
 			ConditionalExpression ce = (ConditionalExpression) expri;
@@ -506,6 +510,18 @@
 		return true;
 	}
 
+	
+	protected int getInferenceKind(MethodBinding nonGenericMethod, TypeBinding[] argumentTypes) {
+		switch (this.scope.parameterCompatibilityLevel(nonGenericMethod, argumentTypes)) {
+			case Scope.AUTOBOX_COMPATIBLE:
+				return CHECK_LOOSE;
+			case Scope.VARARGS_COMPATIBLE:
+				return CHECK_VARARG;
+			default:
+				return CHECK_STRICT;
+		}
+	}
+
 	public boolean hasResultFor(TypeBinding targetType) {
 		if (targetType == null)
 			return this.stepCompleted >= TYPE_INFERRED;
@@ -769,15 +785,21 @@
 	 * @return a bound set representing the solution, or null if inference failed
 	 * @throws InferenceFailureException a compile error has been detected during inference
 	 */
-	public /*@Nullable*/ BoundSet solve() throws InferenceFailureException {
+	public /*@Nullable*/ BoundSet solve(boolean inferringApplicability) throws InferenceFailureException {
 		if (!reduce())
 			return null;
 		if (!this.currentBounds.incorporate(this))
 			return null;
+		if (inferringApplicability)
+			this.b2 = this.currentBounds.copy(); // Preserve the result after reduction, without effects of resolve() for later use in invocation type inference.
 
 		return resolve(this.inferenceVariables);
 	}
 	
+	public /*@Nullable*/ BoundSet solve() throws InferenceFailureException {
+		return solve(false);
+	}
+	
 	public /*@Nullable*/ BoundSet solve(InferenceVariable[] toResolve) throws InferenceFailureException {
 		if (!reduce())
 			return null;
@@ -792,11 +814,14 @@
 	 * @throws InferenceFailureException 
 	 */
 	private boolean reduce() throws InferenceFailureException {
-		if (this.initialConstraints != null) {
-			for (int i = 0; i < this.initialConstraints.length; i++) {
-				if (!this.currentBounds.reduceOneConstraint(this, this.initialConstraints[i]))
-					return false;
-			}
+		// Caution: This can be reentered recursively even as an earlier call is munching through the constraints !
+		for (int i = 0; this.initialConstraints != null && i < this.initialConstraints.length; i++) {
+			final ConstraintFormula currentConstraint = this.initialConstraints[i];
+			if (currentConstraint == null)
+				continue;
+			this.initialConstraints[i] = null;
+			if (!this.currentBounds.reduceOneConstraint(this, currentConstraint))
+				return false;
 		}
 		this.initialConstraints = null;
 		return true;
@@ -895,7 +920,7 @@
 											} else if (glbs.length == 1) {
 												glb = glbs[0];
 											} else {
-												IntersectionCastTypeBinding intersection = new IntersectionCastTypeBinding(glbs, this.environment);
+												IntersectionCastTypeBinding intersection = (IntersectionCastTypeBinding) this.environment.createIntersectionCastType(glbs);
 												if (!ReferenceBinding.isConsistentIntersection(intersection.intersectingTypes)) {
 													tmpBoundSet = prevBoundSet; // clean up
 													break variables; // and start over
@@ -917,6 +942,7 @@
 					final CaptureBinding18[] zs = new CaptureBinding18[numVars];
 					for (int j = 0; j < numVars; j++)
 						zs[j] = freshCapture(variables[j]);
+					final BoundSet kurrentBoundSet = tmpBoundSet;
 					Substitution theta = new Substitution() {
 						public LookupEnvironment environment() { 
 							return InferenceContext18.this.environment;
@@ -928,6 +954,16 @@
 							for (int j = 0; j < numVars; j++)
 								if (TypeBinding.equalsEquals(variables[j], typeVariable))
 									return zs[j];
+							/* If we have an instantiation, lower it to the instantiation. We don't want downstream abstractions to be confused about multiple versions of bounds without
+							   and with instantiations propagated by incorporation. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=430686. There is no value whatsoever in continuing
+							   to speak in two tongues. Also fixes https://bugs.eclipse.org/bugs/show_bug.cgi?id=425031.
+							*/
+							if (typeVariable instanceof InferenceVariable) {
+								InferenceVariable inferenceVariable = (InferenceVariable) typeVariable;
+								TypeBinding instantiation = kurrentBoundSet.getInstantiation(inferenceVariable, null);
+								if (instantiation != null)
+									return instantiation;
+							}
 							return typeVariable;
 						}
 //{ObjectTeams:
@@ -942,7 +978,6 @@
 						// add lower bounds:
 						TypeBinding[] lowerBounds = tmpBoundSet.lowerBounds(variable, true/*onlyProper*/);
 						if (lowerBounds != Binding.NO_TYPES) {
-							lowerBounds = Scope.substitute(theta, lowerBounds);
 							TypeBinding lub = this.scope.lowerUpperBound(lowerBounds);
 							if (lub != TypeBinding.VOID && lub != null)
 								zsj.lowerBound = lub;
@@ -1290,19 +1325,20 @@
 	}
 	
 	public SuspendedInferenceRecord enterPolyInvocation(InvocationSite invocation, Expression[] innerArguments) {
-		SuspendedInferenceRecord record = new SuspendedInferenceRecord(this.currentInvocation, this.invocationArguments, this.inferenceVariables, this.inferenceKind);
+		SuspendedInferenceRecord record = new SuspendedInferenceRecord(this.currentInvocation, this.invocationArguments, this.inferenceVariables, this.inferenceKind, this.usesUncheckedConversion);
 		this.inferenceVariables = null;
 		this.invocationArguments = innerArguments;
 		this.currentInvocation = invocation;
-		
+		this.usesUncheckedConversion = false;
 		return record;
 	}
 	
 	public SuspendedInferenceRecord enterLambda(LambdaExpression lambda) {
-		SuspendedInferenceRecord record = new SuspendedInferenceRecord(this.currentInvocation, this.invocationArguments, this.inferenceVariables, this.inferenceKind);
+		SuspendedInferenceRecord record = new SuspendedInferenceRecord(this.currentInvocation, this.invocationArguments, this.inferenceVariables, this.inferenceKind, this.usesUncheckedConversion);
 		this.inferenceVariables = null;
 		this.invocationArguments = null;
 		this.currentInvocation = null;
+		this.usesUncheckedConversion = false;
 		return record;
 	}
 
@@ -1322,6 +1358,7 @@
 		this.currentInvocation = record.site;
 		this.invocationArguments = record.invocationArguments;
 		this.inferenceKind = record.inferenceKind;
+		this.usesUncheckedConversion = record.usesUncheckedConversion;
 	}
 
 	private Substitution getResultSubstitution(final BoundSet result) {
@@ -1459,6 +1496,7 @@
 		if (this.constraintsWithUncheckedConversion == null)
 			this.constraintsWithUncheckedConversion = new ArrayList<ConstraintFormula>();
 		this.constraintsWithUncheckedConversion.add(constraint);
+		this.usesUncheckedConversion = true;
 	}
 	
 	void reportUncheckedConversions(BoundSet solution) {
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 57dc128..d8ad779 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
@@ -190,11 +190,25 @@
 		
 		ParameterizedGenericMethodBinding methodSubstitute = null;
 		TypeVariableBinding[] typeVariables = originalMethod.typeVariables;
-		InferenceContext18 infCtx18 = null;
+		InferenceContext18 infCtx18 = invocationSite.freshInferenceContext(scope);
 		TypeBinding[] parameters = originalMethod.parameters;
-		infCtx18 = invocationSite.freshInferenceContext(scope);
 		CompilerOptions compilerOptions = scope.compilerOptions();
 		boolean invocationTypeInferred = false;
+		boolean requireBoxing = false;
+		
+		// See if we should start in loose inference mode.
+		TypeBinding [] argumentsCopy = new TypeBinding[arguments.length];
+		for (int i = 0, length = arguments.length, parametersLength = parameters.length ; i < length; i++) {
+			TypeBinding parameter = i < parametersLength ? parameters[i] : parameters[parametersLength - 1];
+			final TypeBinding argument = arguments[i];
+			if (argument.isPrimitiveType() != parameter.isPrimitiveType()) { // Scope.cCM incorrectly but harmlessly uses isBaseType which answers true for null.
+				argumentsCopy[i] = scope.environment().computeBoxingType(argument);
+				requireBoxing = true; // can't be strict mode, needs at least loose.
+			} else {
+				argumentsCopy[i] = argument;
+			}
+		}
+		arguments = argumentsCopy; // either way, this allows the engine to update arguments without harming the callers. 
 		
 		try {
 			BoundSet provisionalResult = null;
@@ -203,23 +217,23 @@
 			final boolean isPolyExpression = invocationSite instanceof Expression && ((Expression)invocationSite).isPolyExpression(originalMethod);
 			boolean isDiamond = isPolyExpression && originalMethod.isConstructor();
 			if (arguments.length == parameters.length) {
-				infCtx18.inferenceKind = InferenceContext18.CHECK_LOOSE; // TODO: validate if 2 phase checking (strict/loose + vararg) is sufficient.
+				infCtx18.inferenceKind = requireBoxing ? InferenceContext18.CHECK_LOOSE : InferenceContext18.CHECK_STRICT; // engine may still slip into loose mode and adjust level.
 				infCtx18.inferInvocationApplicability(originalMethod, arguments, isDiamond);
-				result = infCtx18.solve();
+				result = infCtx18.solve(true);
 			}
 			if (result == null && originalMethod.isVarargs()) {
 				// check for variable-arity applicability
 				infCtx18 = invocationSite.freshInferenceContext(scope); // start over
 				infCtx18.inferenceKind = InferenceContext18.CHECK_VARARG;
 				infCtx18.inferInvocationApplicability(originalMethod, arguments, isDiamond);
-				result = infCtx18.solve();
+				result = infCtx18.solve(true);
 			}
 			if (result == null)
 				return null;
 			if (infCtx18.isResolved(result)) {
 				infCtx18.stepCompleted = InferenceContext18.APPLICABILITY_INFERRED;
 				if (invocationSite instanceof ReferenceExpression)
-					((ReferenceExpression) invocationSite).inferenceKind = infCtx18.inferenceKind;   // CHECK
+					((ReferenceExpression) invocationSite).inferenceKind = infCtx18.inferenceKind;
 			} else {
 				return null;
 			}
@@ -229,8 +243,7 @@
 			if (expectedType != null || !invocationSite.getExpressionContext().definesTargetType()) {
 				// ---- 18.5.2 (Invocation type): ----
 				provisionalResult = result;
-				result = infCtx18.currentBounds.copy(); // the result after reduction, without effects of resolve()
-				result = infCtx18.inferInvocationType(result, expectedType, invocationSite, originalMethod);
+				result = infCtx18.inferInvocationType(expectedType, invocationSite, originalMethod);
 				invocationTypeInferred = true;
 				hasReturnProblem |= result == null;
 				if (hasReturnProblem)
@@ -254,7 +267,6 @@
 					if (hasReturnProblem) { // illegally working from the provisional result?
 						MethodBinding problemMethod = infCtx18.getReturnProblemMethodIfNeeded(expectedType, methodSubstitute);
 						if (problemMethod instanceof ProblemMethodBinding) {
-							methodSubstitute = null;
 							return problemMethod;
 						}
 					}
@@ -268,7 +280,6 @@
 						MethodBinding problemMethod = methodSubstitute.boundCheck18(scope, invocationSite, arguments);
 // SH}
 						if (problemMethod != null) {
-							methodSubstitute = null;
 							return problemMethod;
 						}
 						infCtx18.solutionsPerTargetType.put(expectedType, new Solution(methodSubstitute, result));
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 587f586..f3ab7fd 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
@@ -1663,7 +1663,7 @@
 							try {
 								ReferenceBinding[] refs = new ReferenceBinding[glb.length];
 								System.arraycopy(glb, 0, refs, 0, glb.length); // TODO: if an array type plus more types get here, we get ArrayStoreException!
-								types[i] = new IntersectionCastTypeBinding(refs, this.environment);
+								types[i] = this.environment.createIntersectionCastType(refs);
 							} catch (ArrayStoreException ase) {
 								scope.problemReporter().genericInferenceError("Cannot compute glb of "+Arrays.toString(glb), null); //$NON-NLS-1$
 								return null;
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 a97fa32..810a7b6 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
@@ -206,6 +206,11 @@
 		this.arguments = typeArguments;
 	}
 	
+	@Override
+	public ParameterizedTypeBinding capture(Scope scope, int position) {
+		return this;
+	}
+
 	@Override 
 	public TypeBinding uncapture(Scope scope) {
 		return this;
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 76df96a..2e82bf9 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
@@ -785,20 +785,20 @@
 		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=330435, inference should kick in only at source 1.5+
 		if (typeVariables != Binding.NO_TYPE_VARIABLES && compilerOptions.sourceLevel >= ClassFileConstants.JDK1_5) { // generic method
 			TypeBinding[] newArgs = null;
-			for (int i = 0; i < argLength; i++) {
-				TypeBinding param = i < paramLength ? parameters[i] : parameters[paramLength - 1];
-				if (arguments[i].isBaseType() != param.isBaseType()) {
-					if (newArgs == null) {
-						newArgs = new TypeBinding[argLength];
-						System.arraycopy(arguments, 0, newArgs, 0, argLength);
+			if (compilerOptions.sourceLevel < ClassFileConstants.JDK1_8 || genericTypeArguments != null) { // for 1.8+ inferred calls, we do this inside PGMB.cCM18.
+				for (int i = 0; i < argLength; i++) {
+					TypeBinding param = i < paramLength ? parameters[i] : parameters[paramLength - 1];
+					if (arguments[i].isBaseType() != param.isBaseType()) {
+						if (newArgs == null) {
+							newArgs = new TypeBinding[argLength];
+							System.arraycopy(arguments, 0, newArgs, 0, argLength);
+						}
+						newArgs[i] = environment().computeBoxingType(arguments[i]);
 					}
-					newArgs[i] = environment().computeBoxingType(arguments[i]);
 				}
 			}
 			if (newArgs != null)
 				arguments = newArgs;
-			else  // ensure that computeCompatibleMethod() below can update arguments without harming our caller: (TODO: always copy before the loop? only in 1.8?)
-				System.arraycopy(arguments, 0, arguments=new TypeBinding[argLength], 0, argLength);
 			method = ParameterizedGenericMethodBinding.computeCompatibleMethod(method, arguments, this, invocationSite);
 			if (method == null) return null; // incompatible
 			if (!method.isValidBinding()) return method; // bound check issue is taking precedence
@@ -4635,7 +4635,7 @@
 	  try {
 // orig:
 		for (int i = 0; i < visibleSize; i++) {
-			if ((compatibilityLevels[i] = parameterCompatibilityLevel(visible[i], argumentTypes)) != NOT_COMPATIBLE) {
+			if ((compatibilityLevels[i] = parameterCompatibilityLevel(visible[i], argumentTypes, invocationSite)) != NOT_COMPATIBLE) {
 				if (i != compatibleCount) {
 					visible[compatibleCount] = visible[i];
 					compatibilityLevels[compatibleCount] = compatibilityLevels[i];
@@ -4675,7 +4675,6 @@
 				int levelj = compatibilityLevels[j];
 				nextK: for (int k = 0; k < visibleSize; k++) {
 					if (j == k) continue;
-					// TODO do we want to check existing inference contexts whether they can tell us better about the used inferenceKind?
 					int levelk = compatibilityLevels[k];
 					if (levelj > -1 && levelk > -1 && levelj != levelk) {
 						if (levelj < levelk)
@@ -4998,6 +4997,51 @@
 		} while (scope != null);
 		return lastMethodScope; // may answer null if no method around
 	}
+	
+	// Version that just answers based on inference kind (at 1.8+) when available.
+	public int parameterCompatibilityLevel(MethodBinding method, TypeBinding[] arguments, InvocationSite site) {
+		if (compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8 && method instanceof ParameterizedGenericMethodBinding) {
+			int inferenceKind = InferenceContext18.CHECK_UNKNOWN;
+			InferenceContext18 context = null;
+			if (site instanceof Invocation) {
+				Invocation invocation = (Invocation) site;
+				context = invocation.getInferenceContext((ParameterizedGenericMethodBinding) method);
+				if (context != null)
+					inferenceKind = context.inferenceKind;
+			} else if (site instanceof ReferenceExpression) {
+				inferenceKind = ((ReferenceExpression) site).inferenceKind;
+			}
+			/* 1.8+ Post inference compatibility check policy: For non-functional-type arguments, trust inference. For functional type arguments apply compatibility checks as inference
+			   engine may not have checked arguments that are not pertinent to applicability. One complication to deal with is when the generic method's parameter is its own type variable 
+			   and only applicability was inferred and applicability inference instantiated it with jlO due to lack of upper bounds in the bound set.
+			*/
+			if (site instanceof Invocation && context != null) { // this block can be readily seen to be not relevant for reference expressions
+				MethodBinding shallowOriginal = method.shallowOriginal();
+				for (int i = 0, length = arguments.length; i < length; i++) {
+					TypeBinding argument = arguments[i];
+					if (!argument.isFunctionalType())
+						continue;
+					TypeBinding parameter = InferenceContext18.getParameter(method.parameters, i, context.isVarArgs());
+					if (argument.isCompatibleWith(parameter, this))
+						continue;
+					TypeBinding shallowParameter = InferenceContext18.getParameter(shallowOriginal.parameters, i, context.isVarArgs());
+					if (shallowParameter.isPertinentToApplicability(argument, shallowOriginal))
+						return NOT_COMPATIBLE;
+				}
+			}
+			switch (inferenceKind) {
+				case InferenceContext18.CHECK_STRICT:
+					return COMPATIBLE;
+				case InferenceContext18.CHECK_LOOSE:
+					return AUTOBOX_COMPATIBLE;
+				case InferenceContext18.CHECK_VARARG:
+					return VARARGS_COMPATIBLE;
+				default:
+					break;
+				}
+		}
+		return parameterCompatibilityLevel(method, arguments, false);
+	}
 
 	public int parameterCompatibilityLevel(MethodBinding method, TypeBinding[] arguments) {
 		return parameterCompatibilityLevel(method, arguments, false);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticFactoryMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticFactoryMethodBinding.java
index 93849cd..38ee5be 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticFactoryMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticFactoryMethodBinding.java
@@ -29,13 +29,20 @@
 		this.enclosingType = enclosingType;
 	}
 	
-	/** Apply the given type arguments on the (declaring class of the) actual constructor being represented by this factory method. */
-	public ParameterizedMethodBinding applyTypeArgumentsOnConstructor(TypeBinding[] typeArguments) {
+	public MethodBinding getConstructor() {
+		return this.staticFactoryFor;
+	}
+	
+	/** Apply the given type arguments on the (declaring class of the) actual constructor being represented by this factory method and
+	    if method type arguments is not empty materialize the parameterized generic constructor 
+	*/
+	public ParameterizedMethodBinding applyTypeArgumentsOnConstructor(TypeBinding[] typeArguments, TypeBinding[] constructorTypeArguments) {
 		ReferenceBinding parameterizedType = this.environment.createParameterizedType(this.declaringClass, typeArguments,
 																						this.enclosingType);
 		for (MethodBinding parameterizedMethod : parameterizedType.methods()) {
 			if (parameterizedMethod.original() == this.staticFactoryFor)
-				return (ParameterizedMethodBinding) parameterizedMethod;
+				return constructorTypeArguments.length > 0 ? this.environment.createParameterizedGenericMethod(parameterizedMethod, constructorTypeArguments) :
+													         (ParameterizedMethodBinding) parameterizedMethod;
 			if (parameterizedMethod instanceof ProblemMethodBinding) {
 				MethodBinding closestMatch = ((ProblemMethodBinding)parameterizedMethod).closestMatch;
 				if (closestMatch instanceof ParameterizedMethodBinding && closestMatch.original() == this.staticFactoryFor)
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 ad01d14..597e2d6 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
@@ -454,6 +454,16 @@
 					}
 				}
 			}
+			break;
+		case Binding.INTERSECTION_CAST_TYPE:
+			IntersectionCastTypeBinding ictb = (IntersectionCastTypeBinding) this;
+			ReferenceBinding[] intersectingTypes = ictb.getIntersectingTypes();
+			for (int i = 0, length = intersectingTypes.length; i < length; i++) {
+				TypeBinding superType = intersectingTypes[i].findSuperTypeOriginatingFrom(otherType);
+				if (superType != null)
+					return superType;
+			}
+			break;
 	}
 	return null;
 }
@@ -639,6 +649,27 @@
 // version that allows to capture a type bound using 'scope':
 public abstract boolean isCompatibleWith(TypeBinding right, /*@Nullable*/ Scope scope);
 
+/* Answer true if the receiver type can be assigned to the argument type (right) with boxing/unboxing applied.
+ */
+public boolean isBoxingCompatibleWith(TypeBinding right, /*@NonNull */ Scope scope) {
+	
+	if (right == null)
+		return false;
+
+	if (TypeBinding.equalsEquals(this, right))
+		return true;
+	
+	if (this.isCompatibleWith(right, scope))
+		return true;
+	
+	if (this.isBaseType() != right.isBaseType()) {
+		TypeBinding convertedType = scope.environment().computeBoxingType(this);
+		if (TypeBinding.equalsEquals(convertedType, right) || convertedType.isCompatibleWith(right, scope))
+			return true;
+	}
+	return false;
+}
+
 public boolean isEnum() {
 	return false;
 }
@@ -1299,6 +1330,12 @@
 			TypeBinding otherBound = otherWildcard.bound;
 			switch (otherWildcard.boundKind) {
 				case Wildcard.EXTENDS:
+					if (otherBound instanceof IntersectionCastTypeBinding) {
+						TypeBinding [] intersectingTypes = ((IntersectionCastTypeBinding) otherBound).intersectingTypes;
+						for (int i = 0, length = intersectingTypes.length; i < length; i++)
+							if (TypeBinding.equalsEquals(intersectingTypes[i], this))
+								return true;
+					}
 					if (TypeBinding.equalsEquals(otherBound, this))
 						return true; // ? extends T  <=  ? extends ? extends T
 					if (upperBound == null)
@@ -1311,6 +1348,12 @@
 					return upperBound.isCompatibleWith(otherBound);
 
 				case Wildcard.SUPER:
+					if (otherBound instanceof IntersectionCastTypeBinding) {
+						TypeBinding [] intersectingTypes = ((IntersectionCastTypeBinding) otherBound).intersectingTypes;
+						for (int i = 0, length = intersectingTypes.length; i < length; i++)
+							if (TypeBinding.equalsEquals(intersectingTypes[i], this))
+								return true;
+					}
 					if (TypeBinding.equalsEquals(otherBound, this))
 						return true; // ? super T  <=  ? super ? super T
 					if (lowerBound == null)
@@ -1574,6 +1617,11 @@
 	}
 }
 
+// return a name that can be passed to Signature.createTypeSignature
+public char [] signableName() {
+	return readableName();
+}
+
 /**
  * Answer the receiver classfile signature.
  * Arrays & base types do not distinguish between signature() & constantPoolName().
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
index e9641f9..c9611a2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
@@ -65,6 +65,7 @@
     char[] WILDCARD_PLUS = { '+' };
     char[] WILDCARD_CAPTURE_NAME_PREFIX = "capture#".toCharArray(); //$NON-NLS-1$
     char[] WILDCARD_CAPTURE_NAME_SUFFIX = "-of ".toCharArray(); //$NON-NLS-1$
+    char[] WILDCARD_CAPTURE_SIGNABLE_NAME_SUFFIX = "capture-of ".toCharArray(); //$NON-NLS-1$
 	char[] WILDCARD_CAPTURE = { '!' };
 	char[] CAPTURE18 = { '^' };
 	char[] BYTE = "byte".toCharArray(); //$NON-NLS-1$
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 d59dd78..634c53b 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
@@ -134,7 +134,7 @@
 		} catch (ArrayStoreException ase) {
 			return this.bound;
 		}
-		return new IntersectionCastTypeBinding(allBounds, this.environment);
+		return this.environment.createIntersectionCastType(allBounds);
 	}
 
 	public ReferenceBinding actualType() {
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchStatement.java
index f242409..18ba5a6 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchStatement.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchStatement.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2014 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
@@ -20,7 +20,7 @@
  * <pre>
  * SwitchStatement:
  *		<b>switch</b> <b>(</b> Expression <b>)</b>
- * 			<b>{</b> { SwitchCase | Statement } } <b>}</b>
+ * 			<b>{</b> { SwitchCase | Statement } <b>}</b>
  * SwitchCase:
  *		<b>case</b> Expression  <b>:</b>
  *		<b>default</b> <b>:</b>
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java
index 62c4524..ef9f802 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java
@@ -476,7 +476,7 @@
 				local.declarationSourceEnd,
 				local.sourceStart,
 				local.sourceEnd,
-				local.type == null ? Signature.createTypeSignature(binding.type.readableName(), true) : Util.typeSignature(local.type),
+				local.type == null ? Signature.createTypeSignature(binding.type.signableName(), true) : Util.typeSignature(local.type),
 				local.annotations,
 				local.modifiers,
 				local.getKind() == AbstractVariableDeclaration.PARAMETER);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
index ac15327..0c7835e 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
@@ -17,10 +17,12 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.zip.ZipFile;
 
@@ -1045,6 +1047,102 @@
     }
 	return null;
 }
+
+private List<String> getInverseFullName(char[] qualifier, char[] simpleName) {
+	List <String> result = new ArrayList<String>();
+	if (qualifier != null && qualifier.length > 0) {
+		result.addAll(Arrays.asList(new String(qualifier).split("\\.")));//$NON-NLS-1$
+		Collections.reverse(result);
+	}
+	if (simpleName != null) result.add(0, new String(simpleName));
+	return result;
+}
+
+/** returns the row index which has the highest column entry.
+ * TODO: rewrite this code with list when (if) we move to 1.8 [with FP constructs].
+ */
+private int  getMaxResult(int[][] resultsMap) {
+	int rows = resultsMap.length;
+	int cols = resultsMap[0].length;
+	List <Integer> candidates = new ArrayList<Integer>();
+	candidates.add(0); //default row
+
+	for (int j = 0; j < cols; ++j) {
+		int current = resultsMap[0][j];
+		for (int i = 1; i < rows; ++i) {
+			int tmp = resultsMap[i][j];
+			if (tmp < current) continue;
+			if (tmp > current)  { 
+				current = tmp;
+				candidates.clear();
+			}
+			candidates.add(i);// there is atleast one element always.
+		}
+		if (candidates.size() <= 1) break; // found
+	}
+	return candidates.get(0);
+}
+
+/** apply the function to map the parameter full name to an index 
+ */
+private int mapParameter(List <String> patternParameterFullName, List <String> methodParameterFullName) {
+	int patternLen = patternParameterFullName.size();
+	int methodLen = methodParameterFullName.size();
+	int size = patternLen < methodLen ? patternLen : methodLen;
+	int result = -1;
+	for (int i = 0; i < size; i++) {
+		if (!patternParameterFullName.get(i).equals(methodParameterFullName.get(i))) break;
+		++result;
+	}
+	return patternLen == methodLen && result + 1 == patternLen ? Integer.MAX_VALUE : result;
+}
+/**
+ * returns an array of integers whose elements are matching indices.
+ * As a special case, full match would have max value as the index.
+ */
+private int[] getResultMap(Map<Integer, List<String>> patternMap, Map<Integer, List<String>> methodMap) {
+	int paramLength = methodMap.size();
+	int[] result = new int[paramLength];
+	for (int p = 0; p < paramLength; p++) {
+		result[p] = mapParameter(patternMap.get(p), methodMap.get(p));
+	}
+	return result;
+}
+
+private Map<Integer, List<String>> getSplitNames(char[][] qualifiedNames, char[][] simpleNames) {
+	int paramLength = simpleNames.length;
+	Map <Integer, List<String>> result = new HashMap<Integer, List<String>>();
+	for (int p = 0; p < paramLength; p++) result.put(p, getInverseFullName(qualifiedNames[p], simpleNames[p]));
+	return result;
+}
+
+private Map<Integer, List<String>> getSplitNames(MethodBinding method) {
+	TypeBinding[] methodParameters = method.parameters;
+	int paramLength = methodParameters == null ? 0 : methodParameters.length;
+	Map <Integer, List<String>> result = new HashMap<Integer, List<String>>();
+	for (int p = 0; p < paramLength; p++) result.put(p, getInverseFullName(methodParameters[p].qualifiedSourceName(), null)); // source is part of qualifiedSourceName here);
+	return result;
+}
+
+/**
+ * Selects the most applicable method (though similar but not to be confused with its namesake in jls)
+ * All this machinery for that elusive uncommon case referred in bug 431357.
+ */
+private MethodBinding getMostApplicableMethod(List<MethodBinding> possibleMethods) {
+	int size = possibleMethods.size();
+	MethodBinding result = size != 0 ? possibleMethods.get(0) : null;
+	if (size > 1) {
+		MethodPattern methodPattern =  ((MethodPattern) this.pattern);
+		// can cache but may not be worth since this is not a common case
+		Map<Integer, List<String>> methodPatternReverseNames = getSplitNames(methodPattern.parameterQualifications, methodPattern.parameterSimpleNames);
+		int len = possibleMethods.size();
+		int[][] resultMaps = new int[len][];
+		for (int i = 0; i < len; ++i) resultMaps[i] = getResultMap(methodPatternReverseNames, getSplitNames(possibleMethods.get(i)));
+		result = possibleMethods.get(getMaxResult(resultMaps));
+	}
+	return result;
+}
+
 private MethodBinding getMethodBinding0(MethodPattern methodPattern) {
 	if (this.unitScope == null) return null;
 	// Try to get binding from cache
@@ -1061,6 +1159,7 @@
 		typeName = methodPattern.declaringType.getFullyQualifiedName().toCharArray();
 	}
 	TypeBinding declaringTypeBinding = getType(typeName, typeName);
+	MethodBinding result = null;
 	if (declaringTypeBinding != null) {
 		if (declaringTypeBinding.isArrayType()) {
 			declaringTypeBinding = declaringTypeBinding.leafComponentType();
@@ -1074,6 +1173,7 @@
 			int methodsLength = methods.length;
 			TypeVariableBinding[] refTypeVariables = referenceBinding.typeVariables();
 			int typeVarLength = refTypeVariables==null ? 0 : refTypeVariables.length;
+			List <MethodBinding> possibleMethods = new ArrayList<MethodBinding>(methodsLength);
 			for (int i=0; i<methodsLength; i++) {
 				TypeBinding[] methodParameters = methods[i].parameters;
 				int paramLength = methodParameters==null ? 0 : methodParameters.length;
@@ -1111,14 +1211,14 @@
 					}
 				}
 				if (found) {
-					this.bindings.put(methodPattern, methods[i]);
-					return methods[i];
+					possibleMethods.add(methods[i]);
 				}
 			}
+			result =  getMostApplicableMethod(possibleMethods);
 		}
 	}
-	this.bindings.put(methodPattern, new ProblemMethodBinding(methodPattern.selector, null, ProblemReasons.NotFound));
-	return null;
+	this.bindings.put(methodPattern, result != null ? result : new ProblemMethodBinding(methodPattern.selector, null, ProblemReasons.NotFound));
+	return result;
 }
 protected boolean hasAlreadyDefinedType(CompilationUnitDeclaration parsedUnit) {
 	CompilationResult result = parsedUnit.compilationResult;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
index 5830863..5aed30a 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
@@ -217,7 +217,7 @@
 		    && !(messageSend instanceof TSuperMessageSend) // similar to "super" but for codegen it's a "this"
 //jsv}
 			&& !messageSend.isSuperAccess()
-			&& !(method.isDefault() && this.pattern.focus != null
+			&& !(method.isDefault() && this.pattern.focus != null 
 			&& !CharOperation.equals(this.pattern.declaringPackageName, method.declaringClass.qualifiedPackageName()));
 }
 public int match(ASTNode node, MatchingNodeSet nodeSet) {
@@ -437,6 +437,8 @@
 			return INACCURATE_MATCH;
 		}
 		boolean foundTypeVariable = false;
+		MethodBinding focusMethodBinding = null;
+		boolean checkedFocus = false;
 		// verify each parameter
 		for (int i = 0; i < parameterCount; i++) {
 //{ObjectTeams: callin method?
@@ -446,11 +448,19 @@
 			TypeBinding argType = methodParamters[i];
 // SH}
 			int newLevel = IMPOSSIBLE_MATCH;
-			if (argType.isMemberType()) {
-				// only compare source name for member type (bug 41018)
-				newLevel = CharOperation.match(this.pattern.parameterSimpleNames[i], argType.sourceName(), this.isCaseSensitive)
-					? ACCURATE_MATCH
-					: IMPOSSIBLE_MATCH;
+			boolean foundLevel = false;
+			if (argType.isMemberType() || this.pattern.parameterQualifications[i] != null) {
+				if (!checkedFocus) {
+					focusMethodBinding = this.matchLocator.getMethodBinding(this.pattern);
+					checkedFocus = true;
+				}
+				if (focusMethodBinding != null) {// textual comparison insufficient
+					TypeBinding[] parameters = focusMethodBinding.parameters;
+					if (parameters.length >= parameterCount) {
+						newLevel = argType.isEquivalentTo((parameters[i])) ? ACCURATE_MATCH : IMPOSSIBLE_MATCH;
+						foundLevel = true;
+					}
+				}
 			} else {
 				// TODO (frederic) use this call to refine accuracy on parameter types
 //				 newLevel = resolveLevelForType(this.pattern.parameterSimpleNames[i], this.pattern.parameterQualifications[i], this.pattern.parametersTypeArguments[i], 0, argType);
@@ -461,7 +471,9 @@
 					if (skipImpossibleArg) {
 						// Do not consider match as impossible while finding declarations and source level >= 1.5
 					 	// (see  bugs https://bugs.eclipse.org/bugs/show_bug.cgi?id=79990, 96761, 96763)
-						newLevel = level;
+						if (!foundLevel) {
+							newLevel = level;
+						}
 					} else if (argType.isTypeVariable()) {
 						newLevel = level;
 						foundTypeVariable = true;
@@ -475,7 +487,8 @@
 		if (foundTypeVariable) {
 			if (!method.isStatic() && !method.isPrivate()) {
 				// https://bugs.eclipse.org/bugs/show_bug.cgi?id=123836, No point in textually comparing type variables, captures etc with concrete types. 
-				MethodBinding focusMethodBinding = this.matchLocator.getMethodBinding(this.pattern);
+				if (!checkedFocus)
+					focusMethodBinding = this.matchLocator.getMethodBinding(this.pattern);
 				if (focusMethodBinding != null) {
 					if (matchOverriddenMethod(focusMethodBinding.declaringClass, focusMethodBinding, method)) {
 						return ACCURATE_MATCH;
@@ -982,7 +995,7 @@
 	} else {
 //{ObjectTeams: try harder to use a declaring qualification to lock down to this exact role:
 /* orig:
-		declaringLevel = resolveLevelForType(this.pattern.declaringSimpleName, this.pattern.declaringQualification, method.declaringClass); 
+		declaringLevel = resolveLevelForType(this.pattern.declaringSimpleName, this.pattern.declaringQualification, method.declaringClass);
   :giro */
 		char[] patternDeclaringQualification = this.pattern.getDeclaringQualification();
 		ReferenceBinding declaringClass = method.declaringClass;