From 9d123b5c4f40ae7878dad14934fc5852d2413637 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Sat, 21 May 2011 14:00:18 +0400 Subject: [PATCH] JET-39 Process ?. correctly in the receiver types --- .../jet/lang/parsing/JetParsing.java | 42 +++++++++++++------ .../jet/lang/types/JetTypeInferrer.java | 4 +- idea/testData/psi/Functions.jet | 2 + idea/testData/psi/Functions.txt | 25 ++++++++++- 4 files changed, 59 insertions(+), 14 deletions(-) diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java index 3a8b724f278..18300d2925f 100644 --- a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -862,23 +862,39 @@ public class JetParsing extends AbstractJetParsing { return FUN; } - boolean parameterListOccured = false; + boolean typeParameterListOccured = false; if (at(LT)) { parseTypeParameterList(TokenSet.create(LBRACKET, LBRACE, LPAR)); - parameterListOccured = true; + typeParameterListOccured = true; } - - int lastDot = findLastBefore(TokenSet.create(DOT), TokenSet.create(LPAR), true); + TokenSet receiverTypeTerminators = TokenSet.create(DOT, SAFE_ACCESS); + int lastDot = findLastBefore(receiverTypeTerminators, TokenSet.create(LPAR), true); if (lastDot == -1) { // There's no explicit receiver type specified parseAttributeList(); expect(IDENTIFIER, "Expecting function name or receiver type"); } else { - createTruncatedBuilder(lastDot).parseTypeRef(); + PsiBuilder.Marker typeRefMarker = mark(); + PsiBuilder.Marker nullableType = mark(); + typeRefMarker = createTruncatedBuilder(lastDot).parseTypeRefContents(typeRefMarker); + if (at(SAFE_ACCESS)) { + nullableType.done(NULLABLE_TYPE); + } + else { + nullableType.drop(); + } + typeRefMarker.done(TYPE_REFERENCE); TokenSet functionNameFollow = TokenSet.create(LT, LPAR, COLON, EQ); - expect(DOT, "Expecting '.' before a function name", functionNameFollow); + if (atSet(receiverTypeTerminators)) { + advance(); // expectation + } + else { + errorWithRecovery("Expecting '.' before a function name", functionNameFollow); + } + +// expect(DOT, "Expecting '.' before a function name", functionNameFollow); expect(IDENTIFIER, "Expecting function name", functionNameFollow); } @@ -887,7 +903,7 @@ public class JetParsing extends AbstractJetParsing { if (at(LT)) { PsiBuilder.Marker error = mark(); parseTypeParameterList(TokenSet.orSet(TokenSet.create(LPAR), valueParametersFollow)); - if (parameterListOccured) { + if (typeParameterListOccured) { error.error("Only one type parameter list is allowed for a function"); // TODO : discuss } else { @@ -1158,8 +1174,10 @@ public class JetParsing extends AbstractJetParsing { * : typeDescriptor "?" */ public void parseTypeRef() { - PsiBuilder.Marker type = mark(); + parseTypeRefContents(mark()).done(TYPE_REFERENCE); + } + private PsiBuilder.Marker parseTypeRefContents(PsiBuilder.Marker typeRefMarker) { parseAttributeList(); if (at(IDENTIFIER) || at(NAMESPACE_KEYWORD)) { @@ -1181,14 +1199,14 @@ public class JetParsing extends AbstractJetParsing { } while (at(QUEST)) { - PsiBuilder.Marker precede = type.precede(); + PsiBuilder.Marker precede = typeRefMarker.precede(); advance(); // QUEST - type.done(NULLABLE_TYPE); + typeRefMarker.done(NULLABLE_TYPE); - type = precede; + typeRefMarker = precede; } - type.done(TYPE_REFERENCE); + return typeRefMarker; } /* diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 11538e6dec4..1dc68d9e3dd 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -1425,7 +1425,9 @@ public class JetTypeInferrer { trace.getErrorHandler().genericWarning(expression.getNode(), "Expression always evaluates to false"); // TODO : make an error? } } - + } + else { + trace.getErrorHandler().genericError(pattern.getNode(), "Unsupported [JetTypeInferrer]"); } result = semanticServices.getStandardLibrary().getBooleanType(); } diff --git a/idea/testData/psi/Functions.jet b/idea/testData/psi/Functions.jet index ef3513b2266..aa832351da4 100644 --- a/idea/testData/psi/Functions.jet +++ b/idea/testData/psi/Functions.jet @@ -21,3 +21,5 @@ fun [a()] T.foo(a : foo) : bar {} fun [a] {[a] T.(A) : ()}.foo() {} fun [a()] T.foo(a : foo) : bar {} + +fun A?.foo() : bar? \ No newline at end of file diff --git a/idea/testData/psi/Functions.txt b/idea/testData/psi/Functions.txt index ef0b279c78a..667709d88b4 100644 --- a/idea/testData/psi/Functions.txt +++ b/idea/testData/psi/Functions.txt @@ -813,4 +813,27 @@ JetFile: Functions.jet PsiWhiteSpace(' ') BLOCK PsiElement(LBRACE)('{') - PsiElement(RBRACE)('}') \ No newline at end of file + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + TYPE_REFERENCE + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + PsiElement(SAFE_ACCESS)('?.') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') + PsiElement(QUEST)('?') \ No newline at end of file