JET-39 Process ?. correctly in the receiver types
This commit is contained in:
@@ -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
|
||||
@@ -73,3 +73,5 @@ fun foo() {
|
||||
|
||||
val IList<T>.lastIndex : Int
|
||||
get() = this.size - 1
|
||||
|
||||
val Int?.opt : Int
|
||||
@@ -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')
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user