diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java b/idea/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java index 17345fb365e..88ee3f9205a 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java @@ -1,10 +1,7 @@ package org.jetbrains.jet.lang.descriptors; import com.google.common.base.Function; -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; +import com.google.common.collect.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.*; @@ -270,15 +267,21 @@ public class FunctionDescriptorUtil { @Override public boolean isEmpty() { - // TODO: not implemented - return false; + return getFunctionDescriptors().isEmpty(); } @NotNull @Override public Set getFunctionDescriptors() { - // TODO: not implemented - return null; + Set functionDescriptors = Sets.newHashSet(functionGroup.getFunctionDescriptors()); + for (Iterator iterator = functionDescriptors.iterator(); iterator.hasNext(); ) { + FunctionDescriptor functionDescriptor = iterator.next(); + if (!criterion.apply(functionDescriptor)) { + iterator.remove(); + } + } + + return functionDescriptors; } }; } diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java index 18300d2925f..3c4ad6be1df 100644 --- a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -38,6 +38,7 @@ public class JetParsing extends AbstractJetParsing { private static final TokenSet PARAMETER_NAME_RECOVERY_SET = TokenSet.create(COLON, EQ, COMMA, RPAR); private static final TokenSet NAMESPACE_NAME_RECOVERY_SET = TokenSet.create(DOT, EOL_OR_SEMICOLON); /*package*/ static final TokenSet TYPE_REF_FIRST = TokenSet.create(LBRACKET, IDENTIFIER, LBRACE, LPAR, CAPITALIZED_THIS_KEYWORD); + private static final TokenSet RECEIVER_TYPE_TERMINATORS = TokenSet.create(DOT, SAFE_ACCESS); public static JetParsing createForTopLevel(SemanticWhitespaceAwarePsiBuilder builder) { builder.setDebugMode(true); @@ -725,35 +726,38 @@ public class JetParsing extends AbstractJetParsing { // TODO: extract constant int lastDot = matchTokenStreamPredicate(new FirstBefore( - new AbstractTokenStreamPredicate() { - @Override - public boolean matching(boolean topLevel) { - return topLevel - && at(DOT); - } - }, +// new AbstractTokenStreamPredicate() { +// @Override +// public boolean matching(boolean topLevel) { +// return topLevel +// && at(DOT); +// } +// }, + new AtSet(DOT, SAFE_ACCESS), new AbstractTokenStreamPredicate() { @Override public boolean matching(boolean topLevel) { if (topLevel && (at(EQ) || at(COLON))) return true; if (topLevel && at(IDENTIFIER)) { IElementType lookahead = lookahead(1); - return lookahead != LT && lookahead != DOT; + return lookahead != LT && lookahead != DOT && lookahead != SAFE_ACCESS; } return false; } })); - if (lastDot == -1) { - parseAttributeList(); - expect(IDENTIFIER, "Expecting property name or receiver type", propertyNameFollow); - } - else { - createTruncatedBuilder(lastDot).parseTypeRef(); + parseReceiverType("property", propertyNameFollow, lastDot); - expect(DOT, "Expecting '.' before a property name", propertyNameFollow); - expect(IDENTIFIER, "Expecting property name", propertyNameFollow); - } +// if (lastDot == -1) { +// parseAttributeList(); +// expect(IDENTIFIER, "Expecting property name or receiver type", propertyNameFollow); +// } +// else { +// createTruncatedBuilder(lastDot).parseTypeRef(); +// +// expect(DOT, "Expecting '.' before a property name", propertyNameFollow); +// expect(IDENTIFIER, "Expecting property name", propertyNameFollow); +// } if (at(COLON)) { advance(); // COLON @@ -868,35 +872,8 @@ public class JetParsing extends AbstractJetParsing { typeParameterListOccured = 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 { - 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); - 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); - } + int lastDot = findLastBefore(RECEIVER_TYPE_TERMINATORS, TokenSet.create(LPAR), true); + parseReceiverType("function", TokenSet.create(LT, LPAR, COLON, EQ), lastDot); TokenSet valueParametersFollow = TokenSet.create(COLON, EQ, LBRACE, SEMICOLON, RPAR); @@ -929,6 +906,38 @@ public class JetParsing extends AbstractJetParsing { return FUN; } + /* + * : + * (type "." | attributes)? + */ + private void parseReceiverType(String title, TokenSet nameFollow, int lastDot) { + + if (lastDot == -1) { // There's no explicit receiver type specified + parseAttributeList(); + expect(IDENTIFIER, "Expecting " + title + " name or receiver type", nameFollow); + } else { + 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); + + if (atSet(RECEIVER_TYPE_TERMINATORS)) { + advance(); // expectation + } + else { + errorWithRecovery("Expecting '.' before a " + title + " name", nameFollow); + } + + expect(IDENTIFIER, "Expecting " + title + " name", nameFollow); + } + } + /* * functionBody * : block diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ScopeWithReceiver.java b/idea/src/org/jetbrains/jet/lang/resolve/ScopeWithReceiver.java index b3d67fdeb41..20af13963f4 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ScopeWithReceiver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ScopeWithReceiver.java @@ -12,20 +12,20 @@ import org.jetbrains.jet.lang.types.JetTypeChecker; */ public class ScopeWithReceiver extends JetScopeImpl { - private final JetScope receiverTypeScope; + private final JetType receiverType; private final JetScope outerScope; private final JetTypeChecker typeChecker; public ScopeWithReceiver(JetScope outerScope, JetType receiverType, JetTypeChecker typeChecker) { this.outerScope = outerScope; - this.receiverTypeScope = receiverType.getMemberScope(); + this.receiverType = receiverType; this.typeChecker = typeChecker; } @NotNull @Override public FunctionGroup getFunctionGroup(@NotNull String name) { - FunctionGroup functionGroup = receiverTypeScope.getFunctionGroup(name); + FunctionGroup functionGroup = receiverType.getMemberScope().getFunctionGroup(name); if (functionGroup.isEmpty()) { return FunctionDescriptorUtil.filteredFunctionGroup(outerScope.getFunctionGroup(name), new Function() { @@ -37,7 +37,7 @@ public class ScopeWithReceiver extends JetScopeImpl { return false; } // TODO : in case of inferred type arguments, substitute the receiver type first - return typeChecker.isSubtypeOf(receiverTypeScope.getThisType(), functionReceiverType); + return typeChecker.isSubtypeOf(receiverType, functionReceiverType); } }); } @@ -51,7 +51,7 @@ public class ScopeWithReceiver extends JetScopeImpl { @Override public VariableDescriptor getVariable(@NotNull String name) { - VariableDescriptor variable = receiverTypeScope.getVariable(name); + VariableDescriptor variable = receiverType.getMemberScope().getVariable(name); if (variable != null) { return variable; } @@ -61,7 +61,7 @@ public class ScopeWithReceiver extends JetScopeImpl { JetType receiverType = propertyDescriptor.getReceiverType(); // TODO : in case of type arguments, substitute the receiver type first if (receiverType != null - && typeChecker.isSubtypeOf(receiverTypeScope.getThisType(), receiverType)) { + && typeChecker.isSubtypeOf(receiverType, receiverType)) { return variable; } } @@ -70,13 +70,13 @@ public class ScopeWithReceiver extends JetScopeImpl { @Override public NamespaceDescriptor getNamespace(@NotNull String name) { - return receiverTypeScope.getNamespace(name); + return receiverType.getMemberScope().getNamespace(name); } @NotNull @Override public JetType getThisType() { - return receiverTypeScope.getThisType(); + return receiverType; } @NotNull diff --git a/idea/testData/checker/ExtensionFunctions.jet b/idea/testData/checker/ExtensionFunctions.jet new file mode 100644 index 00000000000..3958be90ab5 --- /dev/null +++ b/idea/testData/checker/ExtensionFunctions.jet @@ -0,0 +1,2 @@ +fun Int?.optint() : Unit +val Int?.optval : Unit \ No newline at end of file diff --git a/idea/testData/psi/Properties.jet b/idea/testData/psi/Properties.jet index 4a83dbd182d..08fdf1a2e33 100644 --- a/idea/testData/psi/Properties.jet +++ b/idea/testData/psi/Properties.jet @@ -73,3 +73,5 @@ fun foo() { val IList.lastIndex : Int get() = this.size - 1 + +val Int?.opt : Int \ No newline at end of file diff --git a/idea/testData/psi/Properties.txt b/idea/testData/psi/Properties.txt index 8b3c1c5af91..cada06eaa00 100644 --- a/idea/testData/psi/Properties.txt +++ b/idea/testData/psi/Properties.txt @@ -777,4 +777,22 @@ JetFile: Properties.jet PsiElement(MINUS)('-') PsiWhiteSpace(' ') INTEGER_CONSTANT - PsiElement(INTEGER_LITERAL)('1') \ No newline at end of file + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n\n') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + TYPE_REFERENCE + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(SAFE_ACCESS)('?.') + PsiElement(IDENTIFIER)('opt') + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') \ No newline at end of file diff --git a/idea/testData/resolve/ExtensionFunctions.jet b/idea/testData/resolve/ExtensionFunctions.jet index 0634aa0d053..8418f76d6d5 100644 --- a/idea/testData/resolve/ExtensionFunctions.jet +++ b/idea/testData/resolve/ExtensionFunctions.jet @@ -3,7 +3,7 @@ fun <~T~T, ~E~E> `T`T.foo(x : `E`E, y : `A`A) : `T`T { y `+`plus 1 y `+1`+ 1.0 - this?.`-`minus(this) + this?.minus(this) this } @@ -11,6 +11,10 @@ fun <~T~T, ~E~E> `T`T.foo(x : `E`E, y : `A`A) : `T`T { ~A~class A ~+1~fun `A`A.plus(a : Any) { + + 1.`foo`foo() + true.`!`foo() + 1 } @@ -28,4 +32,4 @@ fun test() { val <~TT~T> `TT`T.foo : `TT`T -fun Int.foo() = this`:std::Int` \ No newline at end of file +~foo~fun Int.foo() = this`:std::Int` \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java b/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java index b84bab18d07..5566cb2cf2e 100644 --- a/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java +++ b/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java @@ -161,7 +161,7 @@ public class ExpectedResolveData { actualName = actual.toString(); } } - assertNotNull(reference); + assertNotNull(element.getText(), reference); if (expected instanceof JetParameter || actual instanceof JetParameter) { DeclarationDescriptor expectedDescriptor;