diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt index bd3242c5271..373e213d3f6 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt @@ -97,3 +97,9 @@ public fun JetType.isArrayOfJavaLangClass(): Boolean = KotlinBuiltIns.isArray(this) && getArguments().firstOrNull()?.getType()?.isJavaLangClass() ?: false public fun JetType.isJavaLangClassOrArray(): Boolean = isJavaLangClass() || isArrayOfJavaLangClass() + +public fun JetTypeChecker.equalTypesOrNulls(type1: JetType?, type2: JetType?): Boolean { + if (type1 identityEquals type2) return true + if (type1 == null || type2 == null) return false + return equalTypes(type1, type2) +} \ No newline at end of file diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt index bc3721cd6a4..3a7e1d7fe41 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt @@ -29,7 +29,6 @@ import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.completion.handlers.CastReceiverInsertHandler import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler import org.jetbrains.kotlin.idea.util.FuzzyType -import org.jetbrains.kotlin.idea.util.fuzzyReturnType import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstance import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* @@ -39,6 +38,9 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.inline.InlineUtil +import org.jetbrains.kotlin.types.TypeConstructor +import org.jetbrains.kotlin.types.checker.JetTypeChecker +import org.jetbrains.kotlin.types.typeUtil.equalTypesOrNulls import java.util.ArrayList enum class ItemPriority { @@ -144,12 +146,28 @@ fun descriptorsEqualWithSubstitution(descriptor1: DeclarationDescriptor?, descri // optimization: if (descriptor1 == descriptor1.getOriginal() && descriptor2 == descriptor2.getOriginal()) return true - if (descriptor1.getReturnType() != descriptor2.getReturnType()) return false + val typeChecker = JetTypeChecker.withAxioms(object: JetTypeChecker.TypeConstructorEquality { + override fun equals(a: TypeConstructor, b: TypeConstructor): Boolean { + val typeParam1 = a.getDeclarationDescriptor() as? TypeParameterDescriptor + val typeParam2 = b.getDeclarationDescriptor() as? TypeParameterDescriptor + if (typeParam1 != null + && typeParam2 != null + && typeParam1.getContainingDeclaration() == descriptor1 + && typeParam2.getContainingDeclaration() == descriptor2) { + return typeParam1.getIndex() == typeParam2.getIndex() + } + + return a == b + } + }) + + if (!typeChecker.equalTypesOrNulls(descriptor1.getReturnType(), descriptor2.getReturnType())) return false + val parameters1 = descriptor1.getValueParameters() val parameters2 = descriptor2.getValueParameters() if (parameters1.size() != parameters2.size()) return false - for (i in parameters1.indices) { - if (parameters1[i].getType() != parameters2[i].getType()) return false + for ((param1, param2) in parameters1.zip(parameters2)) { + if (!typeChecker.equalTypes(param1.getType(), param2.getType())) return false } return true } diff --git a/idea/idea-completion/testData/basic/multifile/NoGenericFunDuplication/NoGenericFunDuplication.dependency.kt b/idea/idea-completion/testData/basic/multifile/NoGenericFunDuplication/NoGenericFunDuplication.dependency.kt new file mode 100644 index 00000000000..01925ed7f2f --- /dev/null +++ b/idea/idea-completion/testData/basic/multifile/NoGenericFunDuplication/NoGenericFunDuplication.dependency.kt @@ -0,0 +1,5 @@ +package dependency + +class MyPair(public val first: A, public val second: B) + +public fun A.pair(that: B): MyPair = MyPair(this, that) diff --git a/idea/idea-completion/testData/basic/multifile/NoGenericFunDuplication/NoGenericFunDuplication.kt b/idea/idea-completion/testData/basic/multifile/NoGenericFunDuplication/NoGenericFunDuplication.kt new file mode 100644 index 00000000000..418e3b654b2 --- /dev/null +++ b/idea/idea-completion/testData/basic/multifile/NoGenericFunDuplication/NoGenericFunDuplication.kt @@ -0,0 +1,9 @@ +// this test tests correct substitution equality checking for generic functions +import dependency.pair + +fun foo() { + 1 pai +} + +// EXIST: pair +// NUMBER: 1 diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java index 0d7b8798085..106c0676868 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java @@ -131,6 +131,12 @@ public class MultiFileJvmBasicCompletionTestGenerated extends AbstractMultiFileJ doTest(fileName); } + @TestMetadata("NoGenericFunDuplication") + public void testNoGenericFunDuplication() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/NoGenericFunDuplication/"); + doTest(fileName); + } + @TestMetadata("NotImportedExtensionForImplicitReceiver") public void testNotImportedExtensionForImplicitReceiver() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/NotImportedExtensionForImplicitReceiver/");