Fixed bug 449063: [1.8][compiler] Bring back generic signatures for
Lambda Expressions

Change-Id: I6dd177468fdd6d147be7b02897bdaecc0dab1035
diff --git a/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/CompilerToolTests.java b/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/CompilerToolTests.java
index 7cef2f0..67e7d8b 100644
--- a/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/CompilerToolTests.java
+++ b/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/CompilerToolTests.java
@@ -141,6 +141,7 @@
 		"-proc:none",
 		"-proc:only",
 		"-parameters",
+		"-genericsignature"
 	};
 static final String[] FAKE_ZERO_ARG_OPTIONS = new String[] { 
 	// a series of fake options to test the behavior upon ignored and 
diff --git a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/Options.java b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/Options.java
index a581509..4b2f1ff 100644
--- a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/Options.java
+++ b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/Options.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2013 IBM Corporation and others.
+ * Copyright (c) 2006, 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
@@ -65,6 +65,7 @@
 		Options.ZERO_ARGUMENT_OPTIONS.add("-XprintProcessorInfo");//$NON-NLS-1$
 		Options.ZERO_ARGUMENT_OPTIONS.add("-XprintRounds");//$NON-NLS-1$
 		Options.ZERO_ARGUMENT_OPTIONS.add("-parameters");//$NON-NLS-1$
+		Options.ZERO_ARGUMENT_OPTIONS.add("-genericsignature");//$NON-NLS-1$
 
 		FILE_MANAGER_OPTIONS = new HashSet<String>();
 		Options.FILE_MANAGER_OPTIONS.add("-bootclasspath");//$NON-NLS-1$
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
index adbacef..db547cf 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
@@ -1653,6 +1653,7 @@
         "    -inlineJSR         inline JSR bytecode (implicit if target >= 1.5)\n" +
         "    -enableJavadoc     consider references in javadoc\n" +
         "    -parameters        generate method parameters attribute (for target >= 1.8)\n" +
+        "    -genericsignature  generate generic signature for lambda expressions\n" +
         "    -Xemacs            used to enable emacs-style output in the console.\n" +
         "                       It does not affect the xml log output\n" +
         "    -missingNullDefault  report missing default nullness annotation\n" + 
@@ -1897,6 +1898,7 @@
 			"		<option key=\"org.eclipse.jdt.core.compiler.annotation.nullable\" value=\"org.eclipse.jdt.annotation.Nullable\"/>\n" + 
 			"		<option key=\"org.eclipse.jdt.core.compiler.annotation.nullanalysis\" value=\"disabled\"/>\n" + 
 			"		<option key=\"org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode\" value=\"disabled\"/>\n" + 
+			"		<option key=\"org.eclipse.jdt.core.compiler.codegen.lambda.genericSignature\" value=\"do not generate\"/>\n" +
 			"		<option key=\"org.eclipse.jdt.core.compiler.codegen.methodParameters\" value=\"do not generate\"/>\n" + 
 			"		<option key=\"org.eclipse.jdt.core.compiler.codegen.shareCommonFinallyBlocks\" value=\"disabled\"/>\n" +
 			"		<option key=\"org.eclipse.jdt.core.compiler.codegen.targetPlatform\" value=\"1.5\"/>\n" + 
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 b1b42e3..a798ab7 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
@@ -4859,6 +4859,358 @@
 		},
 		"");
 }
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=449063, [1.8][compiler] Bring back generic signatures for Lambda Expressions 
+public void test449063() {
+	Map customOptions = getCompilerOptions();
+	customOptions.put(CompilerOptions.OPTION_LambdaGenericSignature, CompilerOptions.GENERATE);
+	this.runConformTest(
+		new String[] {
+			"Test.java",
+			"import java.io.Serializable;\n" + 
+			"import java.lang.invoke.SerializedLambda;\n" + 
+			"import java.lang.reflect.Method;\n" + 
+			"import java.lang.reflect.Type;\n" + 
+			"public class Test {\n" + 
+			"    public static interface Map<IN, OUT> {\n" + 
+			"        public OUT map(IN in);\n" + 
+			"    }\n" + 
+			"    public static class Tuple<T1, T2> {\n" + 
+			"        private T1 field1;\n" + 
+			"        private T2 field2;\n" + 
+			"    }\n" + 
+			"    public static void main(String[] strings) throws Exception {\n" + 
+			"        Map<Tuple<String, Double>, Tuple<Integer, String>> map = (in) -> new Tuple<>();\n" + 
+			"        for(Method m : Test.class.getDeclaredMethods()) {\n" + 
+			"        // Use the type information stored in signature\n" + 
+			"            if (m.getName().contains(\"lambda\")) {\n" +
+			"              System.out.println(m.getGenericReturnType());\n" + 
+			"              for (Type t : m.getGenericParameterTypes()) {\n" + 
+			"                  System.out.println(t);\n" + 
+			"              }\n" +
+			"            }\n" +
+			"        }\n" +
+			"    }\n" + 
+			"}"
+			},
+			"Test.Test$Tuple<java.lang.Integer, java.lang.String>\n" +
+			"Test.Test$Tuple<java.lang.String, java.lang.Double>",
+			customOptions);
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=449063, [1.8][compiler] Bring back generic signatures for Lambda Expressions 
+public void test449063a() {
+	Map customOptions = getCompilerOptions();
+	customOptions.put(CompilerOptions.OPTION_LambdaGenericSignature, CompilerOptions.GENERATE);
+	this.runConformTest(
+		new String[] {
+			"Test.java",
+			"import java.io.Serializable;\n" + 
+			"import java.lang.invoke.SerializedLambda;\n" + 
+			"import java.lang.reflect.Method;\n" + 
+			"import java.lang.reflect.Type;\n" + 
+			"public class Test {\n" + 
+			"    public static interface Map<IN, OUT> extends Serializable {\n" + 
+			"        public OUT map(IN in);\n" + 
+			"    }\n" + 
+			"    public static class Tuple<T1, T2> {\n" + 
+			"        private T1 field1;\n" + 
+			"        private T2 field2;\n" + 
+			"    }\n" + 
+			"    public static void main(String[] strings) throws Exception {\n" + 
+			"        Map<Tuple<String, Double>, Tuple<Integer, String>> map = (in) -> new Tuple<>();\n" + 
+			"        SerializedLambda sl = getSerializedLambda(map);      \n" + 
+			"        Method m = getLambdaMethod(sl);\n" + 
+			"        // Use the type information stored in signature\n" + 
+			"        System.out.println(m.getGenericReturnType());\n" + 
+			"        for (Type t : m.getGenericParameterTypes()) {\n" + 
+			"            System.out.println(t);\n" + 
+			"        }\n" + 
+			"    }\n" + 
+			"    public static Method getLambdaMethod(SerializedLambda lambda) throws Exception {\n" + 
+			"        String implClassName = lambda.getImplClass().replace(\'/\', \'.\');\n" + 
+			"        Class<?> implClass = Class.forName(implClassName);\n" + 
+			"        String lambdaName = lambda.getImplMethodName();\n" + 
+			"        for (Method m : implClass.getDeclaredMethods()) {\n" + 
+			"            if (m.getName().equals(lambdaName)) {\n" + 
+			"                return m;\n" + 
+			"            }\n" + 
+			"        }\n" + 
+			"        throw new Exception(\"Lambda Method not found\");\n" + 
+			"    }\n" + 
+			"    public static SerializedLambda getSerializedLambda(Object function) throws Exception {\n" + 
+			"        if (function == null || !(function instanceof java.io.Serializable)) {\n" + 
+			"            throw new IllegalArgumentException();\n" + 
+			"        }\n" + 
+			"        for (Class<?> clazz = function.getClass(); clazz != null; clazz = clazz.getSuperclass()) {\n" + 
+			"            try {\n" + 
+			"                Method replaceMethod = clazz.getDeclaredMethod(\"writeReplace\");\n" + 
+			"                replaceMethod.setAccessible(true);\n" + 
+			"                Object serializedForm = replaceMethod.invoke(function);\n" + 
+			"                if (serializedForm instanceof SerializedLambda) {\n" + 
+			"                    return (SerializedLambda) serializedForm;\n" + 
+			"                }\n" + 
+			"            }\n" + 
+			"            catch (NoSuchMethodError e) {\n" + 
+			"                // fall through the loop and try the next class\n" + 
+			"            }\n" + 
+			"            catch (Throwable t) {\n" + 
+			"                throw new RuntimeException(\"Error while extracting serialized lambda\", t);\n" + 
+			"            }\n" + 
+			"        }\n" + 
+			"        throw new Exception(\"writeReplace method not found\");\n" + 
+			"    }\n" + 
+			"}"
+			},
+			"Test.Test$Tuple<java.lang.Integer, java.lang.String>\n" +
+			"Test.Test$Tuple<java.lang.String, java.lang.Double>",
+			customOptions);
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=449063, [1.8][compiler] Bring back generic signatures for Lambda Expressions 
+public void test449063b() {
+	Map customOptions = getCompilerOptions();
+	customOptions.put(CompilerOptions.OPTION_LambdaGenericSignature, CompilerOptions.DO_NOT_GENERATE);
+	this.runConformTest(
+		new String[] {
+			"Test.java",
+			"import java.io.Serializable;\n" + 
+			"import java.lang.invoke.SerializedLambda;\n" + 
+			"import java.lang.reflect.Method;\n" + 
+			"import java.lang.reflect.Type;\n" + 
+			"public class Test {\n" + 
+			"    public static interface Map<IN, OUT> {\n" + 
+			"        public OUT map(IN in);\n" + 
+			"    }\n" + 
+			"    public static class Tuple<T1, T2> {\n" + 
+			"        private T1 field1;\n" + 
+			"        private T2 field2;\n" + 
+			"    }\n" + 
+			"    public static void main(String[] strings) throws Exception {\n" + 
+			"        Map<Tuple<String, Double>, Tuple<Integer, String>> map = (in) -> new Tuple<>();\n" + 
+			"        for(Method m : Test.class.getDeclaredMethods()) {\n" + 
+			"        // Use the type information stored in signature\n" + 
+			"            if (m.getName().contains(\"lambda\")) {\n" +
+			"              System.out.println(m.getGenericReturnType());\n" + 
+			"              for (Type t : m.getGenericParameterTypes()) {\n" + 
+			"                  System.out.println(t);\n" + 
+			"              }\n" +
+			"            }\n" +
+			"        }\n" +
+			"    }\n" + 
+			"}"
+			},
+			"class Test$Tuple\n" +
+			"class Test$Tuple",
+			customOptions);
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=449063, [1.8][compiler] Bring back generic signatures for Lambda Expressions 
+public void test449063c() {
+	Map customOptions = getCompilerOptions();
+	customOptions.put(CompilerOptions.OPTION_LambdaGenericSignature, CompilerOptions.DO_NOT_GENERATE);
+	this.runConformTest(
+		new String[] {
+			"Test.java",
+			"import java.io.Serializable;\n" + 
+			"import java.lang.invoke.SerializedLambda;\n" + 
+			"import java.lang.reflect.Method;\n" + 
+			"import java.lang.reflect.Type;\n" + 
+			"public class Test {\n" + 
+			"    public static interface Map<IN, OUT> extends Serializable {\n" + 
+			"        public OUT map(IN in);\n" + 
+			"    }\n" + 
+			"    public static class Tuple<T1, T2> {\n" + 
+			"        private T1 field1;\n" + 
+			"        private T2 field2;\n" + 
+			"    }\n" + 
+			"    public static void main(String[] strings) throws Exception {\n" + 
+			"        Map<Tuple<String, Double>, Tuple<Integer, String>> map = (in) -> new Tuple<>();\n" + 
+			"        SerializedLambda sl = getSerializedLambda(map);      \n" + 
+			"        Method m = getLambdaMethod(sl);\n" + 
+			"        // Use the type information stored in signature\n" + 
+			"        System.out.println(m.getGenericReturnType());\n" + 
+			"        for (Type t : m.getGenericParameterTypes()) {\n" + 
+			"            System.out.println(t);\n" + 
+			"        }\n" + 
+			"    }\n" + 
+			"    public static Method getLambdaMethod(SerializedLambda lambda) throws Exception {\n" + 
+			"        String implClassName = lambda.getImplClass().replace(\'/\', \'.\');\n" + 
+			"        Class<?> implClass = Class.forName(implClassName);\n" + 
+			"        String lambdaName = lambda.getImplMethodName();\n" + 
+			"        for (Method m : implClass.getDeclaredMethods()) {\n" + 
+			"            if (m.getName().equals(lambdaName)) {\n" + 
+			"                return m;\n" + 
+			"            }\n" + 
+			"        }\n" + 
+			"        throw new Exception(\"Lambda Method not found\");\n" + 
+			"    }\n" + 
+			"    public static SerializedLambda getSerializedLambda(Object function) throws Exception {\n" + 
+			"        if (function == null || !(function instanceof java.io.Serializable)) {\n" + 
+			"            throw new IllegalArgumentException();\n" + 
+			"        }\n" + 
+			"        for (Class<?> clazz = function.getClass(); clazz != null; clazz = clazz.getSuperclass()) {\n" + 
+			"            try {\n" + 
+			"                Method replaceMethod = clazz.getDeclaredMethod(\"writeReplace\");\n" + 
+			"                replaceMethod.setAccessible(true);\n" + 
+			"                Object serializedForm = replaceMethod.invoke(function);\n" + 
+			"                if (serializedForm instanceof SerializedLambda) {\n" + 
+			"                    return (SerializedLambda) serializedForm;\n" + 
+			"                }\n" + 
+			"            }\n" + 
+			"            catch (NoSuchMethodError e) {\n" + 
+			"                // fall through the loop and try the next class\n" + 
+			"            }\n" + 
+			"            catch (Throwable t) {\n" + 
+			"                throw new RuntimeException(\"Error while extracting serialized lambda\", t);\n" + 
+			"            }\n" + 
+			"        }\n" + 
+			"        throw new Exception(\"writeReplace method not found\");\n" + 
+			"    }\n" + 
+			"}"
+			},
+			"class Test$Tuple\n" +
+			"class Test$Tuple",
+			customOptions);
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=449063, [1.8][compiler] Bring back generic signatures for Lambda Expressions 
+public void test449063d() {
+	Map customOptions = getCompilerOptions();
+	customOptions.put(CompilerOptions.OPTION_LambdaGenericSignature, CompilerOptions.GENERATE);
+	this.runConformTest(
+		new String[] {
+			"Test.java",
+			"import java.io.Serializable;\n" + 
+			"import java.lang.invoke.SerializedLambda;\n" + 
+			"import java.lang.reflect.Method;\n" + 
+			"import java.lang.reflect.Type;\n" + 
+			"public class Test {\n" + 
+			"    public static interface Map<IN, OUT> {\n" + 
+			"        public OUT map(IN in);\n" + 
+			"    }\n" + 
+			"    public static Tuple<Integer, String> noop(Tuple<String, Double> t){return null;}\n" +
+			"    public static class Tuple<T1, T2> {\n" + 
+			"        private T1 field1;\n" + 
+			"        private T2 field2;\n" + 
+			"    }\n" + 
+			"    public static void main(String[] strings) throws Exception {\n" + 
+			"        Map<Tuple<String, Double>, Tuple<Integer, String>> map = Test::noop;\n" + 
+			"        for(Method m : Test.class.getDeclaredMethods()) {\n" + 
+			"        // Use the type information stored in signature\n" + 
+			"            if (m.getName().contains(\"lambda\")) {\n" +
+			"              System.out.println(m.getGenericReturnType());\n" + 
+			"              for (Type t : m.getGenericParameterTypes()) {\n" + 
+			"                  System.out.println(t);\n" + 
+			"              }\n" +
+			"            }\n" +
+			"        }\n" +
+			"    }\n" + 
+			"}"
+			},
+			"",
+			customOptions);
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=449063, [1.8][compiler] Bring back generic signatures for Lambda Expressions 
+public void test449063e() {
+	Map customOptions = getCompilerOptions();
+	customOptions.put(CompilerOptions.OPTION_LambdaGenericSignature, CompilerOptions.DO_NOT_GENERATE);
+	this.runConformTest(
+		new String[] {
+			"Test.java",
+			"import java.io.Serializable;\n" + 
+			"import java.lang.invoke.SerializedLambda;\n" + 
+			"import java.lang.reflect.Method;\n" + 
+			"import java.lang.reflect.Type;\n" + 
+			"public class Test {\n" + 
+			"    public static interface Map<IN, OUT> extends Serializable {\n" + 
+			"        public OUT map(IN in);\n" + 
+			"    }\n" + 
+			"    public static Tuple<Integer, String> noop(Tuple<String, Double> t){return null;}\n" +
+			"    public static class Tuple<T1, T2> {\n" + 
+			"        private T1 field1;\n" + 
+			"        private T2 field2;\n" + 
+			"    }\n" + 
+			"    public static void main(String[] strings) throws Exception {\n" + 
+			"        Map<Tuple<String, Double>, Tuple<Integer, String>> map = Test::noop;\n" + 
+			"        SerializedLambda sl = getSerializedLambda(map);      \n" + 
+			"        Method m = getLambdaMethod(sl);\n" + 
+			"        // Use the type information stored in signature\n" + 
+			"        System.out.println(m.getGenericReturnType());\n" + 
+			"        for (Type t : m.getGenericParameterTypes()) {\n" + 
+			"            System.out.println(t);\n" + 
+			"        }\n" + 
+			"    }\n" + 
+			"    public static Method getLambdaMethod(SerializedLambda lambda) throws Exception {\n" + 
+			"        String implClassName = lambda.getImplClass().replace(\'/\', \'.\');\n" + 
+			"        Class<?> implClass = Class.forName(implClassName);\n" + 
+			"        String lambdaName = lambda.getImplMethodName();\n" + 
+			"        for (Method m : implClass.getDeclaredMethods()) {\n" + 
+			"            if (m.getName().equals(lambdaName)) {\n" + 
+			"                return m;\n" + 
+			"            }\n" + 
+			"        }\n" + 
+			"        throw new Exception(\"Lambda Method not found\");\n" + 
+			"    }\n" + 
+			"    public static SerializedLambda getSerializedLambda(Object function) throws Exception {\n" + 
+			"        if (function == null || !(function instanceof java.io.Serializable)) {\n" + 
+			"            throw new IllegalArgumentException();\n" + 
+			"        }\n" + 
+			"        for (Class<?> clazz = function.getClass(); clazz != null; clazz = clazz.getSuperclass()) {\n" + 
+			"            try {\n" + 
+			"                Method replaceMethod = clazz.getDeclaredMethod(\"writeReplace\");\n" + 
+			"                replaceMethod.setAccessible(true);\n" + 
+			"                Object serializedForm = replaceMethod.invoke(function);\n" + 
+			"                if (serializedForm instanceof SerializedLambda) {\n" + 
+			"                    return (SerializedLambda) serializedForm;\n" + 
+			"                }\n" + 
+			"            }\n" + 
+			"            catch (NoSuchMethodError e) {\n" + 
+			"                // fall through the loop and try the next class\n" + 
+			"            }\n" + 
+			"            catch (Throwable t) {\n" + 
+			"                throw new RuntimeException(\"Error while extracting serialized lambda\", t);\n" + 
+			"            }\n" + 
+			"        }\n" + 
+			"        throw new Exception(\"writeReplace method not found\");\n" + 
+			"    }\n" + 
+			"}"
+			},
+			"Test.Test$Tuple<java.lang.Integer, java.lang.String>\n" +
+			"Test.Test$Tuple<java.lang.String, java.lang.Double>",
+			customOptions);
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=449063, [1.8][compiler] Bring back generic signatures for Lambda Expressions 
+public void test449063f() {
+	Map customOptions = getCompilerOptions();
+	customOptions.put(CompilerOptions.OPTION_LambdaGenericSignature, CompilerOptions.GENERATE);
+	this.runConformTest(
+		new String[] {
+			"Test.java",
+			"import java.io.Serializable;\n" + 
+			"import java.lang.reflect.Method;\n" + 
+			"import java.lang.reflect.Type;\n" + 
+			"public class Test implements Serializable{\n" + 
+			"    public static interface Map<IN, OUT> {\n" + 
+			"        public OUT map(IN in);\n" + 
+			"    }\n" + 
+			"    public static Tuple<Integer, String> noop(Tuple<String, Double> t){return null;}\n" +
+			"    public static class Tuple<T1, T2> {\n" + 
+			"        private T1 field1;\n" + 
+			"        private T2 field2;\n" + 
+			"    }\n" + 
+			"    public static void main(String[] strings) throws Exception {\n" + 
+			"        Map<Tuple<String, Double>, Tuple<Integer, String>> map = Test::noop;\n" + 
+			"        for(Method m : Test.class.getDeclaredMethods()) {\n" + 
+			"        // Use the type information stored in signature\n" + 
+			"            if (m.getName().contains(\"lambda\")) {\n" +
+			"              System.out.println(m.getGenericReturnType());\n" + 
+			"              for (Type t : m.getGenericParameterTypes()) {\n" + 
+			"                  System.out.println(t);\n" + 
+			"              }\n" +
+			"            }\n" +
+			"        }\n" +
+			"    }\n" + 
+			"}"
+			},
+			"",
+			customOptions);
+}
 public static Class testClass() {
 	return LambdaExpressionsTest.class;
 }
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
index 805d94c..b32075b 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
@@ -2200,6 +2200,13 @@
 							CompilerOptions.GENERATE);
 					continue;
 				}
+				if (currentArg.equals("-genericsignature")) { //$NON-NLS-1$
+					mode = DEFAULT;
+					this.options.put(
+							CompilerOptions.OPTION_LambdaGenericSignature,
+							CompilerOptions.GENERATE);
+					continue;
+				}
 				if (currentArg.startsWith("-g")) { //$NON-NLS-1$
 					mode = DEFAULT;
 					String debugOption = currentArg;
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
index 72975fd..d43f471 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
@@ -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
@@ -259,6 +259,7 @@
 \    -inlineJSR         inline JSR bytecode (implicit if target >= 1.5)\n\
 \    -enableJavadoc     consider references in javadoc\n\
 \    -parameters        generate method parameters attribute (for target >= 1.8)\n\
+\    -genericsignature  generate generic signature for lambda expressions\n\
 \    -Xemacs            used to enable emacs-style output in the console.\n\
 \                       It does not affect the xml log output\n\
 \    -missingNullDefault  report missing default nullness annotation\n\
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java
index c29cf58..3a94b20 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2014 IBM Corporation and others.
+ * Copyright (c) 2012, 2015 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
@@ -330,6 +330,7 @@
 				// TODO: in which cases do we have to assign this.resolvedType & this.descriptor (with problem bindings) to prevent NPE downstream??
 			}
 		}
+		boolean genericSignatureNeeded = this.requiresGenericSignature || blockScope.compilerOptions().generateGenericSignatureForLambdaExpressions;
 		for (int i = 0; i < length; i++) {
 			Argument argument = this.arguments[i];
 			TypeBinding parameterType;
@@ -382,7 +383,7 @@
 			if ((exception.tagBits & TagBits.HasMissingType) != 0) {
 				this.binding.tagBits |= TagBits.HasMissingType;
 			}
-			if (this.requiresGenericSignature)
+			if (genericSignatureNeeded)
 				this.binding.modifiers |= (exception.modifiers & ExtraCompilerModifiers.AccGenericSignature);
 		}
 		
@@ -391,7 +392,7 @@
 			if ((returnType.tagBits & TagBits.HasMissingType) != 0) {
 				this.binding.tagBits |= TagBits.HasMissingType;
 			}
-			if (this.requiresGenericSignature) {
+			if (genericSignatureNeeded) {
 				TypeBinding leafType = returnType.leafComponentType();
 				if (leafType instanceof ReferenceBinding && (((ReferenceBinding) leafType).modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0)
 					this.binding.modifiers |= ExtraCompilerModifiers.AccGenericSignature;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
index 596b01d..2b42f66 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
@@ -50,6 +50,7 @@
 	public static final String OPTION_SourceFileAttribute = "org.eclipse.jdt.core.compiler.debug.sourceFile"; //$NON-NLS-1$
 	public static final String OPTION_PreserveUnusedLocal = "org.eclipse.jdt.core.compiler.codegen.unusedLocal"; //$NON-NLS-1$
 	public static final String OPTION_MethodParametersAttribute = "org.eclipse.jdt.core.compiler.codegen.methodParameters"; //$NON-NLS-1$
+	public static final String OPTION_LambdaGenericSignature = "org.eclipse.jdt.core.compiler.codegen.lambda.genericSignature"; //$NON-NLS-1$
 	public static final String OPTION_DocCommentSupport= "org.eclipse.jdt.core.compiler.doc.comment.support"; //$NON-NLS-1$
 	public static final String OPTION_ReportMethodWithConstructorName = "org.eclipse.jdt.core.compiler.problem.methodWithConstructorName"; //$NON-NLS-1$
 	public static final String OPTION_ReportOverridingPackageDefaultMethod = "org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod"; //$NON-NLS-1$
@@ -314,7 +315,9 @@
 	/** Classfile debug information, may contain source file name, line numbers, local variable tables, etc... */
 	public int produceDebugAttributes; 
 	/** Classfile method patameters information as per JEP 118... */
-	public boolean produceMethodParameters; 
+	public boolean produceMethodParameters;
+	/** Indicates whether generic signature should be generated for lambda expressions */
+	public boolean generateGenericSignatureForLambdaExpressions;
 	/** Compliance level for the compiler, refers to a JDK version, e.g. {@link ClassFileConstants#JDK1_4} */
 	public long complianceLevel;
 	/** Original compliance level for the compiler, refers to a JDK version, e.g. {@link ClassFileConstants#JDK1_4},
@@ -1039,6 +1042,7 @@
 		optionsMap.put(OPTION_LineNumberAttribute, (this.produceDebugAttributes & ClassFileConstants.ATTR_LINES) != 0 ? GENERATE : DO_NOT_GENERATE);
 		optionsMap.put(OPTION_SourceFileAttribute, (this.produceDebugAttributes & ClassFileConstants.ATTR_SOURCE) != 0 ? GENERATE : DO_NOT_GENERATE);
 		optionsMap.put(OPTION_MethodParametersAttribute, this.produceMethodParameters ? GENERATE : DO_NOT_GENERATE);
+		optionsMap.put(OPTION_LambdaGenericSignature, this.generateGenericSignatureForLambdaExpressions ? GENERATE : DO_NOT_GENERATE);
 		optionsMap.put(OPTION_PreserveUnusedLocal, this.preserveAllLocalVariables ? PRESERVE : OPTIMIZE_OUT);
 		optionsMap.put(OPTION_DocCommentSupport, this.docCommentSupport ? ENABLED : DISABLED);
 		optionsMap.put(OPTION_ReportMethodWithConstructorName, getSeverityString(MethodWithConstructorName));
@@ -1534,6 +1538,13 @@
 				this.produceMethodParameters = false;
 			}
 		}
+		if ((optionValue = optionsMap.get(OPTION_LambdaGenericSignature)) != null) {
+			if (GENERATE.equals(optionValue)) {
+				this.generateGenericSignatureForLambdaExpressions = true;
+			} else if (DO_NOT_GENERATE.equals(optionValue)) {
+				this.generateGenericSignatureForLambdaExpressions = false;
+			}
+		}
 		if ((optionValue = optionsMap.get(OPTION_SuppressWarnings)) != null) {
 			if (ENABLED.equals(optionValue)) {
 				this.suppressWarnings = true;
@@ -1833,6 +1844,7 @@
 		buf.append("\n\t- line number debug attributes: ").append((this.produceDebugAttributes & ClassFileConstants.ATTR_LINES) != 0 ? "ON" : " OFF"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 		buf.append("\n\t- source debug attributes: ").append((this.produceDebugAttributes & ClassFileConstants.ATTR_SOURCE) != 0 ? "ON" : " OFF"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 		buf.append("\n\t- MethodParameters attributes: ").append(this.produceMethodParameters ? GENERATE : DO_NOT_GENERATE); //$NON-NLS-1$
+		buf.append("\n\t- Generic signature for lambda expressions: ").append(this.generateGenericSignatureForLambdaExpressions ? GENERATE : DO_NOT_GENERATE); //$NON-NLS-1$
 		buf.append("\n\t- preserve all local variables: ").append(this.preserveAllLocalVariables ? "ON" : " OFF"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 		buf.append("\n\t- method with constructor name: ").append(getSeverityString(MethodWithConstructorName)); //$NON-NLS-1$
 		buf.append("\n\t- overridden package default method: ").append(getSeverityString(OverriddenPackageDefaultMethod)); //$NON-NLS-1$