diff options
author | Stephan Herrmann | 2014-01-25 14:06:49 +0000 |
---|---|---|
committer | Stephan Herrmann | 2014-01-25 14:06:49 +0000 |
commit | 86bc6fbd8bb61b3353c5beacb63fca5b9ddef84a (patch) | |
tree | 3097a6b980e4d8cc03efbcea0766fb0170ba21ba | |
parent | 31225f931c10340b8616c3f4ecc6725f368df84c (diff) | |
download | eclipse.jdt.core-86bc6fbd8bb61b3353c5beacb63fca5b9ddef84a.tar.gz eclipse.jdt.core-86bc6fbd8bb61b3353c5beacb63fca5b9ddef84a.tar.xz eclipse.jdt.core-86bc6fbd8bb61b3353c5beacb63fca5b9ddef84a.zip |
Bug 426590 - [1.8][compiler] Compiler error with tenary operator
4 files changed, 130 insertions, 53 deletions
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 530607942b..7396f4f424 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 @@ -21,6 +21,7 @@ * Bug 415734 - Eclipse gives compilation error calling method with an inferred generic return type * Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) * Bug 423496 - [1.8] Implement new incorporation rule once it becomes available + * Bug 426590 - [1.8][compiler] Compiler error with tenary operator *******************************************************************************/ package org.eclipse.jdt.core.tests.compiler.regression; @@ -3375,4 +3376,31 @@ public void test426589() { }, ""); } +public void testBug426590() { + runConformTest( + new String[] { + "A.java", + "public class A {\n" + + " \n" + + " }\n" + + " \n" + + " class B extends A {\n" + + " \n" + + " }\n" + + " \n" + + " class C extends B {\n" + + " \n" + + " }\n" + + " \n" + + " class D {\n" + + " D(A a) {\n" + + " \n" + + " }\n" + + " \n" + + " D(boolean b) {\n" + + " this(b ? new B() : new C());\n" + + " }\n" + + " }\n" + }); +} }
\ No newline at end of file diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/DebugEvaluationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/DebugEvaluationTest.java index ea958f9973..f675eb41d3 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/DebugEvaluationTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/DebugEvaluationTest.java @@ -35,6 +35,9 @@ import org.eclipse.jdt.internal.eval.InstallException; import com.sun.jdi.VirtualMachine; public class DebugEvaluationTest extends EvaluationTest { + static { +// TESTS_NAMES = new String[] { "test069" }; + } class DebugRequestor extends Requestor { public boolean acceptClassFiles(org.eclipse.jdt.internal.compiler.ClassFile[] classFiles, char[] codeSnippetClassName) { if (DebugEvaluationTest.this.jdiStackFrame == null) { 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 3910136831..16731ca4a8 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 @@ -1020,7 +1020,8 @@ public class InferenceContext18 { /** * Retrieve the rank'th parameter, possibly respecting varargs invocation, see 15.12.2.4. - * Returns null if out of bounds and CHECK_VARARG was not requested. + * Returns null if out of bounds and CHECK_VARARG was not requested. + * Precondition: isVarArgs implies method.isVarargs() */ public static TypeBinding getParameter(TypeBinding[] parameters, int rank, boolean isVarArgs) { if (isVarArgs) { 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 8975a6e34c..ef4bada4d7 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 @@ -30,6 +30,7 @@ * Bug 426366 - [1.8][compiler] Type inference doesn't handle multiple candidate target types in outer overload context * Bug 426290 - [1.8][compiler] Inference + overloading => wrong method resolution ? * Bug 426589 - [1.8][compiler] Compiler error with generic method/constructor invocation as vargs argument + * Bug 426590 - [1.8][compiler] Compiler error with tenary operator * Jesper S Moller - Contributions for * Bug 378674 - "The method can be declared as static" is wrong * Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335 @@ -763,7 +764,8 @@ public abstract class Scope { } private int parameterCompatibilityLevel18(MethodBinding method, TypeBinding[] arguments, boolean tiebreakingVarargsMethods, InvocationSite site) { - if (site instanceof Invocation) { + jdk18checks: + if (site instanceof Invocation && compilerOptions().complianceLevel >= ClassFileConstants.JDK1_8) { Invocation invocation = (Invocation) site; if (method instanceof ParameterizedGenericMethodBinding) { InferenceContext18 infCtx = invocation.getInferenceContext((ParameterizedGenericMethodBinding) method); @@ -779,62 +781,105 @@ public abstract class Scope { if (invocationArguments != null) { InnerInferenceHelper innerInferenceHelper = invocation.innerInferenceHelper(); int argLen = invocationArguments.length; - boolean isVarArgs = argLen != method.parameters.length; // if same lengths, isVarArgs can still be updated below + boolean isVarArgs[] = new boolean[1]; // emulate an in-out parameter for compatibilityLevel18FromInner(..) + isVarArgs[0] = method.isVarargs() && argLen != method.parameters.length; // if same lengths, isVarArgs can still be updated below + int level = COMPATIBLE; for (int i = 0; i < argLen; i++) { - Expression invocArg = invocationArguments[i]; - if (invocArg instanceof Invocation && invocArg.resolvedType != null) { // TODO any poly? ReferenceExpression? - Invocation innerPoly = (Invocation) invocArg; - TypeBinding resolvedType = invocArg.resolvedType; - TypeBinding targetType = InferenceContext18.getParameter(method.parameters, i, isVarArgs); - if (!isVarArgs && shouldTryVarargs(method, resolvedType, targetType)) { - isVarArgs = true; - targetType = InferenceContext18.getParameter(method.parameters, i, true); + int nextLevel = compatibilityLevel18FromInner(method, innerInferenceHelper, invocationArguments[i], argLen, i, isVarArgs); + if (nextLevel == NOT_COMPATIBLE) + return nextLevel; + if (nextLevel == -2) + break jdk18checks; + level = Math.max(level, nextLevel); + } + return level; // neither NOT_COMPATIBLE nor unknown(-2) seen + } + } + // fall back to old method: + return parameterCompatibilityLevel(method, arguments, tiebreakingVarargsMethods); + } + + private int compatibilityLevel18FromInner(MethodBinding method, InnerInferenceHelper innerInferenceHelper, Expression invocArg, int argLen, int i, boolean[] isVarArgs) + { + int compatible = isVarArgs[0] ? VARARGS_COMPATIBLE : COMPATIBLE; + TypeBinding resolvedType = invocArg.resolvedType; + TypeBinding targetType = InferenceContext18.getParameter(method.parameters, i, isVarArgs[0]); + if (!isVarArgs[0] && shouldTryVarargs(method, resolvedType, targetType)) { + isVarArgs[0] = true; + targetType = InferenceContext18.getParameter(method.parameters, i, true); + } + if (targetType == null) + return NOT_COMPATIBLE; // mismatching number of args or other severe problem inside method binding + if (invocArg instanceof Invocation && resolvedType != null) { + Invocation innerPoly = (Invocation) invocArg; + if (resolvedType.isCompatibleWith(targetType, this)) { + return compatible; + } else { + MethodBinding innerBinding = innerPoly.binding(null); // 1. try without update + if (innerBinding instanceof ParameterizedGenericMethodBinding) { + ParameterizedGenericMethodBinding innerParameterized = (ParameterizedGenericMethodBinding) innerBinding; + InferenceContext18 infCtx18 = innerPoly.getInferenceContext(innerParameterized); + if (infCtx18 != null && !infCtx18.hasResultFor(targetType)) { + // not detected as compatible, because inference still needs to complete? + invocArg.setExpectedType(targetType); + MethodBinding solution = infCtx18.inferInvocationType(innerPoly, innerParameterized); + if (solution != null && solution.isValidBinding()) { + if (innerPoly.updateBindings(solution, targetType)) { + if (innerInferenceHelper != null) + innerInferenceHelper.registerInnerResult(method, invocArg.resolvedType, argLen, i); + } + if (solution.returnType != null && solution.returnType.isCompatibleWith(targetType, this)) + return compatible; } - if (!resolvedType.isCompatibleWith(targetType, this)) { - MethodBinding innerBinding = innerPoly.binding(null); // 1. try without update - if (innerBinding instanceof ParameterizedGenericMethodBinding) { - ParameterizedGenericMethodBinding innerParameterized = (ParameterizedGenericMethodBinding) innerBinding; - InferenceContext18 infCtx18 = innerPoly.getInferenceContext(innerParameterized); - if (infCtx18 != null && !infCtx18.hasResultFor(targetType)) { - // not detected as compatible, because inference still needs to complete? - invocArg.setExpectedType(targetType); - MethodBinding solution = infCtx18.inferInvocationType(innerPoly, innerParameterized); - if (solution != null && solution.isValidBinding()) { - if (innerPoly.updateBindings(solution, targetType)) { - if (innerInferenceHelper != null) - innerInferenceHelper.registerInnerResult(method, invocArg.resolvedType, argLen, i); - } - if (solution.returnType != null && solution.returnType.isCompatibleWith(targetType, this)) - return isVarArgs ? VARARGS_COMPATIBLE : COMPATIBLE; - } - return NOT_COMPATIBLE; - } else if (innerPoly instanceof AllocationExpression) { - // not detected as compatible, because its a diamond whose type hasn't yet been inferred? - TypeBinding[] typeArguments = resolvedType.typeArguments(); - if (typeArguments != null && typeArguments.length == 0) { - AllocationExpression alloc = (AllocationExpression) innerPoly; - if ((alloc.type.bits & ASTNode.IsDiamond) != 0) { - // not-yet-inferred diamond: erasure compatibility should suffice, detail will be checked using inference - if (invocArg.resolvedType.isCompatibleWith(targetType.erasure(), this)) - return COMPATIBLE; - return NOT_COMPATIBLE; - } - } - } - } else if (innerPoly instanceof AllocationExpression) { - MethodBinding updatedMethod = innerPoly.binding(targetType); // 2. try with updating - if (updatedMethod != innerBinding && updatedMethod != null && updatedMethod.isValidBinding()) { - if (updatedMethod.declaringClass.isCompatibleWith(targetType)) - return COMPATIBLE; - return NOT_COMPATIBLE; - } + return NOT_COMPATIBLE; + } else if (innerPoly instanceof AllocationExpression) { + // not detected as compatible, because its a diamond whose type hasn't yet been inferred? + TypeBinding[] typeArguments = resolvedType.typeArguments(); + if (typeArguments != null && typeArguments.length == 0) { + AllocationExpression alloc = (AllocationExpression) innerPoly; + if ((alloc.type.bits & ASTNode.IsDiamond) != 0) { + // not-yet-inferred diamond: erasure compatibility should suffice, detail will be checked using inference + if (resolvedType.isCompatibleWith(targetType.erasure(), this)) + return compatible; + return NOT_COMPATIBLE; } } } + } else if (innerPoly instanceof AllocationExpression) { + MethodBinding updatedMethod = innerPoly.binding(targetType); // 2. try with updating + if (updatedMethod != innerBinding && updatedMethod != null && updatedMethod.isValidBinding()) { + if (updatedMethod.declaringClass.isCompatibleWith(targetType)) + return compatible; + return NOT_COMPATIBLE; + } } } + } else if (invocArg.isPolyExpression()) { + if (invocArg instanceof ConditionalExpression) { + ConditionalExpression ce = (ConditionalExpression) invocArg; + int level = compatibilityLevel18FromInner(method, innerInferenceHelper, ce.valueIfTrue, argLen, compatible, isVarArgs); + if (level == NOT_COMPATIBLE) + return NOT_COMPATIBLE; + int level2 = compatibilityLevel18FromInner(method, innerInferenceHelper, ce.valueIfFalse, argLen, compatible, isVarArgs); + if (level2 == NOT_COMPATIBLE) + return NOT_COMPATIBLE; + return Math.max(level, level2); + } + // LE or RE: + if (invocArg.isCompatibleWith(targetType, this)) + return COMPATIBLE; + if (!isVarArgs[0] && method.isVarargs()) { // can't use shouldTryVarargs without a resolvedType, so just try it: + isVarArgs[0] = true; + targetType = InferenceContext18.getParameter(method.parameters, i, true); + if (targetType != null && invocArg.isCompatibleWith(targetType, this)) + return VARARGS_COMPATIBLE; + } + return NOT_COMPATIBLE; + } else if (resolvedType != null && resolvedType.isValidBinding()) { + // need to handle "normal" expressions too, since mixed poly/standalone argument lists must be fully analyzed. + return parameterCompatibilityLevel(resolvedType, targetType); } - return parameterCompatibilityLevel(method, arguments, tiebreakingVarargsMethods); + return -2; // don't know } private boolean shouldTryVarargs(MethodBinding method, TypeBinding resolvedType, TypeBinding targetType) { @@ -842,7 +887,7 @@ public abstract class Scope { return false; if (targetType == null) return true; // off range - if (targetType.isArrayType() && !resolvedType.isCompatibleWith(targetType, this)) + if (targetType.isArrayType() && resolvedType != null && !resolvedType.isCompatibleWith(targetType, this)) return true; // not a direct match but hope to improve return false; } @@ -4637,12 +4682,12 @@ public abstract class Scope { if (arg == null || param == null) return NOT_COMPATIBLE; - if (arg.isCompatibleWith(param)) + if (arg.isCompatibleWith(param, this)) return COMPATIBLE; if (arg.isBaseType() != param.isBaseType()) { TypeBinding convertedType = environment().computeBoxingType(arg); - if (TypeBinding.equalsEquals(convertedType, param) || convertedType.isCompatibleWith(param)) + if (TypeBinding.equalsEquals(convertedType, param) || convertedType.isCompatibleWith(param, this)) return AUTOBOX_COMPATIBLE; } return NOT_COMPATIBLE; |