KT-2962 auto completion support for extension functions
#KT-2962 Fixed
This commit is contained in:
+33
-14
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user