From 24764ed8650ce1238dbec7533e9b957555be98ef Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Thu, 31 Mar 2016 22:21:29 +0300 Subject: [PATCH] Checking for conflicting substitutors in completion after "by" --- .../org/jetbrains/kotlin/idea/util/FuzzyType.kt | 15 +++++++++++++++ .../propertyDelegate/ConflictingSubstitutors.kt | 11 +++++++++++ .../NonConflictingSubstitutors.kt | 11 +++++++++++ .../test/JvmSmartCompletionTestGenerated.java | 12 ++++++++++++ .../jetbrains/kotlin/idea/core/ExpectedInfos.kt | 11 ++++------- .../kotlin/idea/core/TypesWithOperatorDetector.kt | 3 ++- 6 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 idea/idea-completion/testData/smart/propertyDelegate/ConflictingSubstitutors.kt create mode 100644 idea/idea-completion/testData/smart/propertyDelegate/NonConflictingSubstitutors.kt diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/FuzzyType.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/FuzzyType.kt index d172d429156..3c7beec5805 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/FuzzyType.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/FuzzyType.kt @@ -184,3 +184,18 @@ class FuzzyType( return TypeSubstitutor.create(TypeConstructorSubstitution.createByConstructorsMap(substitution)) } } + + +fun TypeSubstitution.hasConflictWith(other: TypeSubstitution, freeParameters: Collection): Boolean { + return freeParameters.any { parameter -> + val type = parameter.defaultType + val substituted1 = this[type] ?: return@any false + val substituted2 = other[type] ?: return@any false + !KotlinTypeChecker.FLEXIBLE_UNEQUAL_TO_INFLEXIBLE.equalTypes(substituted1.type, substituted2.type) || substituted1.projectionKind != substituted2.projectionKind + } +} + +fun TypeSubstitutor.combineIfNoConflicts(other: TypeSubstitutor, freeParameters: Collection): TypeSubstitutor? { + if (this.substitution.hasConflictWith(other.substitution, freeParameters)) return null + return TypeSubstitutor.createChainedSubstitutor(this.substitution, other.substitution) +} diff --git a/idea/idea-completion/testData/smart/propertyDelegate/ConflictingSubstitutors.kt b/idea/idea-completion/testData/smart/propertyDelegate/ConflictingSubstitutors.kt new file mode 100644 index 00000000000..00d4646a3e2 --- /dev/null +++ b/idea/idea-completion/testData/smart/propertyDelegate/ConflictingSubstitutors.kt @@ -0,0 +1,11 @@ +import kotlin.reflect.KProperty + +class X { + operator fun getValue(thisRef: T, property: KProperty<*>): T = throw Exception() +} + +class C { + val property: Int by +} + +// ABSENT: X diff --git a/idea/idea-completion/testData/smart/propertyDelegate/NonConflictingSubstitutors.kt b/idea/idea-completion/testData/smart/propertyDelegate/NonConflictingSubstitutors.kt new file mode 100644 index 00000000000..1aaaaf102fa --- /dev/null +++ b/idea/idea-completion/testData/smart/propertyDelegate/NonConflictingSubstitutors.kt @@ -0,0 +1,11 @@ +import kotlin.reflect.KProperty + +class X(t: T) { + operator fun getValue(thisRef: T, property: KProperty<*>): T = throw Exception() +} + +class C { + val property: C by +} + +// EXIST: { itemText: "X", tailText: "(t: C) ()" } diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmSmartCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmSmartCompletionTestGenerated.java index ec4391d838c..368f04e4efe 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmSmartCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmSmartCompletionTestGenerated.java @@ -1450,6 +1450,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/smart/propertyDelegate"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("ConflictingSubstitutors.kt") + public void testConflictingSubstitutors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/propertyDelegate/ConflictingSubstitutors.kt"); + doTest(fileName); + } + @TestMetadata("DelegatesDot.kt") public void testDelegatesDot() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/propertyDelegate/DelegatesDot.kt"); @@ -1522,6 +1528,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT doTest(fileName); } + @TestMetadata("NonConflictingSubstitutors.kt") + public void testNonConflictingSubstitutors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/propertyDelegate/NonConflictingSubstitutors.kt"); + doTest(fileName); + } + @TestMetadata("Order.kt") public void testOrder() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/propertyDelegate/Order.kt"); diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt index c9c9e7f8352..40b19e7e780 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt @@ -22,10 +22,7 @@ import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.resolve.ideService -import org.jetbrains.kotlin.idea.util.FuzzyType -import org.jetbrains.kotlin.idea.util.fuzzyExtensionReceiverType -import org.jetbrains.kotlin.idea.util.fuzzyReturnType -import org.jetbrains.kotlin.idea.util.getResolutionScope +import org.jetbrains.kotlin.idea.util.* import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* @@ -632,9 +629,9 @@ class ExpectedInfos( val propertyType = explicitPropertyType ?: getValueOperator.fuzzyReturnType()!! val setParamType = FuzzyType(setValueOperator.valueParameters.last().type, setValueOperator.typeParameters) val setParamTypeSubstitutor = setParamType.checkIsSuperTypeOf(propertyType) ?: return null - return TypeSubstitutor.createChainedSubstitutor(getOperatorSubstitutor.substitution, - TypeSubstitutor.createChainedSubstitutor(setOperatorSubstitutor.substitution, - setParamTypeSubstitutor.substitution).substitution) + return getOperatorSubstitutor + .combineIfNoConflicts(setOperatorSubstitutor, descriptorType.freeParameters) + ?.combineIfNoConflicts(setParamTypeSubstitutor, descriptorType.freeParameters) } override val multipleFuzzyTypes: Collection by lazy { diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/TypesWithOperatorDetector.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/TypesWithOperatorDetector.kt index 2020d41d091..beb05a3b285 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/TypesWithOperatorDetector.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/TypesWithOperatorDetector.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.idea.util.FuzzyType +import org.jetbrains.kotlin.idea.util.combineIfNoConflicts import org.jetbrains.kotlin.idea.util.fuzzyExtensionReceiverType import org.jetbrains.kotlin.idea.util.nullability import org.jetbrains.kotlin.incremental.components.NoLookupLocation @@ -138,7 +139,7 @@ class TypesWithGetValueDetector( val fuzzyReturnType = FuzzyType(operator.returnType ?: return null, freeTypeParams) val substitutorFromPropertyType = fuzzyReturnType.checkIsSubtypeOf(propertyType) ?: return null - return TypeSubstitutor.createChainedSubstitutor(substitutor.substitution, substitutorFromPropertyType.substitution) + return substitutor.combineIfNoConflicts(substitutorFromPropertyType, freeTypeParams) } }