diff --git a/compiler/psi/src/org/jetbrains/kotlin/lexer/KtTokens.java b/compiler/psi/src/org/jetbrains/kotlin/lexer/KtTokens.java index 25f22772b7b..f665dd3770e 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/lexer/KtTokens.java +++ b/compiler/psi/src/org/jetbrains/kotlin/lexer/KtTokens.java @@ -57,7 +57,7 @@ public interface KtTokens { KtKeywordToken SUPER_KEYWORD = KtKeywordToken.keyword("super"); KtKeywordToken VAL_KEYWORD = KtKeywordToken.keyword("val"); KtKeywordToken VAR_KEYWORD = KtKeywordToken.keyword("var"); - KtKeywordToken FUN_KEYWORD = KtKeywordToken.keyword("fun"); + KtModifierKeywordToken FUN_KEYWORD = KtModifierKeywordToken.keywordModifier("fun"); KtKeywordToken FOR_KEYWORD = KtKeywordToken.keyword("for"); KtKeywordToken NULL_KEYWORD = KtKeywordToken.keyword("null"); KtKeywordToken TRUE_KEYWORD = KtKeywordToken.keyword("true"); @@ -229,7 +229,7 @@ public interface KtTokens { REIFIED_KEYWORD, COMPANION_KEYWORD, SEALED_KEYWORD, LATEINIT_KEYWORD, DATA_KEYWORD, INLINE_KEYWORD, NOINLINE_KEYWORD, TAILREC_KEYWORD, EXTERNAL_KEYWORD, ANNOTATION_KEYWORD, CROSSINLINE_KEYWORD, CONST_KEYWORD, OPERATOR_KEYWORD, INFIX_KEYWORD, SUSPEND_KEYWORD, - HEADER_KEYWORD, IMPL_KEYWORD, EXPECT_KEYWORD, ACTUAL_KEYWORD + HEADER_KEYWORD, IMPL_KEYWORD, EXPECT_KEYWORD, ACTUAL_KEYWORD, FUN_KEYWORD }; TokenSet MODIFIER_KEYWORDS = TokenSet.create(MODIFIER_KEYWORDS_ARRAY); diff --git a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java index 6c45c835914..20c52923f3f 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java +++ b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java @@ -51,9 +51,15 @@ public class KotlinParsing extends AbstractKotlinParsing { private static final TokenSet TYPE_REF_FIRST = TokenSet.create(LBRACKET, IDENTIFIER, LPAR, HASH, DYNAMIC_KEYWORD); private static final TokenSet RECEIVER_TYPE_TERMINATORS = TokenSet.create(DOT, SAFE_ACCESS); private static final TokenSet VALUE_PARAMETER_FIRST = - TokenSet.orSet(TokenSet.create(IDENTIFIER, LBRACKET, VAL_KEYWORD, VAR_KEYWORD), MODIFIER_KEYWORDS); + TokenSet.orSet( + TokenSet.create(IDENTIFIER, LBRACKET, VAL_KEYWORD, VAR_KEYWORD), + TokenSet.andNot(MODIFIER_KEYWORDS, TokenSet.create(FUN_KEYWORD)) + ); private static final TokenSet LAMBDA_VALUE_PARAMETER_FIRST = - TokenSet.orSet(TokenSet.create(IDENTIFIER, LBRACKET), MODIFIER_KEYWORDS); + TokenSet.orSet( + TokenSet.create(IDENTIFIER, LBRACKET), + TokenSet.andNot(MODIFIER_KEYWORDS, TokenSet.create(FUN_KEYWORD)) + ); private static final TokenSet SOFT_KEYWORDS_AT_MEMBER_START = TokenSet.create(CONSTRUCTOR_KEYWORD, INIT_KEYWORD); private static final TokenSet ANNOTATION_TARGETS = TokenSet.create( FILE_KEYWORD, FIELD_KEYWORD, GET_KEYWORD, SET_KEYWORD, PROPERTY_KEYWORD, @@ -585,6 +591,12 @@ public class KotlinParsing extends AbstractKotlinParsing { if (atSet(modifierKeywords)) { IElementType lookahead = lookahead(1); + + if (at(FUN_KEYWORD) && lookahead != INTERFACE_KEYWORD) { + marker.rollbackTo(); + return false; + } + if (lookahead != null && !noModifiersBefore.contains(lookahead)) { IElementType tt = tt(); if (tokenConsumer != null) { diff --git a/compiler/testData/psi/kotlinFunInterface_ERR.kt b/compiler/testData/psi/kotlinFunInterface_ERR.kt new file mode 100644 index 00000000000..5a57b783c13 --- /dev/null +++ b/compiler/testData/psi/kotlinFunInterface_ERR.kt @@ -0,0 +1,11 @@ +interface fun Foo + +fun private interface Foo + +fun @Bar interface Foo + +fun class Foo + +fun abstract class Foo + +fun object Foo \ No newline at end of file diff --git a/compiler/testData/psi/kotlinFunInterface_ERR.txt b/compiler/testData/psi/kotlinFunInterface_ERR.txt new file mode 100644 index 00000000000..aa1b6ebfdf0 --- /dev/null +++ b/compiler/testData/psi/kotlinFunInterface_ERR.txt @@ -0,0 +1,79 @@ +KtFile: kotlinFunInterface_ERR.kt + PACKAGE_DIRECTIVE + + IMPORT_LIST + + CLASS + PsiElement(interface)('interface') + PsiErrorElement:Name expected + + PsiWhiteSpace(' ') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('Foo') + PsiErrorElement:Expecting '(' + + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('private') + PsiErrorElement:Expecting '(' + + PsiWhiteSpace(' ') + CLASS + PsiElement(interface)('interface') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('Foo') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiErrorElement:Annotations are not allowed in this position + ANNOTATION_ENTRY + PsiElement(AT)('@') + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Bar') + PsiErrorElement:Expecting function name or receiver type + + PsiWhiteSpace(' ') + CLASS + PsiElement(interface)('interface') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('Foo') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiErrorElement:Expecting function name or receiver type + + PsiWhiteSpace(' ') + CLASS + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('Foo') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('abstract') + PsiErrorElement:Expecting '(' + + PsiWhiteSpace(' ') + CLASS + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('Foo') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiErrorElement:Expecting function name or receiver type + + PsiWhiteSpace(' ') + OBJECT_DECLARATION + PsiElement(object)('object') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('Foo') \ No newline at end of file diff --git a/compiler/testData/psi/validKotlinFunInterface.kt b/compiler/testData/psi/validKotlinFunInterface.kt new file mode 100644 index 00000000000..51d463625cd --- /dev/null +++ b/compiler/testData/psi/validKotlinFunInterface.kt @@ -0,0 +1,17 @@ +fun interface Foo + +fun interface Foo { + fun invoke() +} + +private fun interface Foo + +@Bar +fun interface Foo + +class TopLevel { + fun interface Foo +} + +fun +interface Foo \ No newline at end of file diff --git a/compiler/testData/psi/validKotlinFunInterface.txt b/compiler/testData/psi/validKotlinFunInterface.txt new file mode 100644 index 00000000000..276bbeebf41 --- /dev/null +++ b/compiler/testData/psi/validKotlinFunInterface.txt @@ -0,0 +1,85 @@ +KtFile: validKotlinFunInterface.kt + PACKAGE_DIRECTIVE + + IMPORT_LIST + + CLASS + MODIFIER_LIST + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(interface)('interface') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('Foo') + PsiWhiteSpace('\n\n') + CLASS + MODIFIER_LIST + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(interface)('interface') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('Foo') + PsiWhiteSpace(' ') + CLASS_BODY + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('invoke') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + CLASS + MODIFIER_LIST + PsiElement(private)('private') + PsiWhiteSpace(' ') + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(interface)('interface') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('Foo') + PsiWhiteSpace('\n\n') + CLASS + MODIFIER_LIST + ANNOTATION_ENTRY + PsiElement(AT)('@') + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Bar') + PsiWhiteSpace('\n') + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(interface)('interface') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('Foo') + PsiWhiteSpace('\n\n') + CLASS + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('TopLevel') + PsiWhiteSpace(' ') + CLASS_BODY + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + CLASS + MODIFIER_LIST + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(interface)('interface') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('Foo') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + CLASS + MODIFIER_LIST + PsiElement(fun)('fun') + PsiWhiteSpace('\n') + PsiElement(interface)('interface') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('Foo') \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java index e5e88592f2c..29b7576aba3 100644 --- a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java @@ -450,6 +450,11 @@ public class ParsingTestGenerated extends AbstractParsingTest { runTest("compiler/testData/psi/InterfaceWithEnumKeyword.kt"); } + @TestMetadata("kotlinFunInterface_ERR.kt") + public void testKotlinFunInterface_ERR() throws Exception { + runTest("compiler/testData/psi/kotlinFunInterface_ERR.kt"); + } + @TestMetadata("Labels.kt") public void testLabels() throws Exception { runTest("compiler/testData/psi/Labels.kt"); @@ -715,6 +720,11 @@ public class ParsingTestGenerated extends AbstractParsingTest { runTest("compiler/testData/psi/UnsignedLiteral.kt"); } + @TestMetadata("validKotlinFunInterface.kt") + public void testValidKotlinFunInterface() throws Exception { + runTest("compiler/testData/psi/validKotlinFunInterface.kt"); + } + @TestMetadata("When.kt") public void testWhen() throws Exception { runTest("compiler/testData/psi/When.kt");