Bug 541532 - [11] JEP 323: Local-Variable Syntax for Lambda parameters
does not work for Function and Predicate
Change-Id: Ibf16295c5d6d262949b6c74fc95a8fbb1b9be9b3
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JEP323VarLambdaParamsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JEP323VarLambdaParamsTest.java
index 5bc4f6e..351fb85 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JEP323VarLambdaParamsTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JEP323VarLambdaParamsTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2018 IBM Corporation and others.
+ * Copyright (c) 2018, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -316,4 +316,29 @@
"\'var\' is not allowed as an element type of an array\n" +
"----------\n");
}
+public void testBug541532_01() throws IOException {
+ runConformTest(new String[] {
+ "X.java",
+ "import java.util.Arrays;\n" +
+ "import java.util.List;\n" +
+ "\n" +
+ "public class X {\n" +
+ "\n" +
+ " public static void foo(List<String> list) {\n" +
+ " list.stream()\n" +
+ " .map((var s) -> s.toLowerCase())\n" +
+ " .forEach(System.out::println);\n" +
+ "\n" +
+ " list.stream()\n" +
+ " .filter((var s) -> s.length() == 1)\n" +
+ " .forEach(System.out::println);\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " String[] greetings = {\"hello\", \"world\"};\n" +
+ " X.foo(Arrays.asList(greetings));\n" +
+ " }\n" +
+ "}\n",
+ "hello\nworld"
+ });
+}
}
\ No newline at end of file
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 3494069..08067d8 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, 2018 IBM Corporation and others.
+ * Copyright (c) 2012, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -136,6 +136,7 @@
protected Expression [] resultExpressions = NO_EXPRESSIONS;
public InferenceContext18 inferenceContext; // when performing tentative resolve keep a back reference to the driving context
private Map<Integer/*sourceStart*/, LocalTypeBinding> localTypes; // support look-up of a local type from this lambda copy
+ public boolean argumentsTypeVar = false;
public LambdaExpression(CompilationResult compilationResult, boolean assistNode, boolean requiresGenericSignature) {
@@ -247,7 +248,6 @@
public TypeBinding resolveType(BlockScope blockScope, boolean skipKosherCheck) {
boolean argumentsTypeElided = argumentsTypeElided();
- boolean argumentsTypeVar = argumentsTypeVar(blockScope);
int argumentsLength = this.arguments == null ? 0 : this.arguments.length;
if (this.constant != Constant.NotAConstant) {
@@ -256,7 +256,7 @@
if (this.original == this)
this.ordinal = recordFunctionalType(blockScope);
- if (!argumentsTypeElided && !argumentsTypeVar) {
+ if (!argumentsTypeElided) {
for (int i = 0; i < argumentsLength; i++)
this.argumentTypes[i] = this.arguments[i].type.resolveType(blockScope, true /* check bounds*/);
}
@@ -289,7 +289,7 @@
int parametersLength = this.descriptor.parameters.length;
if (parametersLength != argumentsLength) {
this.scope.problemReporter().lambdaSignatureMismatched(this);
- if (argumentsTypeElided || argumentsTypeVar || this.original != this) // no interest in continuing to error check copy.
+ if (argumentsTypeElided || this.original != this) // no interest in continuing to error check copy.
return this.resolvedType = null; // FUBAR, bail out ...
else {
this.resolvedType = null; // continue to type check.
@@ -314,7 +314,7 @@
TypeBinding argumentType;
final TypeBinding expectedParameterType = haveDescriptor && i < this.descriptor.parameters.length ? this.descriptor.parameters[i] : null;
- argumentType = (argumentsTypeElided || argumentsTypeVar) ? expectedParameterType : this.argumentTypes[i];
+ argumentType = argumentsTypeElided ? expectedParameterType : this.argumentTypes[i];
if (argumentType == null) {
argumentsHaveErrors = true;
} else if (argumentType == TypeBinding.VOID) {
@@ -329,7 +329,7 @@
}
}
}
- if (!argumentsTypeElided && !argumentsTypeVar && !argumentsHaveErrors) {
+ if (!argumentsTypeElided && !argumentsHaveErrors) {
ReferenceBinding groundType = null;
ReferenceBinding expectedSAMType = null;
if (this.expectedType instanceof IntersectionTypeBinding18)
@@ -365,7 +365,7 @@
Argument argument = this.arguments[i];
TypeBinding argumentType;
final TypeBinding expectedParameterType = haveDescriptor && i < this.descriptor.parameters.length ? this.descriptor.parameters[i] : null;
- argumentType = (argumentsTypeElided || argumentsTypeVar) ? expectedParameterType : this.argumentTypes[i];
+ argumentType = argumentsTypeElided ? expectedParameterType : this.argumentTypes[i];
expectedParameterTypes[i] = expectedParameterType;
if (argumentType != null && argumentType != TypeBinding.VOID) {
if (haveDescriptor && expectedParameterType != null && argumentType.isValidBinding() && TypeBinding.notEquals(argumentType, expectedParameterType)) {
@@ -396,7 +396,7 @@
}
}
}
- if (argumentsTypeVar) {
+ if (this.argumentsTypeVar) {
for (int i = 0; i < argumentsLength; ++i) {
this.arguments[i].type.resolvedType = expectedParameterTypes[i];
}
@@ -408,7 +408,7 @@
this.binding.setParameterAnnotations(parameterAnnotations);
}
- if (!argumentsTypeElided && !argumentsTypeVar && !argumentsHaveErrors && this.binding.isVarargs()) {
+ if (!argumentsTypeElided && !argumentsHaveErrors && this.binding.isVarargs()) {
if (!this.binding.parameters[this.binding.parameters.length - 1].isReifiable()) {
this.scope.problemReporter().possibleHeapPollutionFromVararg(this.arguments[this.arguments.length - 1]);
}
@@ -438,7 +438,7 @@
} // TODO (stephan): else? (can that happen?)
if (haveDescriptor && !argumentsHaveErrors && blockScope.compilerOptions().isAnnotationBasedNullAnalysisEnabled) {
- if (!argumentsTypeElided && !argumentsTypeVar) {
+ if (!argumentsTypeElided) {
AbstractMethodDeclaration.createArgumentBindings(this.arguments, this.binding, this.scope); // includes validation
// no application of null-ness default, hence also no warning regarding redundant null annotation
mergeParameterNullAnnotations(blockScope);
@@ -533,28 +533,7 @@
@Override
public boolean argumentsTypeElided() {
- return this.arguments.length > 0 && this.arguments[0].hasElidedType();
- }
-
- private boolean argumentsTypeVar(BlockScope blockScope) {
- if (blockScope.compilerOptions().complianceLevel < ClassFileConstants.getComplianceLevelForJavaVersion(ClassFileConstants.MAJOR_VERSION_11)) return false;
- boolean retval = false, isVar = false, mixReported = false;
- Argument[] args = this.arguments;
- for (int i = 0, l = args.length; i < l; ++i) {
- Argument arg = args[i];
- TypeReference type = arg.type;
- if (type == null) continue;
- boolean prev = isVar;
- retval |= isVar = type.isTypeNameVar(blockScope);
- if (i > 0 && prev != isVar && !mixReported) { // report only once per list
- blockScope.problemReporter().varCannotBeMixedWithNonVarParams(isVar ? arg : args[i - 1]);
- mixReported = true;
- }
- if (isVar && (type.dimensions() > 0 || type.extraDimensions() > 0)) {
- blockScope.problemReporter().varLocalCannotBeArray(arg);
- }
- }
- return retval;
+ return (this.arguments.length > 0 && this.arguments[0].hasElidedType()) || this.argumentsTypeVar;
}
private void analyzeExceptions() {
@@ -710,7 +689,6 @@
if (targetType == null) // assumed to signal another primary error
return true;
-
if (argumentsTypeElided())
return false;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
index 885fc4c..a9e2139 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -941,6 +941,7 @@
private int stateStackLengthStack[] = new int[0];
protected boolean parsingJava8Plus;
protected boolean parsingJava9Plus;
+protected boolean parsingJava11Plus;
protected int unstackedAct = ERROR_ACTION;
private boolean haltOnSyntaxError = false;
private boolean tolerateDefaultClassMethods = false;
@@ -959,6 +960,7 @@
initializeScanner();
this.parsingJava8Plus = this.options.sourceLevel >= ClassFileConstants.JDK1_8;
this.parsingJava9Plus = this.options.sourceLevel >= ClassFileConstants.JDK9;
+ this.parsingJava11Plus = this.options.sourceLevel >= ClassFileConstants.JDK11;
this.astLengthStack = new int[50];
this.expressionLengthStack = new int[30];
this.typeAnnotationLengthStack = new int[30];
@@ -8552,6 +8554,31 @@
this.currentElement.lambdaNestLevel++;
}
}
+private void setArgumentsTypeVar(LambdaExpression lexp) {
+ Argument[] args = lexp.arguments;
+ if (!this.parsingJava11Plus || args == null || args.length == 0) {
+ lexp.argumentsTypeVar = false;
+ return;
+ }
+
+ boolean isVar = false, mixReported = false;
+ for (int i = 0, l = args.length; i < l; ++i) {
+ Argument arg = args[i];
+ TypeReference type = arg.type;
+ char[][] typeName = type != null ? type.getTypeName() : null;
+ boolean prev = isVar;
+ isVar = typeName != null && typeName.length == 1 &&
+ CharOperation.equals(typeName[0], TypeConstants.VAR);
+ lexp.argumentsTypeVar |= isVar;
+ if (i > 0 && prev != isVar && !mixReported) { // report only once per list
+ this.problemReporter().varCannotBeMixedWithNonVarParams(isVar ? arg : args[i - 1]);
+ mixReported = true;
+ }
+ if (isVar && (type.dimensions() > 0 || type.extraDimensions() > 0)) {
+ this.problemReporter().varLocalCannotBeArray(arg);
+ }
+ }
+}
protected void consumeLambdaExpression() {
// LambdaExpression ::= LambdaHeader LambdaBody
@@ -8581,6 +8608,7 @@
if (!this.parsingJava8Plus) {
problemReporter().lambdaExpressionsNotBelow18(lexp);
}
+ setArgumentsTypeVar(lexp);
pushOnExpressionStack(lexp);
if (this.currentElement != null) {
this.lastCheckPoint = body.sourceEnd + 1;