diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java index 2ac32cc6005..17f2a902052 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java @@ -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 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 collectUsedTypeNames(@NotNull JetType jetType) { + Set typeNames = new HashSet(); + + 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 resolveFakeCall( @NotNull ReceiverDescriptor receiver, diff --git a/idea/testData/completion/basic/ExtensionWithAdditionalTypeParameters.kt b/idea/testData/completion/basic/ExtensionWithAdditionalTypeParameters.kt new file mode 100644 index 00000000000..663b8601d21 --- /dev/null +++ b/idea/testData/completion/basic/ExtensionWithAdditionalTypeParameters.kt @@ -0,0 +1,14 @@ +open class Base + +class Test +fun Test.extensionEmpty(param: T) = "Test" +fun Test.extensionBase(param: T) = "Test" +fun Test.extensionTwo(param: T) = "Test" + +fun some() { + Test().ex +} + +// EXIST: extensionEmpty +// EXIST: extensionBase +// EXIST: extensionTwo diff --git a/idea/testData/completion/basic/ExtensionWithGenericParamInReceiver.kt b/idea/testData/completion/basic/ExtensionWithGenericParamInReceiver.kt new file mode 100644 index 00000000000..03557672980 --- /dev/null +++ b/idea/testData/completion/basic/ExtensionWithGenericParamInReceiver.kt @@ -0,0 +1,14 @@ +open class Base +open class OtherBase + +class Some +fun Some.extensionBase(param: R) = "Test" +fun Some.extensionOtherBase(param: R) = "Test" +fun Some.extensionExact() = "Test" + +fun test() { + Some().ex +} + +// EXIST: extensionBase, extensionExact +// ABSENT: extensionOtherBase diff --git a/idea/testData/completion/basic/ExtensionWithGenericReceiver.kt b/idea/testData/completion/basic/ExtensionWithGenericReceiver.kt new file mode 100644 index 00000000000..82680b105fa --- /dev/null +++ b/idea/testData/completion/basic/ExtensionWithGenericReceiver.kt @@ -0,0 +1,22 @@ +open class Base +open class SubBase:Base() +open class SubSubBase:SubBase() +open class OtherBase + +fun T.extensionSomeBase() = 12 +fun T.extensionSomeSubBase() = 12 +fun T.extensionSomeSubSubBase() = 12 +fun T?.extensionSomeNull() = 12 +fun T.extensionSomeNullParam() = 12 +fun T.extensionSomeOtherBase() = 12 + +fun some() { + SubBase().extensionSome +} + +// EXIST: extensionSomeBase +// EXIST: extensionSomeSubBase +// EXIST: extensionSomeNull +// EXIST: extensionSomeNullParam +// ABSENT: extensionSomeOtherBase +// ABSENT: extensionSomeSubSubBase diff --git a/idea/testData/completion/basic/ExtensionWithInternalGenericParameters.kt b/idea/testData/completion/basic/ExtensionWithInternalGenericParameters.kt new file mode 100644 index 00000000000..f8a0dd7f7bc --- /dev/null +++ b/idea/testData/completion/basic/ExtensionWithInternalGenericParameters.kt @@ -0,0 +1,11 @@ +import java.util.HashSet + +open class Base + +fun Set>.extensionInternal() = 12 + +fun some() { + HashSet>().ex +} + +// EXIST: extensionInternal \ No newline at end of file diff --git a/idea/testData/completion/basic/ExtensionWithManyTypeParamsInReceiver.kt b/idea/testData/completion/basic/ExtensionWithManyTypeParamsInReceiver.kt new file mode 100644 index 00000000000..07f4c12e6c6 --- /dev/null +++ b/idea/testData/completion/basic/ExtensionWithManyTypeParamsInReceiver.kt @@ -0,0 +1,18 @@ +open class Base + +class ManySome +fun ManySome.testExactGeneralGeneral() = "Some" +fun ManySome.testExactGeneralInt() = "Some" +fun ManySome.testExactIntInt() = "Some" +fun ManySome.testSubBaseIntInt() = "Some" +fun ManySome.testManyGeneralGeneral() = "Some" + +fun some() { + ManySome().test +} + +// EXIST: testExactGeneralGeneral +// EXIST: testExactGeneralInt +// EXIST: testExactIntInt +// EXIST: testManyGeneralGeneral +// ABSENT: testSubBaseIntInt diff --git a/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java b/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java index 12f9e227f9e..de6cebf97e5 100644 --- a/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java +++ b/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java @@ -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(); }