KT-555 Parse error for generic function invocation

#KT-555 Fixed
This commit is contained in:
Andrey Breslav
2012-03-14 12:51:21 +04:00
parent 7adcecb634
commit 8019357bd5
7 changed files with 245 additions and 69 deletions
@@ -53,7 +53,9 @@ public class JetExpressionParsing extends AbstractJetParsing {
FUN_KEYWORD, FOR_KEYWORD, NULL_KEYWORD, FUN_KEYWORD, FOR_KEYWORD, NULL_KEYWORD,
TRUE_KEYWORD, FALSE_KEYWORD, IS_KEYWORD, THROW_KEYWORD, RETURN_KEYWORD, BREAK_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, 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<bar, baz>=x // TODO GTEQ, foo<bar, baz>=x
EQEQEQ, EXCLEQEQEQ, EQEQ, EXCLEQ, ANDAND, OROR, SAFE_ACCESS, ELVIS, EQEQEQ, EXCLEQEQEQ, EQEQ, EXCLEQ, ANDAND, OROR, SAFE_ACCESS, ELVIS,
SEMICOLON, RANGE, EQ, MULTEQ, DIVEQ, PERCEQ, PLUSEQ, MINUSEQ, NOT_IN, NOT_IS, //HASH, 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); expression.done(SAFE_ACCESS_EXPRESSION);
} }
// else if (at(QUEST)) {
// advance(); // QUEST
//
// parseCallExpression();
//
// expression.done(PREDICATE_EXPRESSION);
// }
// else if (at(HASH)) { // else if (at(HASH)) {
// advance(); // HASH // advance(); // HASH
// //
@@ -426,31 +421,16 @@ public class JetExpressionParsing extends AbstractJetParsing {
parseCallWithClosure(); parseCallWithClosure();
} }
else if (at(LT)) { else if (at(LT)) {
// TODO: be (even) more clever PsiBuilder.Marker typeArgumentList = mark();
int gtPos = matchTokenStreamPredicate(new FirstBefore( if (myJetParsing.tryParseTypeArgumentList(TYPE_ARGUMENT_LIST_STOPPERS)) {
new At(GT), typeArgumentList.done(TYPE_ARGUMENT_LIST);
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);
if (!myBuilder.newlineBeforeCurrentToken() && at(LPAR)) parseValueArgumentList(); if (!myBuilder.newlineBeforeCurrentToken() && at(LPAR)) parseValueArgumentList();
parseCallWithClosure(); parseCallWithClosure();
} }
else return false; else {
typeArgumentList.rollbackTo();
return false;
}
} }
else { else {
return false; return false;
@@ -396,7 +396,7 @@ public class JetParsing extends AbstractJetParsing {
typeReference.done(TYPE_REFERENCE); typeReference.done(TYPE_REFERENCE);
reference.done(CONSTRUCTOR_CALLEE); reference.done(CONSTRUCTOR_CALLEE);
parseTypeArgumentList(-1); parseTypeArgumentList();
if (at(LPAR)) { if (at(LPAR)) {
myExpressionParsing.parseValueArgumentList(); myExpressionParsing.parseValueArgumentList();
@@ -1295,11 +1295,17 @@ public class JetParsing extends AbstractJetParsing {
* : typeDescriptor "?" * : typeDescriptor "?"
*/ */
public void parseTypeRef() { public void parseTypeRef() {
PsiBuilder.Marker typeRefMarker = parseTypeRefContents(); parseTypeRef(TokenSet.EMPTY);
}
public void parseTypeRef(TokenSet extraRecoverySet) {
PsiBuilder.Marker typeRefMarker = parseTypeRefContents(extraRecoverySet);
typeRefMarker.done(TYPE_REFERENCE); typeRefMarker.done(TYPE_REFERENCE);
} }
private PsiBuilder.Marker parseTypeRefContents() { // The extraRecoverySet is needed for the foo(bar<x, 1, y>(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 // Disabling token merge is required for cases like
// Int?.(Foo) -> Bar // Int?.(Foo) -> Bar
// we don't support this case now // 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 // This may be a function parameter list or just a prenthesized type
advance(); // LPAR 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)) { if (at(RPAR)) {
advance(); // RPAR advance(); // RPAR
@@ -1350,7 +1356,7 @@ public class JetParsing extends AbstractJetParsing {
else { else {
errorWithRecovery("Type expected", errorWithRecovery("Type expected",
TokenSet.orSet(TOPLEVEL_OBJECT_FIRST, 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)) { while (at(QUEST)) {
@@ -1409,7 +1415,7 @@ public class JetParsing extends AbstractJetParsing {
break; break;
} }
parseTypeArgumentList(-1); parseTypeArgumentList();
if (!at(DOT)) { if (!at(DOT)) {
break; break;
} }
@@ -1446,11 +1452,18 @@ public class JetParsing extends AbstractJetParsing {
/* /*
* (optionalProjection type){","} * (optionalProjection type){","}
*/ */
public PsiBuilder.Marker parseTypeArgumentList(int expectedGtOffset) { public PsiBuilder.Marker parseTypeArgumentList() {
if (!at(LT)) return null; if (!at(LT)) return null;
PsiBuilder.Marker list = mark(); PsiBuilder.Marker list = mark();
tryParseTypeArgumentList(TokenSet.EMPTY);
list.done(TYPE_ARGUMENT_LIST);
return list;
}
public boolean tryParseTypeArgumentList(TokenSet extraRecoverySet) {
myBuilder.disableNewlines(); myBuilder.disableNewlines();
advance(); // LT advance(); // LT
@@ -1465,27 +1478,24 @@ public class JetParsing extends AbstractJetParsing {
if (at(MUL)) { if (at(MUL)) {
advance(); // MUL advance(); // MUL
} else { }
parseTypeRef(); else {
parseTypeRef(extraRecoverySet);
} }
projection.done(TYPE_PROJECTION); projection.done(TYPE_PROJECTION);
if (!at(COMMA)) break; if (!at(COMMA)) break;
advance(); // COMMA advance(); // COMMA
} }
if (expectedGtOffset >= 0 && myBuilder.getCurrentOffset() < expectedGtOffset) { boolean atGT = at(GT);
final PsiBuilder.Marker error = mark(); if (!atGT) {
while (myBuilder.getCurrentOffset() < expectedGtOffset) { error("Expecting a '>'");
advance(); }
} else {
error.error("Expecting a '>'"); advance(); // GT
} }
expect(GT, "Expecting a '>'");
myBuilder.restoreNewlinesState(); myBuilder.restoreNewlinesState();
return atGT;
list.done(TYPE_ARGUMENT_LIST);
return list;
} }
private void parseModifierListWithShortAnnotations(JetNodeType modifierList, TokenSet lookFor, TokenSet stopAt) { private void parseModifierListWithShortAnnotations(JetNodeType modifierList, TokenSet lookFor, TokenSet stopAt) {
@@ -22,8 +22,8 @@ import com.google.common.collect.Sets;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.inject.Inject;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl; 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.JetToken;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
import javax.inject.Inject;
import java.util.*; import java.util.*;
import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*;
@@ -632,6 +633,9 @@ public class CallResolver {
if (typeReference != null) { if (typeReference != null) {
typeArguments.add(typeResolver.resolveType(scope, typeReference, temporaryTrace, true)); typeArguments.add(typeResolver.resolveType(scope, typeReference, temporaryTrace, true));
} }
else {
typeArguments.add(ErrorUtils.createErrorType("Star projection in a call"));
}
} }
int expectedTypeArgumentCount = candidate.getTypeParameters().size(); int expectedTypeArgumentCount = candidate.getTypeParameters().size();
if (expectedTypeArgumentCount == jetTypeArguments.size()) { if (expectedTypeArgumentCount == jetTypeArguments.size()) {
@@ -731,7 +735,13 @@ public class CallResolver {
} }
for (JetTypeProjection typeProjection : call.getTypeArguments()) { 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); TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i);
JetType typeArgument = typeArguments.get(i); JetType typeArgument = typeArguments.get(i);
JetTypeReference typeReference = jetTypeArguments.get(i).getTypeReference(); JetTypeReference typeReference = jetTypeArguments.get(i).getTypeReference();
assert typeReference != null; if (typeReference != null) {
descriptorResolver.checkBounds(typeReference, typeArgument, typeParameterDescriptor, substitutor, trace); descriptorResolver.checkBounds(typeReference, typeArgument, typeParameterDescriptor, substitutor, trace);
}
} }
} }
@@ -0,0 +1,13 @@
fun getT<T>() {}
fun getTT<A, B>() {}
fun getTTT<A, B, C>(<!UNUSED_PARAMETER!>x<!> : Any) {}
fun foo(<!UNUSED_PARAMETER!>a<!> : Any?) {}
open fun main() {
getT<<!PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT!>*<!>>()
<!UNRESOLVED_REFERENCE!>ggetT<!><<!PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT!>*<!>>()
getTT<<!PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT!>*<!>, <!PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT!>*<!>>()
getTT<<!PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT!>*<!>, Int>()
getTT<Int, <!PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT!>*<!>>()
foo(getTTT<Int, <!PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT!>*<!>, Int>(1))
}
+5
View File
@@ -27,4 +27,9 @@ fun foo() {
f(foo<a, b>(a)) f(foo<a, b>(a))
f(foo<a, 1, b>(a)) f(foo<a, 1, b>(a))
f(foo<a, (1 + 2), b>(a)) f(foo<a, (1 + 2), b>(a))
f(foo<a, 1 + 2, b>(a))
f(foo<a, 1 * 2, b>(a))
f(foo<a, *, b>(a))
f(foo<a, "", b>(a))
foo<*>()
} }
+162
View File
@@ -327,5 +327,167 @@ JetFile: FunctionCalls.jet
PsiElement(IDENTIFIER)('a') PsiElement(IDENTIFIER)('a')
PsiElement(RPAR)(')') PsiElement(RPAR)(')')
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') PsiWhiteSpace('\n')
PsiElement(RBRACE)('}') PsiElement(RBRACE)('}')
@@ -29,24 +29,19 @@ JetFile: TypeExpressionAmbiguities_ERR.jet
PsiElement(LPAR)('(') PsiElement(LPAR)('(')
PsiElement(RPAR)(')') PsiElement(RPAR)(')')
PsiWhiteSpace('\n ') PsiWhiteSpace('\n ')
CALL_EXPRESSION BINARY_EXPRESSION
REFERENCE_EXPRESSION REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('fooo') PsiElement(IDENTIFIER)('fooo')
TYPE_ARGUMENT_LIST OPERATION_REFERENCE
PsiElement(LT)('<') PsiElement(LT)('<')
TYPE_PROJECTION REFERENCE_EXPRESSION
TYPE_REFERENCE PsiElement(IDENTIFIER)('Double')
NULLABLE_TYPE PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line)
USER_TYPE PsiElement(QUEST)('?')
REFERENCE_EXPRESSION PsiElement(IDENTIFIER)('addddd')
PsiElement(IDENTIFIER)('Double') PsiElement(GT)('>')
PsiElement(QUEST)('?') PsiElement(LPAR)('(')
PsiErrorElement:Expecting a '>' PsiElement(RPAR)(')')
PsiElement(IDENTIFIER)('addddd')
PsiElement(GT)('>')
VALUE_ARGUMENT_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n ') PsiWhiteSpace('\n ')
CALL_EXPRESSION CALL_EXPRESSION
REFERENCE_EXPRESSION REFERENCE_EXPRESSION