JET-39 Process ?. correctly in the receiver types

This commit is contained in:
Andrey Breslav
2011-05-23 10:42:50 +04:00
parent 9d123b5c4f
commit dd612c74e3
8 changed files with 104 additions and 66 deletions
@@ -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<FunctionDescriptor> getFunctionDescriptors() {
// TODO: not implemented
return null;
Set<FunctionDescriptor> functionDescriptors = Sets.newHashSet(functionGroup.getFunctionDescriptors());
for (Iterator<FunctionDescriptor> iterator = functionDescriptors.iterator(); iterator.hasNext(); ) {
FunctionDescriptor functionDescriptor = iterator.next();
if (!criterion.apply(functionDescriptor)) {
iterator.remove();
}
}
return functionDescriptors;
}
};
}
@@ -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
@@ -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<FunctionDescriptor, Boolean>() {
@@ -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
@@ -0,0 +1,2 @@
fun Int?.optint() : Unit
val Int?.optval : Unit
+2
View File
@@ -73,3 +73,5 @@ fun foo() {
val IList<T>.lastIndex : Int
get() = this.size - 1
val Int?.opt : Int
+19 -1
View File
@@ -777,4 +777,22 @@ JetFile: Properties.jet
PsiElement(MINUS)('-')
PsiWhiteSpace(' ')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('1')
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')
+6 -2
View File
@@ -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<T>(this)
this?.minus<T>(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`
~foo~fun Int.foo() = this`:std::Int`
@@ -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;