From e6710b6fa22a1ec81f3934c070f602177aa8fdf8 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 21 Dec 2018 09:10:04 +0300 Subject: [PATCH] Add recovery for value parameter without type or name The case for KT-7237 belongs to /NoGTInTypeArguments test It was fixed implicitly: before it recovery was working but the name for the next parameter was attached to type argument list. After that change, parameter without name gets parsed correctly (with an error of course) ^KT-13731 Fixed ^KT-7237 Fixed --- .../kotlin/parsing/KotlinParsing.java | 14 + .../psi/recovery/NoGTInTypeArguments.kt | 9 + .../psi/recovery/NoGTInTypeArguments.txt | 314 ++++++++++++++++++ .../psi/recovery/valueParameterRecovery.kt | 5 + .../psi/recovery/valueParameterRecovery.txt | 108 ++++++ .../valueParameterRecoveryWithTypes.kt | 2 + .../valueParameterRecoveryWithTypes.txt | 101 ++++++ .../kotlin/parsing/ParsingTestGenerated.java | 15 + 8 files changed, 568 insertions(+) create mode 100644 compiler/testData/psi/recovery/NoGTInTypeArguments.kt create mode 100644 compiler/testData/psi/recovery/NoGTInTypeArguments.txt create mode 100644 compiler/testData/psi/recovery/valueParameterRecovery.kt create mode 100644 compiler/testData/psi/recovery/valueParameterRecovery.txt create mode 100644 compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.kt create mode 100644 compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.txt diff --git a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java index c06700c483f..0ae41c29bd8 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java +++ b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java @@ -2252,6 +2252,12 @@ public class KotlinParsing extends AbstractKotlinParsing { if (at(COMMA)) { advance(); // COMMA } + else if (at(COLON)) { + // recovery for the case "fun bar(x: Array : Int)" when we've just parsed "x: Array" + // error should be reported in the `parseValueParameter` call + //noinspection UnnecessaryContinue + continue; + } else { if (!at(RPAR)) error("Expecting comma or ')'"); if (!atSet(isFunctionTypeContents ? LAMBDA_VALUE_PARAMETER_FIRST : VALUE_PARAMETER_FIRST)) break; @@ -2322,6 +2328,14 @@ public class KotlinParsing extends AbstractKotlinParsing { if (at(COLON)) { advance(); // COLON + + if (at(IDENTIFIER) && lookahead(1) == COLON) { + // recovery for the case "fun foo(x: y: Int)" when we're at "y: " it's likely that this is a name of the next parameter, + // not a type reference of the current one + error("Type reference expected"); + return false; + } + parseTypeRef(); } else if (typeRequired) { diff --git a/compiler/testData/psi/recovery/NoGTInTypeArguments.kt b/compiler/testData/psi/recovery/NoGTInTypeArguments.kt new file mode 100644 index 00000000000..bd8376401a2 --- /dev/null +++ b/compiler/testData/psi/recovery/NoGTInTypeArguments.kt @@ -0,0 +1,9 @@ +fun foo1(x: List + IMPORT_LIST + + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo1') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('List') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('s') + PsiErrorElement:Expecting a '>' + + VALUE_PARAMETER + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('String') + PsiElement(RPAR)(')') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo2') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('List') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + PsiWhiteSpace(' ') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('s') + PsiErrorElement:Expecting a '>' + + VALUE_PARAMETER + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('String') + PsiElement(RPAR)(')') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo3') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('List') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(COMMA)(',') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(RPAR)(')') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo4') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('List') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(RPAR)(')') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo5') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('List') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(COMMA)(',') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo6') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('List') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo7') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('List') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(COMMA)(',') + TYPE_PROJECTION + TYPE_REFERENCE + PsiErrorElement:Type expected + + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('main') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/testData/psi/recovery/valueParameterRecovery.kt b/compiler/testData/psi/recovery/valueParameterRecovery.kt new file mode 100644 index 00000000000..fc9a23a8432 --- /dev/null +++ b/compiler/testData/psi/recovery/valueParameterRecovery.kt @@ -0,0 +1,5 @@ +fun foo(x: Int, y: z: Int) {} + +fun bar(x: y: Int, z: Int) {} + +fun baz(x: y: z: Int) {} diff --git a/compiler/testData/psi/recovery/valueParameterRecovery.txt b/compiler/testData/psi/recovery/valueParameterRecovery.txt new file mode 100644 index 00000000000..5c164239ae4 --- /dev/null +++ b/compiler/testData/psi/recovery/valueParameterRecovery.txt @@ -0,0 +1,108 @@ +KtFile: valueParameterRecovery.kt + PACKAGE_DIRECTIVE + + IMPORT_LIST + + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('y') + PsiElement(COLON)(':') + PsiErrorElement:Type reference expected + + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('z') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('bar') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiErrorElement:Type reference expected + + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('y') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('z') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('baz') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiErrorElement:Type reference expected + + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('y') + PsiElement(COLON)(':') + PsiErrorElement:Type reference expected + + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('z') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') diff --git a/compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.kt b/compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.kt new file mode 100644 index 00000000000..211b004ae07 --- /dev/null +++ b/compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.kt @@ -0,0 +1,2 @@ +fun foo(x: Array, : Int, w: Int) {} +fun bar(x: Array : Int, w: Int) {} diff --git a/compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.txt b/compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.txt new file mode 100644 index 00000000000..118beb8073d --- /dev/null +++ b/compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.txt @@ -0,0 +1,101 @@ +KtFile: valueParameterRecoveryWithTypes.kt + PACKAGE_DIRECTIVE + + IMPORT_LIST + + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Array') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(GT)('>') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiErrorElement:Parameter name expected + + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('w') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('bar') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Array') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(GT)('>') + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiErrorElement:Parameter name expected + + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('w') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') diff --git a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java index a5bb676d7d8..f24b758e123 100644 --- a/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/parsing/ParsingTestGenerated.java @@ -2148,6 +2148,11 @@ public class ParsingTestGenerated extends AbstractParsingTest { runTest("compiler/testData/psi/recovery/NoArrowInWhen.kt"); } + @TestMetadata("NoGTInTypeArguments.kt") + public void testNoGTInTypeArguments() throws Exception { + runTest("compiler/testData/psi/recovery/NoGTInTypeArguments.kt"); + } + @TestMetadata("PackageNewLineRecovery.kt") public void testPackageNewLineRecovery() throws Exception { runTest("compiler/testData/psi/recovery/PackageNewLineRecovery.kt"); @@ -2183,6 +2188,16 @@ public class ParsingTestGenerated extends AbstractParsingTest { runTest("compiler/testData/psi/recovery/ValueParameterNoTypeRecovery.kt"); } + @TestMetadata("valueParameterRecovery.kt") + public void testValueParameterRecovery() throws Exception { + runTest("compiler/testData/psi/recovery/valueParameterRecovery.kt"); + } + + @TestMetadata("valueParameterRecoveryWithTypes.kt") + public void testValueParameterRecoveryWithTypes() throws Exception { + runTest("compiler/testData/psi/recovery/valueParameterRecoveryWithTypes.kt"); + } + @TestMetadata("WhenWithoutBraces.kt") public void testWhenWithoutBraces() throws Exception { runTest("compiler/testData/psi/recovery/WhenWithoutBraces.kt");