Lambda expressions support: drop generic lambda expressions

This commit is contained in:
Roman Shevchenko
2012-06-09 14:25:59 +04:00
parent 721229a05d
commit 93488641f8
9 changed files with 49 additions and 135 deletions
@@ -22,14 +22,6 @@ import org.jetbrains.annotations.Nullable;
* Represents a Java lambda expression.
*/
public interface PsiLambdaExpression extends PsiExpression {
/**
* Returns this lambda expression's type parameter list (if any).
*
* @return type parameter list or null.
*/
@Nullable
PsiTypeParameterList getTypeParameterList();
/**
* Returns this lambda expression's parameter list.
*
@@ -163,7 +163,7 @@ public class ExpressionParser {
return parseBinary(builder, ExprType.UNARY, MULTIPLICATIVE_OPS);
case UNARY:
return parseUnary(builder, false);
return parseUnary(builder);
case TYPE:
return myParser.getReferenceParser().parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
@@ -246,14 +246,14 @@ public class ExpressionParser {
}
@Nullable
private PsiBuilder.Marker parseUnary(final PsiBuilder builder, final boolean afterCast) {
private PsiBuilder.Marker parseUnary(final PsiBuilder builder) {
final IElementType tokenType = builder.getTokenType();
if (PREFIX_OPS.contains(tokenType)) {
final PsiBuilder.Marker unary = builder.mark();
builder.advanceLexer();
final PsiBuilder.Marker operand = parseUnary(builder, false);
final PsiBuilder.Marker operand = parseUnary(builder);
if (operand == null) {
error(builder, JavaErrorMessages.message("expected.expression"));
}
@@ -269,19 +269,19 @@ public class ExpressionParser {
myParser.getReferenceParser().parseTypeInfo(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD);
if (typeInfo == null || !expect(builder, JavaTokenType.RPARENTH)) {
typeCast.rollbackTo();
return parsePostfix(builder, false);
return parsePostfix(builder);
}
if (PREF_ARITHMETIC_OPS.contains(builder.getTokenType()) && !typeInfo.isPrimitive) {
typeCast.rollbackTo();
return parsePostfix(builder, false);
return parsePostfix(builder);
}
final PsiBuilder.Marker expr = parseUnary(builder, true);
final PsiBuilder.Marker expr = parseUnary(builder);
if (expr == null) {
if (!typeInfo.isParameterized) { // cannot parse correct parenthesized expression after correct parameterized type
typeCast.rollbackTo();
return parsePostfix(builder, false);
return parsePostfix(builder);
}
else {
error(builder, JavaErrorMessages.message("expected.expression"));
@@ -292,13 +292,13 @@ public class ExpressionParser {
return typeCast;
}
else {
return parsePostfix(builder, afterCast);
return parsePostfix(builder);
}
}
@Nullable
private PsiBuilder.Marker parsePostfix(final PsiBuilder builder, final boolean afterCast) {
PsiBuilder.Marker operand = parsePrimary(builder, null, -1, afterCast);
private PsiBuilder.Marker parsePostfix(final PsiBuilder builder) {
PsiBuilder.Marker operand = parsePrimary(builder, null, -1);
if (operand == null) return null;
while (POSTFIX_OPS.contains(builder.getTokenType())) {
@@ -315,13 +315,10 @@ public class ExpressionParser {
// todo[r.sh] make 'this', 'super' and 'class' reference expressions
@Nullable
private PsiBuilder.Marker parsePrimary(final PsiBuilder builder,
@Nullable final BreakPoint breakPoint,
final int breakOffset,
final boolean afterCast) {
private PsiBuilder.Marker parsePrimary(final PsiBuilder builder, @Nullable final BreakPoint breakPoint, final int breakOffset) {
PsiBuilder.Marker startMarker = builder.mark();
PsiBuilder.Marker expr = parsePrimaryExpressionStart(builder, afterCast);
PsiBuilder.Marker expr = parsePrimaryExpressionStart(builder);
if (expr == null) {
startMarker.drop();
return null;
@@ -349,7 +346,7 @@ public class ExpressionParser {
final PsiBuilder.Marker classObjAccess = parseClassAccessOrMethodReference(builder);
if (classObjAccess == null || builder.getCurrentOffset() < offset) {
copy.rollbackTo();
return parsePrimary(builder, BreakPoint.P1, offset, false);
return parsePrimary(builder, BreakPoint.P1, offset);
}
startMarker = copy;
@@ -373,13 +370,13 @@ public class ExpressionParser {
final PsiBuilder.Marker ref = myParser.getReferenceParser().parseJavaCodeReference(builder, false, true, false, false, false);
if (ref == null || builder.getTokenType() != JavaTokenType.DOT || builder.getCurrentOffset() != dotOffset) {
copy.rollbackTo();
return parsePrimary(builder, BreakPoint.P2, offset, false);
return parsePrimary(builder, BreakPoint.P2, offset);
}
builder.advanceLexer();
if (builder.getTokenType() != dotTokenType) {
copy.rollbackTo();
return parsePrimary(builder, BreakPoint.P2, offset, false);
return parsePrimary(builder, BreakPoint.P2, offset);
}
builder.advanceLexer();
@@ -420,7 +417,7 @@ public class ExpressionParser {
final PsiBuilder.Marker copy = startMarker.precede();
startMarker.rollbackTo();
final PsiBuilder.Marker qualifier = parsePrimaryExpressionStart(builder, false);
final PsiBuilder.Marker qualifier = parsePrimaryExpressionStart(builder);
if (qualifier != null) {
final PsiBuilder.Marker refExpr = qualifier.precede();
if (builder.getTokenType() == JavaTokenType.DOT) {
@@ -436,7 +433,7 @@ public class ExpressionParser {
}
copy.rollbackTo();
return parsePrimary(builder, BreakPoint.P3, -1, false);
return parsePrimary(builder, BreakPoint.P3, -1);
}
else {
startMarker.drop();
@@ -465,7 +462,7 @@ public class ExpressionParser {
final PsiBuilder.Marker classObjAccess = parseClassAccessOrMethodReference(builder);
if (classObjAccess == null || builder.getCurrentOffset() <= pos) {
copy.rollbackTo();
return parsePrimary(builder, BreakPoint.P4, -1, false);
return parsePrimary(builder, BreakPoint.P4, -1);
}
startMarker = copy;
@@ -505,7 +502,7 @@ public class ExpressionParser {
}
@Nullable
private PsiBuilder.Marker parsePrimaryExpressionStart(final PsiBuilder builder, final boolean afterCast) {
private PsiBuilder.Marker parsePrimaryExpressionStart(final PsiBuilder builder) {
IElementType tokenType = builder.getTokenType();
if (LITERALS.contains(tokenType)) {
@@ -597,29 +594,6 @@ public class ExpressionParser {
if (tokenType == JavaTokenType.LT) {
expr = builder.mark();
if (!afterCast) {
final PsiBuilder.Marker typeParams = myParser.getReferenceParser().parseTypeParameters(builder, true);
if (typeParams != null) {
tokenType = builder.getTokenType();
PsiBuilder.Marker lambda = null;
if (tokenType == JavaTokenType.LPARENTH) {
lambda = parseLambdaAfterParenth(builder, typeParams);
}
else if (tokenType == JavaTokenType.IDENTIFIER && builder.lookAhead(1) == JavaTokenType.ARROW) {
lambda = parseLambdaExpression(builder, false, typeParams);
}
if (lambda != null) {
expr.drop();
return lambda;
}
expr.rollbackTo();
expr = builder.mark();
}
}
if (!myParser.getReferenceParser().parseReferenceParameterList(builder, false, false)) {
expr.rollbackTo();
return null;
@@ -297,13 +297,6 @@ public class ReferenceParser {
@NotNull
public PsiBuilder.Marker parseTypeParameters(final PsiBuilder builder) {
final PsiBuilder.Marker marker = parseTypeParameters(builder, false);
assert marker != null;
return marker;
}
@Nullable
public PsiBuilder.Marker parseTypeParameters(final PsiBuilder builder, final boolean stopOnErrors) {
final PsiBuilder.Marker list = builder.mark();
if (!expect(builder, JavaTokenType.LT)) {
list.done(JavaElementType.TYPE_PARAMETER_LIST);
@@ -313,10 +306,6 @@ public class ReferenceParser {
while (true) {
final PsiBuilder.Marker param = parseTypeParameter(builder);
if (param == null) {
if (stopOnErrors) {
list.rollbackTo();
return null;
}
error(builder, JavaErrorMessages.message("expected.type.parameter"));
}
if (!expect(builder, JavaTokenType.COMMA)) {
@@ -325,11 +314,6 @@ public class ReferenceParser {
}
if (!expect(builder, JavaTokenType.GT)) {
if (stopOnErrors) {
list.rollbackTo();
return null;
}
// hack for completion
if (builder.getTokenType() == JavaTokenType.IDENTIFIER) {
if (builder.lookAhead(1) == JavaTokenType.GT) {
@@ -187,7 +187,7 @@ public class PsiImplUtil {
final boolean fromBody = lastParent instanceof PsiCodeBlock;
final PsiTypeParameterList typeParameterList = method.getTypeParameterList();
final PsiParameterList parameterList = method.getParameterList();
return processDeclarationsInMethodLike(method, processor, state, fromBody, place, typeParameterList, parameterList);
return processDeclarationsInMethodLike(method, processor, state, place, fromBody, typeParameterList, parameterList);
}
public static boolean processDeclarationsInLambda(@NotNull final PsiLambdaExpression lambda,
@@ -196,23 +196,24 @@ public class PsiImplUtil {
final PsiElement lastParent,
@NotNull final PsiElement place) {
final boolean fromBody = lastParent != null && lastParent == lambda.getBody();
final PsiTypeParameterList typeParameterList = lambda.getTypeParameterList();
final PsiParameterList parameterList = lambda.getParameterList();
return processDeclarationsInMethodLike(lambda, processor, state, fromBody, place, typeParameterList, parameterList);
return processDeclarationsInMethodLike(lambda, processor, state, place, fromBody, null, parameterList);
}
private static boolean processDeclarationsInMethodLike(@NotNull final PsiElement element,
@NotNull final PsiScopeProcessor processor,
@NotNull final ResolveState state,
final boolean fromBody,
@NotNull final PsiElement place,
final boolean fromBody,
@Nullable final PsiTypeParameterList typeParameterList,
@NotNull final PsiParameterList parameterList) {
processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, element);
final ElementClassHint hint = processor.getHint(ElementClassHint.KEY);
if (hint == null || hint.shouldProcess(ElementClassHint.DeclarationKind.CLASS)) {
if (typeParameterList != null && !typeParameterList.processDeclarations(processor, state, null, place)) return false;
if (typeParameterList != null) {
final ElementClassHint hint = processor.getHint(ElementClassHint.KEY);
if (hint == null || hint.shouldProcess(ElementClassHint.DeclarationKind.CLASS)) {
if (!typeParameterList.processDeclarations(processor, state, null, place)) return false;
}
}
if (fromBody) {
@@ -27,12 +27,6 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi
super(JavaElementType.LAMBDA_EXPRESSION);
}
@Override
public PsiTypeParameterList getTypeParameterList() {
final PsiElement element = getFirstChild();
return element instanceof PsiTypeParameterList ? (PsiTypeParameterList)element : null;
}
@NotNull
@Override
public PsiParameterList getParameterList() {
@@ -26,16 +26,11 @@ class C {
int parse(String s);
}
interface ListProducer<T> {
List<T> produce();
}
void test() {
Simplest simplest = <weak_warning descr="Lambda expressions type check is not yet implemented">() -> { }</weak_warning>;
use(<weak_warning descr="Lambda expressions type check is not yet implemented">() -> { }</weak_warning>);
IntParser intParser = <weak_warning descr="Lambda expressions type check is not yet implemented">(String s) -> Integer.parseInt(s)</weak_warning>;
ListProducer<String> listProducer = <weak_warning descr="Lambda expressions type check is not yet implemented"><T>() -> new ArrayList<T>()</weak_warning>;
}
Runnable foo() {
@@ -1,33 +1,18 @@
PsiJavaFile:LambdaExpression12.java
PsiLambdaExpression:<T>() -> new C<T>()
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:T
PsiIdentifier:T('T')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiJavaToken:GT('>')
PsiParameterList:()
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiErrorElement:Unparsed tokens
PsiJavaToken:LT('<')
PsiIdentifier:T('T')
PsiJavaToken:GT('>')
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiNewExpression:new C<T>()
PsiKeyword:new('new')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:C<T>
PsiIdentifier:C('C')
PsiReferenceParameterList
PsiJavaToken:LT('<')
PsiTypeElement:T
PsiJavaCodeReferenceElement:T
PsiIdentifier:T('T')
PsiReferenceParameterList
<empty list>
PsiJavaToken:GT('>')
PsiExpressionList
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
PsiKeyword:new('new')
PsiWhiteSpace(' ')
PsiIdentifier:C('C')
PsiJavaToken:LT('<')
PsiIdentifier:T('T')
PsiJavaToken:GT('>')
PsiJavaToken:LPARENTH('(')
PsiJavaToken:RPARENTH(')')
@@ -1,21 +1,10 @@
PsiJavaFile:LambdaExpression13.java
PsiLambdaExpression:<T>t -> t
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:T
PsiIdentifier:T('T')
PsiElement(EXTENDS_BOUND_LIST)
<empty list>
PsiJavaToken:GT('>')
PsiParameterList:t
PsiParameter:t
PsiModifierList:
<empty list>
PsiIdentifier:t('t')
PsiErrorElement:Unparsed tokens
PsiJavaToken:LT('<')
PsiIdentifier:T('T')
PsiJavaToken:GT('>')
PsiIdentifier:t('t')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiReferenceExpression:t
PsiReferenceParameterList
<empty list>
PsiIdentifier:t('t')
PsiIdentifier:t('t')
@@ -134,8 +134,8 @@ public class ExpressionParserTest extends JavaParsingTestCase {
public void testLambdaExpression9() { doParserTest("(I)p -> null"); }
public void testLambdaExpression10() { doParserTest("(I)(p -> null)"); }
public void testLambdaExpression11() { doParserTest("() -> { }"); }
public void testLambdaExpression12() { doParserTest("<T>() -> new C<T>()"); }
public void testLambdaExpression13() { doParserTest("<T>t -> t"); }
public void testLambdaExpression12() { doParserTest("<T>() -> new C<T>()"); } // these two expressions
public void testLambdaExpression13() { doParserTest("<T>t -> t"); } // should no longer be parsed
public void testLambdaExpression14() { doParserTest("(String t) -> t"); }
public void testLambdaExpression15() { doParserTest("(int a, int b) -> a + b"); }
public void testLambdaExpression16() { doParserTest("(final int x) -> x"); }