Revert "KT-8263: Conditional operators are not parsed correctly"
This reverts commit 85800b4f9f.
This commit is contained in:
@@ -149,8 +149,6 @@ public interface KtNodeTypes {
|
||||
IElementType CLASS_LITERAL_EXPRESSION = new KtNodeType("CLASS_LITERAL_EXPRESSION", KtClassLiteralExpression.class);
|
||||
IElementType SAFE_ACCESS_EXPRESSION = new KtNodeType("SAFE_ACCESS_EXPRESSION", KtSafeQualifiedExpression.class);
|
||||
|
||||
IElementType TYPE_ARGUMENT_LIST_LIKE_EXPRESSION = new IElementType("TYPE_ARGUMENT_LIST_LIKE_EXPRESSION", null);
|
||||
|
||||
IElementType OBJECT_LITERAL = new KtNodeType("OBJECT_LITERAL", KtObjectLiteralExpression.class);
|
||||
|
||||
IElementType WHEN = new KtNodeType("WHEN", KtWhenExpression.class);
|
||||
|
||||
@@ -59,17 +59,20 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static final TokenSet STRONG_TYPE_ARGUMENT_LIST_POSTFIX_INDICATORS = TokenSet.orSet(
|
||||
TokenSet.create(COLONCOLON, QUEST, LBRACKET), Precedence.POSTFIX.getOperations()
|
||||
);
|
||||
private static final TokenSet WEAK_TYPE_ARGUMENT_LIST_POSTFIX_INDICATORS = TokenSet.create(
|
||||
RBRACKET, RBRACE, RPAR, EQ, COLON, SEMICOLON, COMMA,
|
||||
|
||||
EQEQEQ, EXCLEQEQEQ, EQEQ, EXCLEQ, ELVIS, AS_KEYWORD, IS_KEYWORD, NOT_IS, NOT_IN, RANGE, RANGE_UNTIL, ARROW,
|
||||
|
||||
PACKAGE_KEYWORD, CLASS_KEYWORD, INTERFACE_KEYWORD, OBJECT_KEYWORD, TYPE_ALIAS_KEYWORD, SUPER_KEYWORD, VAL_KEYWORD,
|
||||
VAR_KEYWORD, FUN_KEYWORD, RETURN_KEYWORD, FOR_KEYWORD, WHILE_KEYWORD, DO_KEYWORD, BREAK_KEYWORD, CONTINUE_KEYWORD,
|
||||
THROW_KEYWORD
|
||||
private static final TokenSet TYPE_ARGUMENT_LIST_STOPPERS = TokenSet.create(
|
||||
INTEGER_LITERAL, FLOAT_LITERAL, CHARACTER_LITERAL, OPEN_QUOTE,
|
||||
PACKAGE_KEYWORD, AS_KEYWORD, TYPE_ALIAS_KEYWORD, INTERFACE_KEYWORD, CLASS_KEYWORD, THIS_KEYWORD, VAL_KEYWORD, VAR_KEYWORD,
|
||||
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, EXCLEXCL,
|
||||
// MUL,
|
||||
PLUS, MINUS, EXCL, DIV, PERC, LTEQ,
|
||||
// TODO GTEQ, foo<bar, baz>=x
|
||||
EQEQEQ, EXCLEQEQEQ, EQEQ, EXCLEQ, ANDAND, OROR, SAFE_ACCESS, ELVIS,
|
||||
SEMICOLON, RANGE, RANGE_UNTIL, EQ, MULTEQ, DIVEQ, PERCEQ, PLUSEQ, MINUSEQ, NOT_IN, NOT_IS,
|
||||
COLONCOLON,
|
||||
COLON
|
||||
);
|
||||
|
||||
/*package*/ static final TokenSet EXPRESSION_FIRST = TokenSet.create(
|
||||
@@ -155,7 +158,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
|
||||
AS(AS_KEYWORD, AS_SAFE) {
|
||||
@Override
|
||||
public IElementType parseRightHandSide(IElementType operation, KotlinExpressionParsing parser) {
|
||||
parser.myKotlinParsing.parseTypeRefWithoutIntersections(/* partOfExpression */ true);
|
||||
parser.myKotlinParsing.parseTypeRefWithoutIntersections();
|
||||
return BINARY_WITH_TYPE;
|
||||
}
|
||||
|
||||
@@ -174,7 +177,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
|
||||
@Override
|
||||
public IElementType parseRightHandSide(IElementType operation, KotlinExpressionParsing parser) {
|
||||
if (operation == IS_KEYWORD || operation == NOT_IS) {
|
||||
parser.myKotlinParsing.parseTypeRefWithoutIntersections(/* partOfExpression */ true);
|
||||
parser.myKotlinParsing.parseTypeRefWithoutIntersections();
|
||||
return IS_EXPRESSION;
|
||||
}
|
||||
|
||||
@@ -389,7 +392,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
|
||||
|
||||
if (at(LT)) {
|
||||
PsiBuilder.Marker typeArgumentList = mark();
|
||||
if (parseCallSuffixTypeArgumentList()) {
|
||||
if (myKotlinParsing.tryParseTypeArgumentList(TYPE_ARGUMENT_LIST_STOPPERS)) {
|
||||
typeArgumentList.error("Type arguments are not allowed");
|
||||
}
|
||||
else {
|
||||
@@ -397,7 +400,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
|
||||
}
|
||||
}
|
||||
|
||||
if (isAtValueArgumentList()) {
|
||||
if (at(LPAR) && !myBuilder.newlineBeforeCurrentToken()) {
|
||||
PsiBuilder.Marker lpar = mark();
|
||||
parseCallSuffix();
|
||||
lpar.error("This syntax is reserved for future use; to call a reference, enclose it in parentheses: (foo::bar)(args)");
|
||||
@@ -481,141 +484,35 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
|
||||
|
||||
/*
|
||||
* callSuffix
|
||||
* : typeArguments? valueArguments? annotatedLambda*
|
||||
* : typeArguments? valueArguments annotatedLambda
|
||||
* : typeArguments annotatedLambda
|
||||
* ;
|
||||
*/
|
||||
private boolean parseCallSuffix() {
|
||||
if (at(LT) && parseCallSuffixTypeArgumentList()) {
|
||||
if (at(LPAR) && !myBuilder.newlineBeforeCurrentToken()) parseValueArgumentList();
|
||||
parseCallWithClosure();
|
||||
|
||||
return true;
|
||||
if (parseCallWithClosure()) {
|
||||
// do nothing
|
||||
}
|
||||
else if (at(LPAR)) {
|
||||
parseValueArgumentList();
|
||||
parseCallWithClosure();
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (parseCallWithClosure()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean parseCallSuffixTypeArgumentList() {
|
||||
PsiBuilder.Marker typeArgumentList = mark();
|
||||
|
||||
KotlinParsing.TypeArgumentListKind kind = myKotlinParsing.tryParseTypeArgumentList();
|
||||
|
||||
// If the parsed section did not fulfill the criteria of a type argument list or
|
||||
// if there's no indication of an intended call suffix, drop the type argument list.
|
||||
if (kind == KotlinParsing.TypeArgumentListKind.NONE) {
|
||||
typeArgumentList.rollbackTo();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isAtTypeArgumentListPostfixIndicator()) {
|
||||
typeArgumentList.rollbackTo();
|
||||
|
||||
mark().done(TYPE_ARGUMENT_LIST_LIKE_EXPRESSION);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the parsed section could have been a faulty type argument type list, check
|
||||
// whether it could have also been parsed as the right-hand side of a comparison
|
||||
// expression correctly. If so, we have never had a faulty type argument list in
|
||||
// the first place, and therefor it must be dropped.
|
||||
if (kind == KotlinParsing.TypeArgumentListKind.FAULTY_TYPE_ARGUMENT_LIST) {
|
||||
// For better error highlighting we only try to produce a faulty type argument list, if
|
||||
// there are strong indicators. Otherwise, we would lean too much towards call suffixes
|
||||
// in cases like when typing "x < 0 && 1 > ", where the last element hasn't been typed
|
||||
// yet.
|
||||
if (!isAtStrongTypeArgumentListPostfixIndicator()) {
|
||||
typeArgumentList.rollbackTo();
|
||||
|
||||
mark().done(TYPE_ARGUMENT_LIST_LIKE_EXPRESSION);
|
||||
return false;
|
||||
}
|
||||
|
||||
typeArgumentList.rollbackTo();
|
||||
|
||||
if (isAtConditionalExpression()) {
|
||||
mark().done(TYPE_ARGUMENT_LIST_LIKE_EXPRESSION);
|
||||
return false;
|
||||
}
|
||||
|
||||
typeArgumentList = mark();
|
||||
|
||||
myKotlinParsing.tryParseTypeArgumentList();
|
||||
}
|
||||
|
||||
// At this point we're sure that it's either a correct type argument list followed
|
||||
// by some indication of a call suffix or that it's faulty type argument list that
|
||||
// is definitely not a correct right-hand side of an expression and is followed by
|
||||
// a strong indication of a call suffix.
|
||||
|
||||
typeArgumentList.done(TYPE_ARGUMENT_LIST);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isAtTypeArgumentListPostfixIndicator() {
|
||||
return isAtStrongTypeArgumentListPostfixIndicator() || isAtWeakTypeArgumentListPostfixIndicator();
|
||||
}
|
||||
|
||||
private boolean isAtStrongTypeArgumentListPostfixIndicator() {
|
||||
// The start of a value argument list or an annotated lambda indicates a type argument list.
|
||||
// <...>( <...>{ <...>@identifier{ <...>identifier@{ <...>[
|
||||
// Postfix expression are usually not applied to non-null boolean comparisons.
|
||||
// <...>:: <...>? <...>. <...>?. <...>!! <...>++ <...>--
|
||||
return isAtValueArgumentList() || isAtAnnotatedLambda() || atSet(STRONG_TYPE_ARGUMENT_LIST_POSTFIX_INDICATORS);
|
||||
}
|
||||
|
||||
private boolean isAtWeakTypeArgumentListPostfixIndicator() {
|
||||
// Line breaks are only available outside of value argument list. This is an incomplete line of code.
|
||||
// <...>↵
|
||||
// Other limiting tokens are also a likely indicator of an indented function call.
|
||||
// <...>) <...>] <...>} <...>, <...>: <...>=
|
||||
// Operators are unlikely to be applied to non-null booleans.
|
||||
// <...>== <...>!= <...>=== <...>!== <...> as <...> is <...> in
|
||||
// Hard keywords hint towards some formatting issue where line breaks are missing
|
||||
// <...>fun <...>var <...>var <...>object
|
||||
return myBuilder.newlineBeforeCurrentToken() || atSet(WEAK_TYPE_ARGUMENT_LIST_POSTFIX_INDICATORS);
|
||||
}
|
||||
|
||||
boolean isAtConditionalExpression() {
|
||||
assert _at(LT) : "caller must check that current token is LT";
|
||||
|
||||
PsiBuilder.Marker marker = mark();
|
||||
|
||||
advance(); // LT
|
||||
|
||||
boolean hasNoErrors;
|
||||
|
||||
do {
|
||||
PsiBuilder.Marker errorScope = mark();
|
||||
|
||||
parseExpression();
|
||||
|
||||
hasNoErrors = !myBuilder.hasErrorsAfter(errorScope);
|
||||
errorScope.drop();
|
||||
|
||||
if (!hasNoErrors) break;
|
||||
|
||||
if (at(COMMA)) {
|
||||
advance();
|
||||
else if (at(LT)) {
|
||||
PsiBuilder.Marker typeArgumentList = mark();
|
||||
if (myKotlinParsing.tryParseTypeArgumentList(TYPE_ARGUMENT_LIST_STOPPERS)) {
|
||||
typeArgumentList.done(TYPE_ARGUMENT_LIST);
|
||||
if (!myBuilder.newlineBeforeCurrentToken() && at(LPAR)) parseValueArgumentList();
|
||||
parseCallWithClosure();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
typeArgumentList.rollbackTo();
|
||||
return false;
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
marker.rollbackTo();
|
||||
|
||||
return hasNoErrors;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -687,24 +584,6 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isAtAnnotatedLambda() {
|
||||
// "{"
|
||||
if (_at(LBRACE)) {
|
||||
return true;
|
||||
}
|
||||
// IDENTIFIER "@" "{"
|
||||
else if (_at(IDENTIFIER) && myBuilder.rawLookup(1) == AT && myBuilder.rawLookup(2) == LBRACE) {
|
||||
return true;
|
||||
}
|
||||
// "@"
|
||||
else if (_at(AT)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void doneOrDrop(
|
||||
@NotNull PsiBuilder.Marker marker,
|
||||
@NotNull IElementType type,
|
||||
@@ -1096,7 +975,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
|
||||
error("Expecting a type");
|
||||
}
|
||||
else {
|
||||
myKotlinParsing.parseTypeRef(/* partOfExpression */ false);
|
||||
myKotlinParsing.parseTypeRef();
|
||||
}
|
||||
condition.done(WHEN_CONDITION_IS_PATTERN);
|
||||
}
|
||||
@@ -1369,7 +1248,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
|
||||
|
||||
if (at(COLON)) {
|
||||
advance(); // COLON
|
||||
myKotlinParsing.parseTypeRef(TokenSet.create(ARROW, COMMA), /* partOfExpression */ false);
|
||||
myKotlinParsing.parseTypeRef(TokenSet.create(ARROW, COMMA));
|
||||
}
|
||||
parameter.done(VALUE_PARAMETER);
|
||||
|
||||
@@ -1595,7 +1474,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
|
||||
|
||||
if (at(COLON)) {
|
||||
advance(); // COLON
|
||||
myKotlinParsing.parseTypeRef(TokenSet.create(IN_KEYWORD), /* partOfExpression */ false);
|
||||
myKotlinParsing.parseTypeRef(TokenSet.create(IN_KEYWORD));
|
||||
}
|
||||
}
|
||||
parameter.done(VALUE_PARAMETER);
|
||||
@@ -1912,7 +1791,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
|
||||
}
|
||||
|
||||
/*
|
||||
* "super" ("<" type ">")? label?
|
||||
* "this" ("<" type ">")? label?
|
||||
*/
|
||||
private void parseSuperExpression() {
|
||||
assert _at(SUPER_KEYWORD);
|
||||
@@ -1929,7 +1808,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
|
||||
myBuilder.disableNewlines();
|
||||
advance(); // LT
|
||||
|
||||
myKotlinParsing.parseTypeRef(/* partOfExpression */ false);
|
||||
myKotlinParsing.parseTypeRef();
|
||||
|
||||
if (at(GT)) {
|
||||
advance(); // GT
|
||||
@@ -1987,10 +1866,6 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
|
||||
list.done(VALUE_ARGUMENT_LIST);
|
||||
}
|
||||
|
||||
private boolean isAtValueArgumentList() {
|
||||
return _at(LPAR) && !myBuilder.newlineBeforeCurrentToken();
|
||||
}
|
||||
|
||||
/*
|
||||
* (SimpleName "=")? "*"? element
|
||||
*/
|
||||
|
||||
@@ -65,21 +65,6 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
FILE_KEYWORD, FIELD_KEYWORD, GET_KEYWORD, SET_KEYWORD, PROPERTY_KEYWORD,
|
||||
RECEIVER_KEYWORD, PARAM_KEYWORD, SETPARAM_KEYWORD, DELEGATE_KEYWORD);
|
||||
|
||||
private static final TokenSet TYPE_ARGUMENT_LIST_RECOVERY_SET = TokenSet.create(
|
||||
INTEGER_LITERAL, FLOAT_LITERAL, CHARACTER_LITERAL, OPEN_QUOTE,
|
||||
PACKAGE_KEYWORD, AS_KEYWORD, TYPE_ALIAS_KEYWORD, INTERFACE_KEYWORD, CLASS_KEYWORD, THIS_KEYWORD, VAL_KEYWORD, VAR_KEYWORD,
|
||||
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, EXCLEXCL,
|
||||
// MUL,
|
||||
PLUS, MINUS, EXCL, DIV, PERC, LTEQ,
|
||||
GTEQ, GT, EQEQEQ, EXCLEQEQEQ, EQEQ, EXCLEQ, ANDAND, OROR, SAFE_ACCESS, ELVIS,
|
||||
SEMICOLON, RANGE, RANGE_UNTIL, EQ, MULTEQ, DIVEQ, PERCEQ, PLUSEQ, MINUSEQ, NOT_IN, NOT_IS,
|
||||
COLONCOLON,
|
||||
COLON
|
||||
);
|
||||
|
||||
static KotlinParsing createForTopLevel(SemanticWhitespaceAwarePsiBuilder builder) {
|
||||
KotlinParsing kotlinParsing = new KotlinParsing(builder);
|
||||
kotlinParsing.myExpressionParsing = new KotlinExpressionParsing(builder, kotlinParsing);
|
||||
@@ -145,7 +130,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
|
||||
void parseTypeCodeFragment() {
|
||||
PsiBuilder.Marker marker = mark();
|
||||
parseTypeRef(/* partOfExpression */ false);
|
||||
parseTypeRef();
|
||||
|
||||
checkForUnexpectedSymbols();
|
||||
|
||||
@@ -675,7 +660,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
if (myExpressionParsing.isAtLabelDefinitionOrMissingIdentifier()) {
|
||||
myExpressionParsing.parseLabelDefinition();
|
||||
}
|
||||
parseTypeRef(/* partOfExpression */ false);
|
||||
parseTypeRef();
|
||||
contextReceiver.done(CONTEXT_RECEIVER);
|
||||
}
|
||||
|
||||
@@ -900,11 +885,11 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
|
||||
PsiBuilder.Marker reference = mark();
|
||||
PsiBuilder.Marker typeReference = mark();
|
||||
parseUserType(/* allowSimpleIntersectionTypes */ false, /* partOfExpression */ false);
|
||||
parseUserType(/* allowSimpleIntersectionTypes */ false);
|
||||
typeReference.done(TYPE_REFERENCE);
|
||||
reference.done(CONSTRUCTOR_CALLEE);
|
||||
|
||||
parseTypeArgumentList(/* partOfExpression */ false);
|
||||
parseTypeArgumentList();
|
||||
|
||||
boolean whitespaceAfterAnnotation = WHITE_SPACE_OR_COMMENT_BIT_SET.contains(myBuilder.rawLookup(-1));
|
||||
boolean shouldBeParsedNextAsFunctionalType = at(LPAR) && whitespaceAfterAnnotation && mode.withSignificantWhitespaceBeforeArguments;
|
||||
@@ -1387,7 +1372,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
|
||||
expect(EQ, "Expecting '='", TokenSet.orSet(TOP_LEVEL_DECLARATION_FIRST, TokenSet.create(SEMICOLON)));
|
||||
|
||||
parseTypeRef(/* partOfExpression */ false);
|
||||
parseTypeRef();
|
||||
|
||||
consumeIf(SEMICOLON);
|
||||
|
||||
@@ -1461,7 +1446,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
noTypeReference = false;
|
||||
PsiBuilder.Marker type = mark();
|
||||
advance(); // COLON
|
||||
parseTypeRef(/* partOfExpression */ false);
|
||||
parseTypeRef();
|
||||
errorIf(type, multiDeclaration, "Type annotations are not allowed on destructuring declarations");
|
||||
}
|
||||
|
||||
@@ -1564,7 +1549,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
|
||||
if (at(COLON)) {
|
||||
advance(); // COLON
|
||||
parseTypeRef(follow, /* partOfExpression */ false);
|
||||
parseTypeRef(follow);
|
||||
}
|
||||
property.done(DESTRUCTURING_DECLARATION_ENTRY);
|
||||
|
||||
@@ -1660,7 +1645,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
|
||||
if (at(COLON)) {
|
||||
advance(); // COLON
|
||||
parseTypeRef(/* partOfExpression */ false);
|
||||
parseTypeRef();
|
||||
}
|
||||
setterParameter.done(VALUE_PARAMETER);
|
||||
if (at(COMMA)) {
|
||||
@@ -1680,7 +1665,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
if (at(COLON)) {
|
||||
advance();
|
||||
|
||||
parseTypeRef(/* partOfExpression */ false);
|
||||
parseTypeRef();
|
||||
}
|
||||
|
||||
if (propertyComponentKind != PropertyComponentKind.FIELD) {
|
||||
@@ -1777,7 +1762,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
if (at(COLON)) {
|
||||
advance(); // COLON
|
||||
|
||||
parseTypeRef(/* partOfExpression */ false);
|
||||
parseTypeRef();
|
||||
}
|
||||
|
||||
boolean functionContractOccurred = parseFunctionContract();
|
||||
@@ -1820,7 +1805,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
|
||||
if (!receiverPresent) return false;
|
||||
|
||||
createTruncatedBuilder(lastDot).parseTypeRefWithoutIntersections(/* partOfExpression */ false);
|
||||
createTruncatedBuilder(lastDot).parseTypeRefWithoutIntersections();
|
||||
|
||||
if (atSet(RECEIVER_TYPE_TERMINATORS)) {
|
||||
advance(); // expectation
|
||||
@@ -1992,7 +1977,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
private void parseDelegationSpecifier() {
|
||||
PsiBuilder.Marker delegator = mark();
|
||||
PsiBuilder.Marker reference = mark();
|
||||
parseTypeRef(/* partOfExpression */ false);
|
||||
parseTypeRef();
|
||||
|
||||
if (at(BY_KEYWORD)) {
|
||||
reference.drop();
|
||||
@@ -2103,7 +2088,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
|
||||
expect(COLON, "Expecting ':' before the upper bound", TokenSet.orSet(TokenSet.create(LBRACE, RBRACE), TYPE_REF_FIRST));
|
||||
|
||||
parseTypeRef(/* partOfExpression */ false);
|
||||
parseTypeRef();
|
||||
|
||||
constraint.done(TYPE_CONSTRAINT);
|
||||
}
|
||||
@@ -2135,7 +2120,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
|
||||
if (at(COLON)) {
|
||||
advance(); // COLON
|
||||
parseTypeRef(/* partOfExpression */ false);
|
||||
parseTypeRef();
|
||||
}
|
||||
|
||||
mark.done(TYPE_PARAMETER);
|
||||
@@ -2158,30 +2143,26 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
* : typeReference "?"
|
||||
* ;
|
||||
*/
|
||||
void parseTypeRef(boolean partOfExpression) {
|
||||
parseTypeRef(TokenSet.EMPTY, partOfExpression);
|
||||
void parseTypeRef() {
|
||||
parseTypeRef(TokenSet.EMPTY);
|
||||
}
|
||||
|
||||
void parseTypeRefWithoutIntersections(boolean partOfExpression) {
|
||||
parseTypeRef(TokenSet.EMPTY, partOfExpression, /* allowSimpleIntersectionTypes */ false);
|
||||
void parseTypeRefWithoutIntersections() {
|
||||
parseTypeRef(TokenSet.EMPTY, /* allowSimpleIntersectionTypes */ false);
|
||||
}
|
||||
|
||||
void parseTypeRef(TokenSet extraRecoverySet, boolean partOfExpression) {
|
||||
parseTypeRef(extraRecoverySet, partOfExpression, /* allowSimpleIntersectionTypes */ true);
|
||||
void parseTypeRef(TokenSet extraRecoverySet) {
|
||||
parseTypeRef(extraRecoverySet, /* allowSimpleIntersectionTypes */ true);
|
||||
}
|
||||
|
||||
private void parseTypeRef(TokenSet extraRecoverySet, boolean partOfExpression, boolean allowSimpleIntersectionTypes) {
|
||||
PsiBuilder.Marker typeRefMarker = parseTypeRefContents(extraRecoverySet, partOfExpression, allowSimpleIntersectionTypes);
|
||||
private void parseTypeRef(TokenSet extraRecoverySet, boolean allowSimpleIntersectionTypes) {
|
||||
PsiBuilder.Marker typeRefMarker = parseTypeRefContents(extraRecoverySet, allowSimpleIntersectionTypes);
|
||||
typeRefMarker.done(TYPE_REFERENCE);
|
||||
}
|
||||
|
||||
// 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,
|
||||
boolean partOfExpression,
|
||||
boolean allowSimpleIntersectionTypes
|
||||
) {
|
||||
private PsiBuilder.Marker parseTypeRefContents(TokenSet extraRecoverySet, boolean allowSimpleIntersectionTypes) {
|
||||
PsiBuilder.Marker typeRefMarker = mark();
|
||||
|
||||
parseTypeModifierList();
|
||||
@@ -2207,14 +2188,14 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
dynamicType.done(DYNAMIC_TYPE);
|
||||
}
|
||||
else if (at(IDENTIFIER) || at(PACKAGE_KEYWORD) || atParenthesizedMutableForPlatformTypes(0)) {
|
||||
parseUserType(allowSimpleIntersectionTypes, partOfExpression);
|
||||
parseUserType(allowSimpleIntersectionTypes);
|
||||
}
|
||||
else if (at(LPAR)) {
|
||||
PsiBuilder.Marker functionOrParenthesizedType = mark();
|
||||
|
||||
// This may be a function parameter list or just a parenthesized type
|
||||
advance(); // LPAR
|
||||
parseTypeRefContents(TokenSet.EMPTY, /* partOfExpression */ false, /* allowSimpleIntersectionTypes */ true).drop(); // parenthesized types, no reference element around it is needed
|
||||
parseTypeRefContents(TokenSet.EMPTY, /* allowSimpleIntersectionTypes */ true).drop(); // parenthesized types, no reference element around it is needed
|
||||
|
||||
if (at(RPAR) && lookahead(1) != ARROW) {
|
||||
// It's a parenthesized type
|
||||
@@ -2256,7 +2237,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
leftTypeRef.done(TYPE_REFERENCE);
|
||||
|
||||
advance(); // &
|
||||
parseTypeRef(extraRecoverySet, /* allowSimpleIntersectionTypes */ false, true /* partOfExpression */);
|
||||
parseTypeRef(extraRecoverySet, /* allowSimpleIntersectionTypes */ true);
|
||||
|
||||
intersectionType.done(INTERSECTION_TYPE);
|
||||
wasIntersection = true;
|
||||
@@ -2321,7 +2302,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
* - (Mutable)List<Foo>!
|
||||
* - Array<(out) Foo>!
|
||||
*/
|
||||
private void parseUserType(boolean allowSimpleIntersectionTypes, boolean partOfExpression) {
|
||||
private void parseUserType(boolean allowSimpleIntersectionTypes) {
|
||||
PsiBuilder.Marker userType = mark();
|
||||
|
||||
if (at(PACKAGE_KEYWORD)) {
|
||||
@@ -2344,7 +2325,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
break;
|
||||
}
|
||||
|
||||
parseTypeArgumentList(partOfExpression);
|
||||
parseTypeArgumentList();
|
||||
|
||||
recoverOnPlatformTypeSuffix();
|
||||
|
||||
@@ -2414,72 +2395,21 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
/*
|
||||
* (optionalProjection type){","}
|
||||
*/
|
||||
private void parseTypeArgumentList(boolean partOfExpression) {
|
||||
if (!at(LT)) return;
|
||||
private PsiBuilder.Marker parseTypeArgumentList() {
|
||||
if (!at(LT)) return null;
|
||||
|
||||
PsiBuilder.Marker typeArgumentList = mark();
|
||||
PsiBuilder.Marker list = mark();
|
||||
|
||||
TypeArgumentListKind kind = tryParseTypeArgumentList();
|
||||
tryParseTypeArgumentList(TokenSet.EMPTY);
|
||||
|
||||
if (kind == TypeArgumentListKind.NONE && partOfExpression) {
|
||||
typeArgumentList.rollbackTo();
|
||||
|
||||
mark().done(TYPE_ARGUMENT_LIST_LIKE_EXPRESSION);
|
||||
return;
|
||||
}
|
||||
|
||||
// Type argument lists that appear inside of expressions might also be comparisons:
|
||||
// some(a as Int < 3, y > z)
|
||||
if (kind == TypeArgumentListKind.FAULTY_TYPE_ARGUMENT_LIST && partOfExpression) {
|
||||
typeArgumentList.rollbackTo();
|
||||
|
||||
if (myExpressionParsing.isAtConditionalExpression()) {
|
||||
mark().done(TYPE_ARGUMENT_LIST_LIKE_EXPRESSION);
|
||||
return;
|
||||
}
|
||||
|
||||
typeArgumentList = mark();
|
||||
|
||||
tryParseTypeArgumentList();
|
||||
}
|
||||
|
||||
typeArgumentList.done(TYPE_ARGUMENT_LIST);
|
||||
list.done(TYPE_ARGUMENT_LIST);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to parse a section into a type argument list and reports how successful the attempt was.
|
||||
* <p>
|
||||
* The returned value of the method indicates to what degree the parsed section can be considered a type
|
||||
* argument list.
|
||||
* <p>
|
||||
* {@link TypeArgumentListKind#TYPE_ARGUMENT_LIST} states the section should most likely be considered as
|
||||
* a type argument list. This is the case, if any of the following conditions apply:
|
||||
* <ul>
|
||||
* <li> the type argument list contains no syntax errors.
|
||||
* <li> the type argument list is empty
|
||||
* </ul>
|
||||
* <p>
|
||||
* {@link TypeArgumentListKind#FAULTY_TYPE_ARGUMENT_LIST} indicates that the section may be considered as
|
||||
* a type argument list. This is the case, if any of the following conditions apply:
|
||||
* <ul>
|
||||
* <li> the sections contains syntax errors, but ends with a '>'
|
||||
* </ul>
|
||||
* <p>
|
||||
* {@link TypeArgumentListKind#NONE} indicates that the section must not be considered as a type argument
|
||||
* list. This is the case, if none of the above cases apply.
|
||||
*/
|
||||
TypeArgumentListKind tryParseTypeArgumentList() {
|
||||
assert _at(LT) : "caller must check that current token is LT";
|
||||
|
||||
PsiBuilder.Marker errorScope = mark();
|
||||
|
||||
boolean tryParseTypeArgumentList(TokenSet extraRecoverySet) {
|
||||
myBuilder.disableNewlines();
|
||||
advance(); // LT
|
||||
|
||||
// Even if the type argument list is empty, we still want to "try" to parse it in
|
||||
// order to get error highlighting for the missing type
|
||||
boolean empty = at(GT) || at(GTEQ);
|
||||
|
||||
while (true) {
|
||||
PsiBuilder.Marker projection = mark();
|
||||
|
||||
@@ -2493,46 +2423,25 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
advance(); // MUL
|
||||
}
|
||||
else {
|
||||
parseTypeRef(TYPE_ARGUMENT_LIST_RECOVERY_SET, /* partOfExpression */ false);
|
||||
parseTypeRef(extraRecoverySet);
|
||||
}
|
||||
projection.done(TYPE_PROJECTION);
|
||||
|
||||
if (!at(COMMA)) break;
|
||||
advance(); // COMMA
|
||||
if (at(GT) || at(GTEQ)) break;
|
||||
if (at(GT)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
myBuilder.disableJoiningComplexTokens();
|
||||
|
||||
boolean atGT = at(GT);
|
||||
|
||||
if (atGT) {
|
||||
advance(); // GT
|
||||
}
|
||||
else {
|
||||
if (!atGT) {
|
||||
error("Expecting a '>'");
|
||||
}
|
||||
|
||||
myBuilder.restoreJoiningComplexTokensState();
|
||||
|
||||
myBuilder.restoreNewlinesState();
|
||||
|
||||
boolean success = !myBuilder.hasErrorsAfter(errorScope);
|
||||
errorScope.drop();
|
||||
|
||||
if (success || empty) {
|
||||
return TypeArgumentListKind.TYPE_ARGUMENT_LIST;
|
||||
}
|
||||
else if (atGT) {
|
||||
return TypeArgumentListKind.FAULTY_TYPE_ARGUMENT_LIST;
|
||||
}
|
||||
else {
|
||||
return TypeArgumentListKind.NONE;
|
||||
advance(); // GT
|
||||
}
|
||||
}
|
||||
|
||||
public enum TypeArgumentListKind {
|
||||
TYPE_ARGUMENT_LIST, FAULTY_TYPE_ARGUMENT_LIST, NONE,
|
||||
myBuilder.restoreNewlinesState();
|
||||
return atGT;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2550,7 +2459,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
parseValueParameterList(true, /* typeRequired = */ true, TokenSet.EMPTY);
|
||||
|
||||
expect(ARROW, "Expecting '->' to specify return type of a function type", TYPE_REF_FIRST);
|
||||
parseTypeRef(/* partOfExpression */ false);
|
||||
parseTypeRef();
|
||||
|
||||
return functionType;
|
||||
}
|
||||
@@ -2590,7 +2499,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
if (!tryParseValueParameter(typeRequired)) {
|
||||
PsiBuilder.Marker valueParameter = mark();
|
||||
parseFunctionTypeValueParameterModifierList();
|
||||
parseTypeRef(/* partOfExpression */ false);
|
||||
parseTypeRef();
|
||||
closeDeclarationWithCommentBinders(valueParameter, VALUE_PARAMETER, false);
|
||||
}
|
||||
}
|
||||
@@ -2670,7 +2579,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
else {
|
||||
noErrors = false;
|
||||
}
|
||||
parseTypeRef(/* partOfExpression */ false);
|
||||
parseTypeRef();
|
||||
}
|
||||
else {
|
||||
expect(IDENTIFIER, "Parameter name expected", PARAMETER_NAME_RECOVERY_SET);
|
||||
@@ -2685,7 +2594,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
return false;
|
||||
}
|
||||
|
||||
parseTypeRef(/* partOfExpression */ false);
|
||||
parseTypeRef();
|
||||
}
|
||||
else if (typeRequired) {
|
||||
errorWithRecovery("Parameters must have type annotation", PARAMETER_NAME_RECOVERY_SET);
|
||||
|
||||
@@ -33,6 +33,4 @@ public interface SemanticWhitespaceAwarePsiBuilder extends PsiBuilder {
|
||||
void disableJoiningComplexTokens();
|
||||
|
||||
boolean isWhitespaceOrComment(@NotNull IElementType elementType);
|
||||
|
||||
boolean hasErrorsAfter(@NotNull PsiBuilder.Marker marker);
|
||||
}
|
||||
|
||||
-5
@@ -68,9 +68,4 @@ public class SemanticWhitespaceAwarePsiBuilderAdapter extends PsiBuilderAdapter
|
||||
public boolean isWhitespaceOrComment(@NotNull IElementType elementType) {
|
||||
return myBuilder.isWhitespaceOrComment(elementType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasErrorsAfter(@NotNull Marker marker) {
|
||||
return myBuilder.hasErrorsAfter(marker);
|
||||
}
|
||||
}
|
||||
|
||||
-6
@@ -202,10 +202,4 @@ public class SemanticWhitespaceAwarePsiBuilderImpl extends PsiBuilderAdapter imp
|
||||
}
|
||||
return getJoinedTokenType(super.lookAhead(steps), 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasErrorsAfter(@NotNull Marker marker) {
|
||||
assert delegateImpl != null : "PsiBuilderImpl not found";
|
||||
return delegateImpl.hasErrorsAfter(marker);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user