From 8019357bd5af89975f9f36d447708cb949b5b9f6 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Wed, 14 Mar 2012 12:51:21 +0400 Subject: [PATCH] KT-555 Parse error for generic function invocation #KT-555 Fixed --- .../lang/parsing/JetExpressionParsing.java | 40 ++--- .../jet/lang/parsing/JetParsing.java | 50 +++--- .../jet/lang/resolve/calls/CallResolver.java | 19 +- .../tests/StarsInFunctionCalls.jet | 13 ++ compiler/testData/psi/FunctionCalls.jet | 5 + compiler/testData/psi/FunctionCalls.txt | 162 ++++++++++++++++++ .../psi/TypeExpressionAmbiguities_ERR.txt | 25 ++- 7 files changed, 245 insertions(+), 69 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/StarsInFunctionCalls.jet diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java index c925df969a7..0831cff822c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java @@ -53,7 +53,9 @@ public class JetExpressionParsing extends AbstractJetParsing { FUN_KEYWORD, FOR_KEYWORD, NULL_KEYWORD, TRUE_KEYWORD, FALSE_KEYWORD, IS_KEYWORD, THROW_KEYWORD, RETURN_KEYWORD, BREAK_KEYWORD, CONTINUE_KEYWORD, OBJECT_KEYWORD, IF_KEYWORD, TRY_KEYWORD, ELSE_KEYWORD, WHILE_KEYWORD, DO_KEYWORD, - WHEN_KEYWORD, RBRACKET, RBRACE, RPAR, PLUSPLUS, MINUSMINUS, MUL, PLUS, MINUS, EXCL, DIV, PERC, LTEQ, + WHEN_KEYWORD, RBRACKET, RBRACE, RPAR, PLUSPLUS, MINUSMINUS, +// MUL, + PLUS, MINUS, EXCL, DIV, PERC, LTEQ, // TODO GTEQ, foo=x EQEQEQ, EXCLEQEQEQ, EQEQ, EXCLEQ, ANDAND, OROR, SAFE_ACCESS, ELVIS, SEMICOLON, RANGE, EQ, MULTEQ, DIVEQ, PERCEQ, PLUSEQ, MINUSEQ, NOT_IN, NOT_IS, //HASH, @@ -385,13 +387,6 @@ public class JetExpressionParsing extends AbstractJetParsing { expression.done(SAFE_ACCESS_EXPRESSION); } -// else if (at(QUEST)) { -// advance(); // QUEST -// -// parseCallExpression(); -// -// expression.done(PREDICATE_EXPRESSION); -// } // else if (at(HASH)) { // advance(); // HASH // @@ -426,31 +421,16 @@ public class JetExpressionParsing extends AbstractJetParsing { parseCallWithClosure(); } else if (at(LT)) { - // TODO: be (even) more clever - int gtPos = matchTokenStreamPredicate(new FirstBefore( - new At(GT), - new AtSet(TYPE_ARGUMENT_LIST_STOPPERS, TokenSet.create(RPAR, RBRACE, RBRACKET)) - .or(new AtFirstTokenOfTokens(IDENTIFIER, LPAR) -// .or(new AtFirstTokenOfTokens(QUEST, IDENTIFIER)) - ) - ) { - @Override - public boolean isTopLevel(int openAngleBrackets, int openBrackets, int openBraces, int openParentheses) { - return openAngleBrackets == 1 && openBrackets == 0 && openBraces == 0 && openParentheses == 0; - } - - @Override - public boolean handleUnmatchedClosing(IElementType token) { - fail(); - return true; - } - }); - if (gtPos >= 0) { - myJetParsing.parseTypeArgumentList(gtPos); + PsiBuilder.Marker typeArgumentList = mark(); + if (myJetParsing.tryParseTypeArgumentList(TYPE_ARGUMENT_LIST_STOPPERS)) { + typeArgumentList.done(TYPE_ARGUMENT_LIST); if (!myBuilder.newlineBeforeCurrentToken() && at(LPAR)) parseValueArgumentList(); parseCallWithClosure(); } - else return false; + else { + typeArgumentList.rollbackTo(); + return false; + } } else { return false; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java index a490e8e261d..409e4e8264f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -396,7 +396,7 @@ public class JetParsing extends AbstractJetParsing { typeReference.done(TYPE_REFERENCE); reference.done(CONSTRUCTOR_CALLEE); - parseTypeArgumentList(-1); + parseTypeArgumentList(); if (at(LPAR)) { myExpressionParsing.parseValueArgumentList(); @@ -1295,11 +1295,17 @@ public class JetParsing extends AbstractJetParsing { * : typeDescriptor "?" */ public void parseTypeRef() { - PsiBuilder.Marker typeRefMarker = parseTypeRefContents(); + parseTypeRef(TokenSet.EMPTY); + } + + public void parseTypeRef(TokenSet extraRecoverySet) { + PsiBuilder.Marker typeRefMarker = parseTypeRefContents(extraRecoverySet); typeRefMarker.done(TYPE_REFERENCE); } - private PsiBuilder.Marker parseTypeRefContents() { + // The extraRecoverySet is needed for the foo(bar(z)) case, to tell whether we should stop + // on expression-indicating symbols or not + private PsiBuilder.Marker parseTypeRefContents(TokenSet extraRecoverySet) { // Disabling token merge is required for cases like // Int?.(Foo) -> Bar // we don't support this case now @@ -1318,7 +1324,7 @@ public class JetParsing extends AbstractJetParsing { // This may be a function parameter list or just a prenthesized type advance(); // LPAR - parseTypeRefContents().drop(); // parenthesized types, no reference element around it is needed + parseTypeRefContents(TokenSet.EMPTY).drop(); // parenthesized types, no reference element around it is needed if (at(RPAR)) { advance(); // RPAR @@ -1350,7 +1356,7 @@ public class JetParsing extends AbstractJetParsing { else { errorWithRecovery("Type expected", TokenSet.orSet(TOPLEVEL_OBJECT_FIRST, - TokenSet.create(EQ, COMMA, GT, RBRACKET, DOT, RPAR, RBRACE, LBRACE, SEMICOLON))); + TokenSet.create(EQ, COMMA, GT, RBRACKET, DOT, RPAR, RBRACE, LBRACE, SEMICOLON), extraRecoverySet)); } while (at(QUEST)) { @@ -1409,7 +1415,7 @@ public class JetParsing extends AbstractJetParsing { break; } - parseTypeArgumentList(-1); + parseTypeArgumentList(); if (!at(DOT)) { break; } @@ -1446,11 +1452,18 @@ public class JetParsing extends AbstractJetParsing { /* * (optionalProjection type){","} */ - public PsiBuilder.Marker parseTypeArgumentList(int expectedGtOffset) { + public PsiBuilder.Marker parseTypeArgumentList() { if (!at(LT)) return null; PsiBuilder.Marker list = mark(); + tryParseTypeArgumentList(TokenSet.EMPTY); + + list.done(TYPE_ARGUMENT_LIST); + return list; + } + + public boolean tryParseTypeArgumentList(TokenSet extraRecoverySet) { myBuilder.disableNewlines(); advance(); // LT @@ -1465,27 +1478,24 @@ public class JetParsing extends AbstractJetParsing { if (at(MUL)) { advance(); // MUL - } else { - parseTypeRef(); + } + else { + parseTypeRef(extraRecoverySet); } projection.done(TYPE_PROJECTION); if (!at(COMMA)) break; advance(); // COMMA } - if (expectedGtOffset >= 0 && myBuilder.getCurrentOffset() < expectedGtOffset) { - final PsiBuilder.Marker error = mark(); - while (myBuilder.getCurrentOffset() < expectedGtOffset) { - advance(); - } - error.error("Expecting a '>'"); + boolean atGT = at(GT); + if (!atGT) { + error("Expecting a '>'"); + } + else { + advance(); // GT } - - expect(GT, "Expecting a '>'"); myBuilder.restoreNewlinesState(); - - list.done(TYPE_ARGUMENT_LIST); - return list; + return atGT; } private void parseModifierListWithShortAnnotations(JetNodeType modifierList, TokenSet lookFor, TokenSet stopAt) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index c695c320db3..581a7b5d623 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -22,8 +22,8 @@ import com.google.common.collect.Sets; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; -import javax.inject.Inject; import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl; @@ -40,6 +40,7 @@ import org.jetbrains.jet.lang.types.lang.JetStandardClasses; import org.jetbrains.jet.lexer.JetToken; import org.jetbrains.jet.lexer.JetTokens; +import javax.inject.Inject; import java.util.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*; @@ -632,6 +633,9 @@ public class CallResolver { if (typeReference != null) { typeArguments.add(typeResolver.resolveType(scope, typeReference, temporaryTrace, true)); } + else { + typeArguments.add(ErrorUtils.createErrorType("Star projection in a call")); + } } int expectedTypeArgumentCount = candidate.getTypeParameters().size(); if (expectedTypeArgumentCount == jetTypeArguments.size()) { @@ -731,7 +735,13 @@ public class CallResolver { } for (JetTypeProjection typeProjection : call.getTypeArguments()) { - typeResolver.resolveType(scope, typeProjection.getTypeReference(), trace, true); + JetTypeReference typeReference = typeProjection.getTypeReference(); + if (typeReference == null) { + trace.report(Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(typeProjection)); + } + else { + typeResolver.resolveType(scope, typeReference, trace, true); + } } } @@ -958,8 +968,9 @@ public class CallResolver { TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i); JetType typeArgument = typeArguments.get(i); JetTypeReference typeReference = jetTypeArguments.get(i).getTypeReference(); - assert typeReference != null; - descriptorResolver.checkBounds(typeReference, typeArgument, typeParameterDescriptor, substitutor, trace); + if (typeReference != null) { + descriptorResolver.checkBounds(typeReference, typeArgument, typeParameterDescriptor, substitutor, trace); + } } } diff --git a/compiler/testData/diagnostics/tests/StarsInFunctionCalls.jet b/compiler/testData/diagnostics/tests/StarsInFunctionCalls.jet new file mode 100644 index 00000000000..dc3f7be47bb --- /dev/null +++ b/compiler/testData/diagnostics/tests/StarsInFunctionCalls.jet @@ -0,0 +1,13 @@ +fun getT() {} +fun getTT() {} +fun getTTT(x : Any) {} +fun foo(a : Any?) {} + +open fun main() { + getT<*>() + ggetT<*>() + getTT<*, *>() + getTT<*, Int>() + getTT*>() + foo(getTTT*, Int>(1)) +} diff --git a/compiler/testData/psi/FunctionCalls.jet b/compiler/testData/psi/FunctionCalls.jet index b3815710d1a..bddd92df5c7 100644 --- a/compiler/testData/psi/FunctionCalls.jet +++ b/compiler/testData/psi/FunctionCalls.jet @@ -27,4 +27,9 @@ fun foo() { f(foo(a)) f(foo(a)) f(foo(a)) + f(foo(a)) + f(foo(a)) + f(foo(a)) + f(foo(a)) + foo<*>() } \ No newline at end of file diff --git a/compiler/testData/psi/FunctionCalls.txt b/compiler/testData/psi/FunctionCalls.txt index b008b1afe86..ded66195cb9 100644 --- a/compiler/testData/psi/FunctionCalls.txt +++ b/compiler/testData/psi/FunctionCalls.txt @@ -327,5 +327,167 @@ JetFile: FunctionCalls.jet PsiElement(IDENTIFIER)('a') PsiElement(RPAR)(')') PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('f') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + OPERATION_REFERENCE + PsiElement(LT)('<') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_ARGUMENT + BINARY_EXPRESSION + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(PLUS)('+') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('2') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_ARGUMENT + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + OPERATION_REFERENCE + PsiElement(GT)('>') + PARENTHESIZED + PsiElement(LPAR)('(') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(RPAR)(')') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('f') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + OPERATION_REFERENCE + PsiElement(LT)('<') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_ARGUMENT + BINARY_EXPRESSION + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(MUL)('*') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('2') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_ARGUMENT + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + OPERATION_REFERENCE + PsiElement(GT)('>') + PARENTHESIZED + PsiElement(LPAR)('(') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(RPAR)(')') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('f') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + TYPE_PROJECTION + PsiElement(MUL)('*') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiElement(GT)('>') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(RPAR)(')') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('f') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + OPERATION_REFERENCE + PsiElement(LT)('<') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_ARGUMENT + STRING_TEMPLATE + PsiElement(OPEN_QUOTE)('"') + PsiElement(CLOSING_QUOTE)('"') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_ARGUMENT + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + OPERATION_REFERENCE + PsiElement(GT)('>') + PARENTHESIZED + PsiElement(LPAR)('(') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(RPAR)(')') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + PsiElement(MUL)('*') + PsiElement(GT)('>') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') PsiWhiteSpace('\n') PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/testData/psi/TypeExpressionAmbiguities_ERR.txt b/compiler/testData/psi/TypeExpressionAmbiguities_ERR.txt index 76c13957cc5..5da65ed6b83 100644 --- a/compiler/testData/psi/TypeExpressionAmbiguities_ERR.txt +++ b/compiler/testData/psi/TypeExpressionAmbiguities_ERR.txt @@ -29,24 +29,19 @@ JetFile: TypeExpressionAmbiguities_ERR.jet PsiElement(LPAR)('(') PsiElement(RPAR)(')') PsiWhiteSpace('\n ') - CALL_EXPRESSION + BINARY_EXPRESSION REFERENCE_EXPRESSION PsiElement(IDENTIFIER)('fooo') - TYPE_ARGUMENT_LIST + OPERATION_REFERENCE PsiElement(LT)('<') - TYPE_PROJECTION - TYPE_REFERENCE - NULLABLE_TYPE - USER_TYPE - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('Double') - PsiElement(QUEST)('?') - PsiErrorElement:Expecting a '>' - PsiElement(IDENTIFIER)('addddd') - PsiElement(GT)('>') - VALUE_ARGUMENT_LIST - PsiElement(LPAR)('(') - PsiElement(RPAR)(')') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Double') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(QUEST)('?') + PsiElement(IDENTIFIER)('addddd') + PsiElement(GT)('>') + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') PsiWhiteSpace('\n ') CALL_EXPRESSION REFERENCE_EXPRESSION