diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java index 1c6dbfb32d7..dba0dd21d60 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java @@ -372,7 +372,7 @@ public class JetExpressionParsing extends AbstractJetParsing { /* * callableReference - * : userType? "::" SimpleName + * : (userType "?"*)? "::" SimpleName * ; */ private boolean parseCallableReferenceExpression() { @@ -381,7 +381,9 @@ public class JetExpressionParsing extends AbstractJetParsing { if (!at(COLONCOLON)) { PsiBuilder.Marker typeReference = mark(); myJetParsing.parseUserType(); + typeReference = myJetParsing.parseNullableTypeSuffix(typeReference); typeReference.done(TYPE_REFERENCE); + if (!at(COLONCOLON)) { expression.rollbackTo(); return false; 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 e14ec5a3e90..1644e65d41a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.parsing; import com.intellij.lang.PsiBuilder; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeType; import org.jetbrains.jet.lexer.JetKeywordToken; @@ -1478,14 +1479,7 @@ public class JetParsing extends AbstractJetParsing { TokenSet.create(EQ, COMMA, GT, RBRACKET, DOT, RPAR, RBRACE, LBRACE, SEMICOLON), extraRecoverySet)); } - while (at(QUEST)) { - PsiBuilder.Marker precede = typeRefMarker.precede(); - - advance(); // QUEST - typeRefMarker.done(NULLABLE_TYPE); - - typeRefMarker = precede; - } + typeRefMarker = parseNullableTypeSuffix(typeRefMarker); if (at(DOT)) { // This is a receiver for a function type @@ -1513,6 +1507,17 @@ public class JetParsing extends AbstractJetParsing { return typeRefMarker; } + @NotNull + PsiBuilder.Marker parseNullableTypeSuffix(@NotNull PsiBuilder.Marker typeRefMarker) { + while (at(QUEST)) { + PsiBuilder.Marker precede = typeRefMarker.precede(); + advance(); // QUEST + typeRefMarker.done(NULLABLE_TYPE); + typeRefMarker = precede; + } + return typeRefMarker; + } + /* * userType * : ("package" ".")? simpleUserType{"."} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionOnNullable.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionOnNullable.kt new file mode 100644 index 00000000000..f6fb90d4f42 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionOnNullable.kt @@ -0,0 +1,8 @@ +class A { + fun foo() {} +} + +fun A?.foo() {} + +val f = A::foo : KMemberFunction0 +val g = A?::foo : KExtensionFunction0 diff --git a/compiler/testData/psi/DoubleColon.kt b/compiler/testData/psi/DoubleColon.kt index bf44a1c132d..acb42293fbe 100644 --- a/compiler/testData/psi/DoubleColon.kt +++ b/compiler/testData/psi/DoubleColon.kt @@ -23,6 +23,11 @@ fun ok() { (a::b)() a.(b::c)() a.b::c() + + a?::b + a??::b + a?::c + a?::d } fun err0() { diff --git a/compiler/testData/psi/DoubleColon.txt b/compiler/testData/psi/DoubleColon.txt index a1e37dc967d..278f3d7554f 100644 --- a/compiler/testData/psi/DoubleColon.txt +++ b/compiler/testData/psi/DoubleColon.txt @@ -392,6 +392,78 @@ JetFile: DoubleColon.kt PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) PsiElement(LPAR)('(') PsiElement(RPAR)(')') + PsiWhiteSpace('\n\n ') + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(QUEST)('?') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiWhiteSpace('\n ') + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + NULLABLE_TYPE + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(QUEST)('?') + PsiElement(QUEST)('?') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiWhiteSpace('\n ') + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiElement(GT)('>') + PsiElement(QUEST)('?') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('c') + PsiWhiteSpace('\n ') + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiElement(QUEST)('?') + PsiElement(COMMA)(',') + TYPE_PROJECTION + TYPE_REFERENCE + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('c') + PsiElement(QUEST)('?') + PsiElement(GT)('>') + PsiElement(QUEST)('?') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('d') PsiWhiteSpace('\n') PsiElement(RBRACE)('}') PsiWhiteSpace('\n\n') diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestWithStdLibGenerated.java index 186d535e122..ed8963048ac 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestWithStdLibGenerated.java @@ -192,6 +192,11 @@ public class JetDiagnosticsTestWithStdLibGenerated extends AbstractJetDiagnostic doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionInClassDisallowed.kt"); } + @TestMetadata("extensionOnNullable.kt") + public void testExtensionOnNullable() throws Exception { + doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/function/extensionOnNullable.kt"); + } + @TestMetadata("genericClassFromTopLevel.kt") public void testGenericClassFromTopLevel() throws Exception { doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/function/genericClassFromTopLevel.kt"); diff --git a/grammar/src/expressions.grm b/grammar/src/expressions.grm index 5b4bae7859e..39e547baaf0 100644 --- a/grammar/src/expressions.grm +++ b/grammar/src/expressions.grm @@ -104,7 +104,7 @@ postfixUnaryExpression // TODO: callSuffix is forbidden after callableReference, since parentheses will be used to provide parameter types callableReference - : userType? "::" SimpleName + : (userType "?"*)? "::" SimpleName ; // !!! When you add here, remember to update the FIRST set in the parser