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 57471dc7120..9a97153ce8d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -419,13 +419,27 @@ public class JetParsing extends AbstractJetParsing { expect(IDENTIFIER, "Class name expected", CLASS_NAME_RECOVERY_SET); boolean typeParametersDeclared = parseTypeParameterList(TYPE_PARAMETER_GT_RECOVERY_SET); - if (parseModifierList(PRIMARY_CONSTRUCTOR_MODIFIER_LIST, false)) { + PsiBuilder.Marker beforeConstructorModifiers = mark(); + boolean hasConstructorModifiers = parseModifierList(PRIMARY_CONSTRUCTOR_MODIFIER_LIST, false); + + // Some modifiers found, but no parentheses following: class has already ended, and we are looking at something else + if (hasConstructorModifiers && !atSet(LPAR, LBRACE, COLON) ) { + beforeConstructorModifiers.rollbackTo(); + return CLASS; + } + + // We are still inside a class declaration + beforeConstructorModifiers.drop(); + + if (at(LPAR)) { parseValueParameterList(false, TokenSet.create(COLON, LBRACE)); } - else { - if (at(LPAR)) { - parseValueParameterList(false, TokenSet.create(COLON, LBRACE)); - } + else if (hasConstructorModifiers) { + // A comprehensive error message for cases like: + // class A private : Foo + // or + // class A private { + error("Expecting primary constructor parameter list"); } if (at(COLON)) { diff --git a/compiler/testData/psi/PrimaryConstructorModifiers_ERR.jet b/compiler/testData/psi/PrimaryConstructorModifiers_ERR.jet new file mode 100644 index 00000000000..d24a9e56ab5 --- /dev/null +++ b/compiler/testData/psi/PrimaryConstructorModifiers_ERR.jet @@ -0,0 +1,13 @@ +open class A + +open class AB private { + fun foo() {} +} + +class A1 { + +} + +open class B private () { + +} diff --git a/compiler/testData/psi/PrimaryConstructorModifiers_ERR.txt b/compiler/testData/psi/PrimaryConstructorModifiers_ERR.txt new file mode 100644 index 00000000000..090d5cf7366 --- /dev/null +++ b/compiler/testData/psi/PrimaryConstructorModifiers_ERR.txt @@ -0,0 +1,87 @@ +JetFile: PrimaryConstructorModifiers_ERR.jet + NAMESPACE + CLASS + MODIFIER_LIST + PsiElement(open)('open') + PsiWhiteSpace(' ') + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('A') + PsiWhiteSpace('\n\n') + TYPE_PARAMETER_LIST + + CLASS + MODIFIER_LIST + PsiElement(open)('open') + PsiWhiteSpace(' ') + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('AB') + PsiWhiteSpace(' ') + TYPE_PARAMETER_LIST + + PRIMARY_CONSTRUCTOR_MODIFIER_LIST + PsiElement(private)('private') + PsiErrorElement:Expecting primary constructor parameter list + + PsiWhiteSpace(' ') + CLASS_BODY + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + CLASS + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('A1') + PsiWhiteSpace(' ') + TYPE_PARAMETER_LIST + + CLASS_BODY + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + CLASS + MODIFIER_LIST + PsiElement(open)('open') + PsiWhiteSpace(' ') + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('B') + TYPE_PARAMETER_LIST + PsiElement(LT)('<') + TYPE_PARAMETER + PsiElement(IDENTIFIER)('T') + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + PsiElement(GT)('>') + PsiWhiteSpace(' ') + PRIMARY_CONSTRUCTOR_MODIFIER_LIST + PsiElement(private)('private') + PsiWhiteSpace(' ') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + CLASS_BODY + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n\n') + PsiElement(RBRACE)('}') \ No newline at end of file