Checking for conflicting substitutors in completion after "by"

This commit is contained in:
Valentin Kipyatkov
2016-03-31 22:21:29 +03:00
parent e05d6a7056
commit 24764ed865
6 changed files with 55 additions and 8 deletions
@@ -184,3 +184,18 @@ class FuzzyType(
return TypeSubstitutor.create(TypeConstructorSubstitution.createByConstructorsMap(substitution)) return TypeSubstitutor.create(TypeConstructorSubstitution.createByConstructorsMap(substitution))
} }
} }
fun TypeSubstitution.hasConflictWith(other: TypeSubstitution, freeParameters: Collection<TypeParameterDescriptor>): 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<TypeParameterDescriptor>): TypeSubstitutor? {
if (this.substitution.hasConflictWith(other.substitution, freeParameters)) return null
return TypeSubstitutor.createChainedSubstitutor(this.substitution, other.substitution)
}
@@ -0,0 +1,11 @@
import kotlin.reflect.KProperty
class X<T> {
operator fun getValue(thisRef: T, property: KProperty<*>): T = throw Exception()
}
class C<T> {
val property: Int by <caret>
}
// ABSENT: X
@@ -0,0 +1,11 @@
import kotlin.reflect.KProperty
class X<T>(t: T) {
operator fun getValue(thisRef: T, property: KProperty<*>): T = throw Exception()
}
class C<T> {
val property: C<T> by <caret>
}
// EXIST: { itemText: "X", tailText: "(t: C<T>) (<root>)" }
@@ -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); 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") @TestMetadata("DelegatesDot.kt")
public void testDelegatesDot() throws Exception { public void testDelegatesDot() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/propertyDelegate/DelegatesDot.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/propertyDelegate/DelegatesDot.kt");
@@ -1522,6 +1528,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
doTest(fileName); 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") @TestMetadata("Order.kt")
public void testOrder() throws Exception { public void testOrder() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/propertyDelegate/Order.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/propertyDelegate/Order.kt");
@@ -22,10 +22,7 @@ import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.ideService import org.jetbrains.kotlin.idea.resolve.ideService
import org.jetbrains.kotlin.idea.util.FuzzyType import org.jetbrains.kotlin.idea.util.*
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.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -632,9 +629,9 @@ class ExpectedInfos(
val propertyType = explicitPropertyType ?: getValueOperator.fuzzyReturnType()!! val propertyType = explicitPropertyType ?: getValueOperator.fuzzyReturnType()!!
val setParamType = FuzzyType(setValueOperator.valueParameters.last().type, setValueOperator.typeParameters) val setParamType = FuzzyType(setValueOperator.valueParameters.last().type, setValueOperator.typeParameters)
val setParamTypeSubstitutor = setParamType.checkIsSuperTypeOf(propertyType) ?: return null val setParamTypeSubstitutor = setParamType.checkIsSuperTypeOf(propertyType) ?: return null
return TypeSubstitutor.createChainedSubstitutor(getOperatorSubstitutor.substitution, return getOperatorSubstitutor
TypeSubstitutor.createChainedSubstitutor(setOperatorSubstitutor.substitution, .combineIfNoConflicts(setOperatorSubstitutor, descriptorType.freeParameters)
setParamTypeSubstitutor.substitution).substitution) ?.combineIfNoConflicts(setParamTypeSubstitutor, descriptorType.freeParameters)
} }
override val multipleFuzzyTypes: Collection<FuzzyType> by lazy { override val multipleFuzzyTypes: Collection<FuzzyType> by lazy {
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.idea.util.FuzzyType 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.fuzzyExtensionReceiverType
import org.jetbrains.kotlin.idea.util.nullability import org.jetbrains.kotlin.idea.util.nullability
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
@@ -138,7 +139,7 @@ class TypesWithGetValueDetector(
val fuzzyReturnType = FuzzyType(operator.returnType ?: return null, freeTypeParams) val fuzzyReturnType = FuzzyType(operator.returnType ?: return null, freeTypeParams)
val substitutorFromPropertyType = fuzzyReturnType.checkIsSubtypeOf(propertyType) ?: return null val substitutorFromPropertyType = fuzzyReturnType.checkIsSubtypeOf(propertyType) ?: return null
return TypeSubstitutor.createChainedSubstitutor(substitutor.substitution, substitutorFromPropertyType.substitution) return substitutor.combineIfNoConflicts(substitutorFromPropertyType, freeTypeParams)
} }
} }