KT-2962 auto completion support for extension functions

#KT-2962 Fixed
This commit is contained in:
Nikolay Krasko
2012-10-18 12:12:26 +04:00
parent ce2b915645
commit 11da503c62
7 changed files with 132 additions and 14 deletions
@@ -46,10 +46,7 @@ import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.util.slicedmap.WritableSlice;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.*;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
@@ -231,25 +228,47 @@ public class ExpressionTypingUtils {
private static boolean checkReceiverResolution (
@NotNull ReceiverDescriptor expectedReceiver,
@NotNull JetType receiverType,
@NotNull CallableDescriptor receiverArgument
@NotNull CallableDescriptor callableDescriptor
) {
ConstraintSystem constraintSystem = new ConstraintSystemImpl();
for (TypeParameterDescriptor typeParameterDescriptor : receiverArgument.getTypeParameters()) {
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT);
ReceiverDescriptor callReceiver = callableDescriptor.getReceiverParameter();
if (!expectedReceiver.exists() && !callReceiver.exists()) {
// Both receivers do not exist
return true;
}
ReceiverDescriptor receiverParameter = receiverArgument.getReceiverParameter();
if (expectedReceiver.exists() && receiverParameter.exists()) {
constraintSystem.addSupertypeConstraint(receiverParameter.getType(), receiverType, ConstraintPosition.RECEIVER_POSITION);
}
else if (expectedReceiver.exists() || receiverParameter.exists()) {
// Only one of receivers exist
if (!(expectedReceiver.exists() && callReceiver.exists())) {
return false;
}
Set<Name> typeNamesInReceiver = collectUsedTypeNames(callReceiver.getType());
ConstraintSystem constraintSystem = new ConstraintSystemImpl();
for (TypeParameterDescriptor typeParameterDescriptor : callableDescriptor.getTypeParameters()) {
if (typeNamesInReceiver.contains(typeParameterDescriptor.getName())) {
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT);
}
}
constraintSystem.addSupertypeConstraint(callReceiver.getType(), receiverType, ConstraintPosition.RECEIVER_POSITION);
return constraintSystem.isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem);
}
private static Set<Name> collectUsedTypeNames(@NotNull JetType jetType) {
Set<Name> typeNames = new HashSet<Name>();
ClassifierDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
if (descriptor != null) {
typeNames.add(descriptor.getName());
}
for (TypeProjection argument : jetType.getArguments()) {
typeNames.addAll(collectUsedTypeNames(argument.getType()));
}
return typeNames;
}
@NotNull
public static OverloadResolutionResults<FunctionDescriptor> resolveFakeCall(
@NotNull ReceiverDescriptor receiver,
@@ -0,0 +1,14 @@
open class Base
class Test
fun <T> Test.extensionEmpty(param: T) = "Test"
fun <T: Base> Test.extensionBase(param: T) = "Test"
fun <T: Base, P> Test.extensionTwo(param: T) = "Test"
fun some() {
Test().ex<caret>
}
// EXIST: extensionEmpty
// EXIST: extensionBase
// EXIST: extensionTwo
@@ -0,0 +1,14 @@
open class Base
open class OtherBase
class Some<T>
fun <TSome : Base, R : Base> Some<TSome>.extensionBase(param: R) = "Test"
fun <TSome : OtherBase, R : OtherBase> Some<TSome>.extensionOtherBase(param: R) = "Test"
fun <TSome> Some<TSome>.extensionExact() = "Test"
fun test() {
Some<Base>().ex<caret>
}
// EXIST: extensionBase, extensionExact
// ABSENT: extensionOtherBase
@@ -0,0 +1,22 @@
open class Base
open class SubBase:Base()
open class SubSubBase:SubBase()
open class OtherBase
fun <T: Base> T.extensionSomeBase() = 12
fun <T: SubBase> T.extensionSomeSubBase() = 12
fun <T: SubSubBase> T.extensionSomeSubSubBase() = 12
fun <T: Base> T?.extensionSomeNull() = 12
fun <T: Base?> T.extensionSomeNullParam() = 12
fun <T: OtherBase> T.extensionSomeOtherBase() = 12
fun some() {
SubBase().extensionSome<caret>
}
// EXIST: extensionSomeBase
// EXIST: extensionSomeSubBase
// EXIST: extensionSomeNull
// EXIST: extensionSomeNullParam
// ABSENT: extensionSomeOtherBase
// ABSENT: extensionSomeSubSubBase
@@ -0,0 +1,11 @@
import java.util.HashSet
open class Base
fun <T: Base> Set<List<T>>.extensionInternal() = 12
fun some() {
HashSet<List<Base>>().ex<caret>
}
// EXIST: extensionInternal
@@ -0,0 +1,18 @@
open class Base
class ManySome<T, U>
fun <P1, P2>ManySome<P1, P2>.testExactGeneralGeneral() = "Some"
fun <P1, P2>ManySome<P1, Int>.testExactGeneralInt() = "Some"
fun <P1, P2>ManySome<Int, Int>.testExactIntInt() = "Some"
fun <P1 : Base, P2>ManySome<P1, Int>.testSubBaseIntInt() = "Some"
fun <P1, P2, P3>ManySome<P1, P2>.testManyGeneralGeneral() = "Some"
fun some() {
ManySome<Int, Int>().test<caret>
}
// EXIST: testExactGeneralGeneral
// EXIST: testExactGeneralInt
// EXIST: testExactIntInt
// EXIST: testManyGeneralGeneral
// ABSENT: testSubBaseIntInt
@@ -76,6 +76,26 @@ public class JetBasicCompletionTest extends JetCompletionTestBase {
doTest();
}
public void testExtensionWithAdditionalTypeParameters() {
doTest();
}
public void testExtensionWithGenericParamInReceiver() {
doTest();
}
public void testExtensionWithGenericReceiver() {
doTest();
}
public void testExtensionWithInternalGenericParameters() {
doTest();
}
public void testExtensionWithManyTypeParamsInReceiver() {
doTest();
}
public void testExtensionForProperty() {
doTest();
}