diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/VarargsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/VarargsTest.java index 536723b..1bba491 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/VarargsTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/VarargsTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2011 IBM Corporation and others. + * Copyright (c) 2005, 2012 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 @@ -798,6 +798,55 @@ "----------\n" ); } + + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=383780 + public void test015_tolerate() throws Exception { + if (this.complianceLevel < ClassFileConstants.JDK1_5) return; + Map options = getCompilerOptions(); + try { + System.setProperty("tolerateVarargsCodeThatCompiledEarlier", "true"); + if (this.complianceLevel >= ClassFileConstants.JDK1_7) { + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " public static void main(String[] s) {\n" + + " Y.count(new int[0]);\n" + // for some reason this is not ambiguous + " }\n" + + "}\n" + + "class Y {\n" + + " public static void count(int[] array, int ... values) { System.out.print(1); }\n" + + " public static void count(int[] array, int[] ... values) { System.out.print(2); }\n" + + "}\n", + }, + "----------\n" + + "1. ERROR in X.java (at line 3)\n" + + " Y.count(new int[0]);\n" + + " ^^^^^\n" + + "The method count(int[], int[]) is ambiguous for the type Y\n" + + "----------\n", + null, true, options); + } else { + this.runConformTest( + new String[] { + "X.java", + "public class X {\n" + + " public static void main(String[] s) {\n" + + " Y.count(new int[0]);\n" + // for some reason this is not ambiguous + " }\n" + + "}\n" + + "class Y {\n" + + " public static void count(int[] array, int ... values) { System.out.print(1); }\n" + + " public static void count(int[] array, int[] ... values) { System.out.print(2); }\n" + + "}\n", + }, + "1", + null, true, null, options, null); + } + } finally { + System.setProperty("tolerateVarargsCodeThatCompiledEarlier", "false"); + } + } public void test016() { // check behaviour of Scope.mostSpecificMethodBinding() this.runNegativeTest( // but this call is ambiguous @@ -1235,7 +1284,7 @@ }, "1"); } - //https://bugs.eclipse.org/bugs/show_bug.cgi?id=102631 + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=102631 public void test033() { this.runNegativeTest( new String[] { @@ -1301,6 +1350,61 @@ "The method c(boolean, boolean, Object[]) is ambiguous for the type X\n" + "----------\n" ); + } + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=383780 + public void test033_tolerate() { + if (this.complianceLevel < ClassFileConstants.JDK1_5) return; + Map options = getCompilerOptions(); + try { + System.setProperty("tolerateVarargsCodeThatCompiledEarlier", "true"); + if (this.complianceLevel >= ClassFileConstants.JDK1_7) { + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " void a(boolean b, Object... o) {System.out.print(1);}\n" + + " void a(Object... o) {System.out.print(2);}\n" + + " public static void main(String[] args) {\n" + + " X x = new X();\n" + + " x.a(true);\n" + + " x.a(true, \"foobar\");\n" + + " x.a(\"foo\", \"bar\");\n" + + " }\n" + + "}\n", + }, + "----------\n" + + "1. ERROR in X.java (at line 6)\n" + + " x.a(true);\n" + + " ^\n" + + "The method a(boolean, Object[]) is ambiguous for the type X\n" + + "----------\n" + + "2. ERROR in X.java (at line 7)\n" + + " x.a(true, \"foobar\");\n" + + " ^\n" + + "The method a(boolean, Object[]) is ambiguous for the type X\n" + + "----------\n", + null, true, options); + } else { + this.runConformTest( + new String[] { + "X.java", + "public class X {\n" + + " void a(boolean b, Object... o) {System.out.print(1);}\n" + + " void a(Object... o) {System.out.print(2);}\n" + + " public static void main(String[] args) {\n" + + " X x = new X();\n" + + " x.a(true);\n" + + " x.a(true, \"foobar\");\n" + + " x.a(\"foo\", \"bar\");\n" + + " }\n" + + "}\n", + }, + "112", + null, true, null, options, null); + } + } finally { + System.setProperty("tolerateVarargsCodeThatCompiledEarlier", "false"); + } } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=106106 public void test034() { @@ -2818,6 +2922,106 @@ }, "Done"); } + + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=383780 + public void test070_tolerate() throws Exception { + if (this.complianceLevel < ClassFileConstants.JDK1_5) return; + Map options = getCompilerOptions(); + try { + System.setProperty("tolerateVarargsCodeThatCompiledEarlier", "true"); + if (this.complianceLevel < ClassFileConstants.JDK1_7) { + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " public static void foo(int ...i) {}\n" + + " public static void foo(double...d) {}\n" + + " public static void main(String[] args) {\n" + + " foo(1, 2, 3);\n" + + " System.out.println (\"Done\");\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 5)\n" + + " foo(1, 2, 3);\n" + + " ^^^\n" + + "The method foo(int[]) is ambiguous for the type X\n" + + "----------\n", + null, true, options); + } else { + this.runConformTest( + new String[] { + "X.java", + "public class X {\n" + + " public static void foo(int ...i) {}\n" + + " public static void foo(double...d) {}\n" + + " public static void main(String[] args) {\n" + + " foo(1, 2, 3);\n" + + " System.out.println (\"Done\");\n" + + " }\n" + + "}\n" + }, + "Done", + null, true, null, options, null); + } + } finally { + System.setProperty("tolerateVarargsCodeThatCompiledEarlier", "false"); + } + + } + + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=383780 + public void test070_tolerate2() throws Exception { + if (this.complianceLevel < ClassFileConstants.JDK1_5) return; + Map options = getCompilerOptions(); + try { + System.setProperty("tolerateVarargsCodeThatCompiledEarlier", "true"); + if (this.complianceLevel >= ClassFileConstants.JDK1_7) { + this.runNegativeTest( + new String[] { + "X.java", + "import java.util.Arrays;\n" + + "public class X {\n" + + " public static void test(int... a) {\n" + + " System.out.println(Arrays.toString(a));\n}\n" + + " public static void test(Object... a) {\n" + + " System.out.println(Arrays.toString(a));\n}\n" + + " public static void main(String[] args) {\n" + + " test(1);\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 10)\n" + + " test(1);\n" + + " ^^^^\n" + + "The method test(int[]) is ambiguous for the type X\n" + + "----------\n", + null, true, options); + } else { + this.runConformTest( + new String[] { + "X.java", + "import java.util.Arrays;\n" + + "public class X {\n" + + " public static void test(int... a) {\n" + + " System.out.println(Arrays.toString(a));\n}\n" + + " public static void test(Object... a) {\n" + + " System.out.println(Arrays.toString(a));\n}\n" + + " public static void main(String[] args) {\n" + + " test(1);\n" + + " }\n" + + "}\n" + }, + "[1]", + null, true, null, options, null); + } + } finally { + System.setProperty("tolerateVarargsCodeThatCompiledEarlier", "false"); + } + + } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=346038 public void test070a() throws Exception { if (this.complianceLevel < ClassFileConstants.JDK1_5) return; @@ -2835,6 +3039,52 @@ }, "Done"); } + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=383780 + public void test070a_tolerate() throws Exception { + if (this.complianceLevel < ClassFileConstants.JDK1_5) return; + Map options = getCompilerOptions(); + try { + System.setProperty("tolerateVarargsCodeThatCompiledEarlier", "true"); + if (this.complianceLevel < ClassFileConstants.JDK1_7) { + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " public static void foo(int ...i) {}\n" + + " public static void foo(double...d) {}\n" + + " public static void main(String[] args) {\n" + + " foo(1, 2, 3);\n" + + " System.out.println (\"Done\");\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 5)\n" + + " foo(1, 2, 3);\n" + + " ^^^\n" + + "The method foo(int[]) is ambiguous for the type X\n" + + "----------\n", + null, true, options); + } else { + this.runConformTest( + new String[] { + "X.java", + "public class X {\n" + + " public static void foo(int ...i) {}\n" + + " public static void foo(double...d) {}\n" + + " public static void main(String[] args) {\n" + + " foo(1, 2, 3);\n" + + " System.out.println (\"Done\");\n" + + " }\n" + + "}\n" + }, + "Done", + null, true, null, options, null); + } + } finally { + System.setProperty("tolerateVarargsCodeThatCompiledEarlier", "false"); + } + } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=346038 public void test070b() throws Exception { if (this.complianceLevel < ClassFileConstants.JDK1_5) return; 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 25fee09..1ca216e 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. + * Copyright (c) 2000, 2012 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 @@ -582,6 +582,10 @@ } int compatibilityLevel; + CompilerOptions options = this.compilerOptions(); + String tolerateVarargsCode = System.getProperty("tolerateVarargsCodeThatCompiledEarlier"); //$NON-NLS-1$ + if (options.complianceLevel < ClassFileConstants.JDK1_7 && tolerateVarargsCode != null && tolerateVarargsCode.equalsIgnoreCase("true")) //$NON-NLS-1$ + tiebreakingVarargsMethods = false; if ((compatibilityLevel = parameterCompatibilityLevel(method, arguments, tiebreakingVarargsMethods)) > NOT_COMPATIBLE) { if (compatibilityLevel == VARARGS_COMPATIBLE) { TypeBinding varargsElementType = method.parameters[method.parameters.length - 1].leafComponentType(); @@ -3029,8 +3033,15 @@ if (i == oneParamsLength - 1 && one.isVarargs() && two.isVarargs()) { TypeBinding oType = ((ArrayBinding) oneParam).elementsType(); TypeBinding eType = ((ArrayBinding) twoParam).elementsType(); - if (oType == eType || oType.isCompatibleWith(eType)) - return true; // special case to choose between 2 varargs methods when the last arg is Object[] + CompilerOptions options = this.compilerOptions(); + String tolerateVarargsCode = System.getProperty("tolerateVarargsCodeThatCompiledEarlier"); //$NON-NLS-1$ + if (options.complianceLevel < ClassFileConstants.JDK1_7 && tolerateVarargsCode != null && tolerateVarargsCode.equalsIgnoreCase("true")) {//$NON-NLS-1$ + if (oneParam == eType || oneParam.isCompatibleWith(eType)) + return true; // special case to choose between 2 varargs methods when the last arg is Object[] + } else { + if (oType == eType || oType.isCompatibleWith(eType)) + return true; // special case to choose between 2 varargs methods when the last arg is Object[] + } } return false; } @@ -4092,7 +4103,12 @@ // only called if env.options.sourceLevel >= ClassFileConstants.JDK1_5 if (arg.isCompatibleWith(param)) return COMPATIBLE; - if (tieBreakingVarargsMethods) { + CompilerOptions options = this.compilerOptions(); + String tolerateVarargsCode = System.getProperty("tolerateVarargsCodeThatCompiledEarlier"); //$NON-NLS-1$ + boolean isTolerateVarargsSet = false; + if (tolerateVarargsCode != null && tolerateVarargsCode.equalsIgnoreCase("true")) //$NON-NLS-1$ + isTolerateVarargsSet = true; + if (tieBreakingVarargsMethods && (options.complianceLevel >= ClassFileConstants.JDK1_7 || !isTolerateVarargsSet)) { //$NON-NLS-1$ /* 15.12.2.5 Choosing the Most Specific Method, ... One variable arity member method named m is more specific than another variable arity member method of the same name if either ... Only subtypes relationship should be used. Actually this is true even for fixed arity methods, but in practice is not an issue since we run the algorithm