Fixed Bug 521818: [compiler] LambdaConversionException when using a
method reference for a generic SAM with intersection types as argument

Change-Id: I45bf1a6fda91be27a06d6a10d4b7126d22146dfd
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java
index a3b21b8..9f5def5 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java
@@ -6597,6 +6597,50 @@
 		}
 	);
 }
+public void testBug521818() {
+	runConformTest(
+		new String[] {
+			"test/Main.java",
+			"package test;\n" + 
+			"class C {}\n" + 
+			"class D {\n" + 
+			"	<T extends C & Runnable> D(int i, T t) {" +
+			"		System.out.println(\"D\");\n" +
+			"}\n" + 
+			"}\n" + 
+			"interface Goo {\n" + 
+			"    <T extends C & Runnable> String m(T p);\n" + 
+			"}\n" + 
+			"class A {\n" + 
+			"    public static <K extends Runnable> String bar(K a) {\n" +
+			"		System.out.println(\"Bar\");\n" +
+			"       return null;\n" + 
+			"    }\n" + 
+			"    public static <K extends Runnable> D baz(int i, K a) {\n" +
+			"		System.out.println(\"Baz\");\n" +
+			"       return null;\n" + 
+			"    }\n"+ 
+			"}\n" +  
+			"interface Foo<Z extends C & Runnable> {\n" + 
+			"	D get(int i, Z z);\n" + 
+			"}\n" + 
+			"public class Main  {\n" +  
+			"    public static void main(String[] args) {\n" + 
+			"    	Foo<? extends C> h = A::baz;\n" + 
+			"    	h.get(0,  null);\n" + 
+			"    	Foo<? extends C> h2 = D::new;\n" + 
+			"    	h2.get(0,  null);\n" + 
+			"    	Goo g = A::bar;\n" + 
+			"    	g.m(null);\n" + 
+			"    } \n" + 
+			"}"
+		},
+		"Baz\n" +
+		"D\n" +
+		"Bar"
+		
+	);
+}
 public static Class testClass() {
 	return LambdaExpressionsTest.class;
 }
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 063ed9b..dec5751 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
@@ -88,6 +88,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
 import org.eclipse.jdt.internal.compiler.parser.Parser;
 import org.eclipse.jdt.internal.compiler.parser.Scanner;
 
@@ -271,10 +272,38 @@
 		// these cases are either too complicated, impossible to handle or result in significant code duplication 
 		return (this.binding.isVarargs() || 
 				(isConstructorReference() && this.receiverType.syntheticOuterLocalVariables() != null && this.shouldCaptureInstance) ||
-				this.requiresBridges()); // bridges.
+				this.requiresBridges() || // bridges.
+				!isDirectCodeGenPossible());
 		// To fix: We should opt for direct code generation wherever possible.
 	}
-	
+	private boolean isDirectCodeGenPossible() {
+		if (this.binding != null) {
+			if (isMethodReference() && this.syntheticAccessor == null) {
+				if (TypeBinding.notEquals(this.binding.declaringClass, this.lhs.resolvedType.erasure())) {
+					// reference to a method declared by an inaccessible type accessed via a
+					// subtype - normally a bridge method would be present to facilitate
+					// this access, unless the method is final, in which case, direct access to
+					// the method is not possible, an implicit lambda is needed
+					if (!this.binding.declaringClass.canBeSeenBy(this.enclosingScope)) {
+						return !this.binding.isFinal();
+					}
+				}
+			}
+			TypeBinding[] descriptorParams = this.descriptor.parameters;
+			TypeBinding[] origParams = this.binding.original().parameters;
+			TypeBinding[] origDescParams = this.descriptor.original().parameters;
+			int offset = this.receiverPrecedesParameters ? 1 : 0;
+			for (int i = 0; i < descriptorParams.length - offset; i++) {
+				TypeBinding descType = descriptorParams[i + offset];
+				TypeBinding origDescType = origDescParams[i + offset];
+				if (descType.isIntersectionType18() || 
+						(descType.isTypeVariable() && ((TypeVariableBinding) descType).otherUpperBounds() != null)) {
+					return CharOperation.equals(origDescType.signature(), origParams[i].signature());
+				}
+			}
+		}
+		return true;
+	}
 	public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
 		this.actualMethodBinding = this.binding; // grab before synthetics come into play.
 		// Handle some special cases up front and transform them into implicit lambdas.