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))
}
}
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);
}
@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");
@@ -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<FuzzyType> by lazy {
@@ -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)
}
}