Resolve extension calls on class objects

#KT-3470 Fixed
This commit is contained in:
Alexander Udalov
2013-11-12 16:36:25 +04:00
parent 838c408e68
commit e2622b5dbb
10 changed files with 97 additions and 15 deletions
@@ -19,11 +19,12 @@ package org.jetbrains.jet.lang.resolve;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.resolve.name.SpecialNames;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.types.NamespaceType;
public class JetModuleUtil {
public static NamespaceType getRootNamespaceType(JetElement expression) {
// TODO: this is a stub: at least the modules' root namespaces must be indexed here
return new NamespaceType(SpecialNames.ROOT_NAMESPACE, JetScope.EMPTY);
return new NamespaceType(SpecialNames.ROOT_NAMESPACE, JetScope.EMPTY, ReceiverValue.NO_RECEIVER);
}
}
@@ -52,6 +52,7 @@ import java.util.List;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getStaticNestedClassesScope;
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER;
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
import static org.jetbrains.jet.lang.psi.JetPsiUtil.isLHSOfDot;
@@ -113,7 +114,7 @@ public class CallExpressionResolver {
return "Scope for the type parameter on the left hand side of dot";
}
};
return new NamespaceType(referencedName, scopeForStaticMembersResolution);
return new NamespaceType(referencedName, scopeForStaticMembersResolution, NO_RECEIVER);
}
temporaryTrace.commit();
return result[0];
@@ -154,7 +155,7 @@ public class CallExpressionResolver {
}
JetScope scope = new ChainedScope(classifier, scopes.toArray(new JetScope[scopes.size()]));
return new NamespaceType(referencedName, scope);
return new NamespaceType(referencedName, scope, new ExpressionReceiver(expression, classObjectType));
}
return classObjectType;
}
@@ -195,7 +196,7 @@ public class CallExpressionResolver {
else {
scope = namespace.getMemberScope();
}
return new NamespaceType(name, scope);
return new NamespaceType(name, scope, NO_RECEIVER);
}
@Nullable
@@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.resolve.calls.tasks;
import com.google.common.collect.Lists;
import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
@@ -25,7 +26,6 @@ import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import org.jetbrains.jet.lang.psi.JetSuperExpression;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.LibrarySourceHacks;
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl;
import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext;
import org.jetbrains.jet.lang.resolve.name.Name;
@@ -34,9 +34,11 @@ import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.types.ErrorUtils;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.NamespaceType;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -82,20 +84,27 @@ public class TaskPrioritizer {
@NotNull JetReferenceExpression functionReference,
@NotNull List<CallableDescriptorCollector<? extends D>> callableDescriptorCollectors
) {
List<Pair<JetScope, ReceiverValue>> variants = new ArrayList<Pair<JetScope, ReceiverValue>>(2);
ReceiverValue explicitReceiver = context.call.getExplicitReceiver();
JetScope scope;
if (explicitReceiver.exists() && explicitReceiver.getType() instanceof NamespaceType) {
// Receiver is a namespace
scope = explicitReceiver.getType().getMemberScope();
explicitReceiver = NO_RECEIVER;
JetType receiverType = explicitReceiver.getType();
variants.add(Pair.create(receiverType.getMemberScope(), NO_RECEIVER));
ReceiverValue value = ((NamespaceType) receiverType).getReceiverValue();
if (value.exists()) {
variants.add(Pair.create(context.scope, value));
}
}
else {
scope = context.scope;
variants.add(Pair.create(context.scope, explicitReceiver));
}
ResolutionTaskHolder<D, F> result =
new ResolutionTaskHolder<D, F>(functionReference, context, new MyPriorityProvider<D>(context), null);
for (Pair<JetScope, ReceiverValue> pair : variants) {
doComputeTasks(pair.second, new TaskPrioritizerContext<D, F>(name, result, context, pair.first, callableDescriptorCollectors));
}
ResolutionTaskHolder<D, F> result = new ResolutionTaskHolder<D, F>(functionReference, context, new MyPriorityProvider<D>(context), null);
TaskPrioritizerContext<D, F> c = new TaskPrioritizerContext<D, F>(name, result, context, scope, callableDescriptorCollectors);
doComputeTasks(explicitReceiver, c);
return result.getTasks();
}
@@ -0,0 +1,7 @@
class SomeClass { class object }
fun box() =
if ((SomeClass.toString() as java.lang.String).matches("SomeClass\\\$object@[0-9a-fA-F]+"))
"OK"
else
"Fail: $SomeClass"
@@ -0,0 +1,19 @@
trait Tr
class A { class object }
class B { class object : Tr }
fun Any.f1() {}
fun Any?.f2() {}
fun Tr.f3() {}
fun Tr?.f4() {}
fun A.f5() {}
fun test() {
A.f1()
A.f2()
B.f3()
B.f4()
A.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>f5<!>()
B.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>f5<!>()
}
@@ -0,0 +1,7 @@
class A {
class object {
fun foo() = toString()
}
}
val a = A.toString()
@@ -0,0 +1,11 @@
// FILE: A.java
public class A {
public static void foo() {}
public static class Nested {}
}
// FILE: B.kt
fun Any?.bar() = 42
fun f1() = A.<!UNRESOLVED_REFERENCE!>bar<!>()
fun f2() = A.Nested.<!UNRESOLVED_REFERENCE!>bar<!>()
@@ -2674,6 +2674,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/extensions"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("classObject.kt")
public void testClassObject() throws Exception {
doTest("compiler/testData/diagnostics/tests/extensions/classObject.kt");
}
@TestMetadata("ExtensionFunctions.kt")
public void testExtensionFunctions() throws Exception {
doTest("compiler/testData/diagnostics/tests/extensions/ExtensionFunctions.kt");
@@ -2704,6 +2709,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/extensions/kt2317.kt");
}
@TestMetadata("kt3470.kt")
public void testKt3470() throws Exception {
doTest("compiler/testData/diagnostics/tests/extensions/kt3470.kt");
}
@TestMetadata("kt3563.kt")
public void testKt3563() throws Exception {
doTest("compiler/testData/diagnostics/tests/extensions/kt3563.kt");
@@ -2714,6 +2724,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/extensions/kt819ExtensionProperties.kt");
}
@TestMetadata("noClassObjectsInJava.kt")
public void testNoClassObjectsInJava() throws Exception {
doTest("compiler/testData/diagnostics/tests/extensions/noClassObjectsInJava.kt");
}
@TestMetadata("object.kt")
public void testObject() throws Exception {
doTest("compiler/testData/diagnostics/tests/extensions/object.kt");
@@ -743,6 +743,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest("compiler/testData/codegen/box/classes/classObjectNotOfEnum.kt");
}
@TestMetadata("classObjectToString.kt")
public void testClassObjectToString() throws Exception {
doTest("compiler/testData/codegen/box/classes/classObjectToString.kt");
}
@TestMetadata("classObjectWithPrivateGenericMember.kt")
public void testClassObjectWithPrivateGenericMember() throws Exception {
doTest("compiler/testData/codegen/box/classes/classObjectWithPrivateGenericMember.kt");
@@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import java.util.List;
@@ -29,12 +30,13 @@ import java.util.List;
*/
public class NamespaceType implements JetType {
private final Name name;
@NotNull
private final JetScope memberScope;
private final ReceiverValue receiver;
public NamespaceType(@NotNull Name name, @NotNull JetScope memberScope) {
public NamespaceType(@NotNull Name name, @NotNull JetScope memberScope, @NotNull ReceiverValue receiver) {
this.name = name;
this.memberScope = memberScope;
this.receiver = receiver;
}
@NotNull
@@ -48,6 +50,11 @@ public class NamespaceType implements JetType {
return false;
}
@NotNull
public ReceiverValue getReceiverValue() {
return receiver;
}
@NotNull
@Override
public TypeConstructor getConstructor() {