Added better way to construct FuzzyType

This commit is contained in:
Valentin Kipyatkov
2016-03-31 22:40:00 +03:00
parent e18fb20d5a
commit f85de3aac7
11 changed files with 48 additions and 57 deletions
@@ -29,18 +29,11 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.typeUtil.* import org.jetbrains.kotlin.types.typeUtil.*
import java.util.* import java.util.*
fun CallableDescriptor.fuzzyReturnType(): FuzzyType? { fun CallableDescriptor.fuzzyReturnType() = returnType?.toFuzzyType(typeParameters)
val returnType = returnType ?: return null fun CallableDescriptor.fuzzyExtensionReceiverType() = extensionReceiverParameter?.type?.toFuzzyType(typeParameters)
return FuzzyType(returnType, typeParameters)
}
fun CallableDescriptor.fuzzyExtensionReceiverType(): FuzzyType? { fun FuzzyType.makeNotNullable() = type.makeNotNullable().toFuzzyType(freeParameters)
val receiverParameter = extensionReceiverParameter fun FuzzyType.makeNullable() = type.makeNullable().toFuzzyType(freeParameters)
return if (receiverParameter != null) FuzzyType(receiverParameter.type, typeParameters) else null
}
fun FuzzyType.makeNotNullable() = FuzzyType(type.makeNotNullable(), freeParameters)
fun FuzzyType.makeNullable() = FuzzyType(type.makeNullable(), freeParameters)
fun FuzzyType.nullability() = type.nullability() fun FuzzyType.nullability() = type.nullability()
fun FuzzyType.isAlmostEverything(): Boolean { fun FuzzyType.isAlmostEverything(): Boolean {
@@ -70,6 +63,8 @@ fun FuzzyType.presentationType(): KotlinType {
return substitutor.substitute(type, Variance.INVARIANT)!! return substitutor.substitute(type, Variance.INVARIANT)!!
} }
fun KotlinType.toFuzzyType(freeParameters: Collection<TypeParameterDescriptor>) = FuzzyType(this, freeParameters)
class FuzzyType( class FuzzyType(
val type: KotlinType, val type: KotlinType,
freeParameters: Collection<TypeParameterDescriptor> freeParameters: Collection<TypeParameterDescriptor>
@@ -122,10 +117,10 @@ class FuzzyType(
= matchedSubstitutor(otherType, MatchKind.IS_SUPERTYPE) = matchedSubstitutor(otherType, MatchKind.IS_SUPERTYPE)
fun checkIsSubtypeOf(otherType: KotlinType): TypeSubstitutor? fun checkIsSubtypeOf(otherType: KotlinType): TypeSubstitutor?
= checkIsSubtypeOf(FuzzyType(otherType, emptyList())) = checkIsSubtypeOf(otherType.toFuzzyType(emptyList()))
fun checkIsSuperTypeOf(otherType: KotlinType): TypeSubstitutor? fun checkIsSuperTypeOf(otherType: KotlinType): TypeSubstitutor?
= checkIsSuperTypeOf(FuzzyType(otherType, emptyList())) = checkIsSuperTypeOf(otherType.toFuzzyType(emptyList()))
private enum class MatchKind { private enum class MatchKind {
IS_SUBTYPE, IS_SUBTYPE,
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.idea.core.WhenEntryAdditionalData
import org.jetbrains.kotlin.idea.core.fuzzyType import org.jetbrains.kotlin.idea.core.fuzzyType
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
import org.jetbrains.kotlin.idea.util.FuzzyType import org.jetbrains.kotlin.idea.util.toFuzzyType
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.KotlinTypeImpl import org.jetbrains.kotlin.types.KotlinTypeImpl
@@ -98,7 +98,7 @@ object KeywordValues {
if (qualifierType != null) { if (qualifierType != null) {
val kClassDescriptor = resolutionFacade.getFrontendService(ReflectionTypes::class.java).kClass val kClassDescriptor = resolutionFacade.getFrontendService(ReflectionTypes::class.java).kClass
val classLiteralType = KotlinTypeImpl.create(Annotations.EMPTY, kClassDescriptor, false, listOf(TypeProjectionImpl(qualifierType))) val classLiteralType = KotlinTypeImpl.create(Annotations.EMPTY, kClassDescriptor, false, listOf(TypeProjectionImpl(qualifierType)))
val kClassTypes = listOf(FuzzyType(classLiteralType, emptyList())) val kClassTypes = listOf(classLiteralType.toFuzzyType(emptyList()))
val kClassMatcher = { info: ExpectedInfo -> kClassTypes.matchExpectedInfo(info) } val kClassMatcher = { info: ExpectedInfo -> kClassTypes.matchExpectedInfo(info) }
consumer.consume("class", kClassMatcher, SmartCompletionItemPriority.CLASS_LITERAL) { consumer.consume("class", kClassMatcher, SmartCompletionItemPriority.CLASS_LITERAL) {
LookupElementBuilder.create(KeywordLookupObject(), "class").bold() LookupElementBuilder.create(KeywordLookupObject(), "class").bold()
@@ -110,7 +110,7 @@ object KeywordValues {
if (javaLangClassDescriptor != null) { if (javaLangClassDescriptor != null) {
val javaLangClassType = KotlinTypeImpl.create(Annotations.EMPTY, javaLangClassDescriptor, false, listOf(TypeProjectionImpl(qualifierType))) val javaLangClassType = KotlinTypeImpl.create(Annotations.EMPTY, javaLangClassDescriptor, false, listOf(TypeProjectionImpl(qualifierType)))
val javaClassTypes = listOf(FuzzyType(javaLangClassType, emptyList())) val javaClassTypes = listOf(javaLangClassType.toFuzzyType(emptyList()))
val javaClassMatcher = { info: ExpectedInfo -> javaClassTypes.matchExpectedInfo(info) } val javaClassMatcher = { info: ExpectedInfo -> javaClassTypes.matchExpectedInfo(info) }
consumer.consume("class", javaClassMatcher, SmartCompletionItemPriority.CLASS_LITERAL) { consumer.consume("class", javaClassMatcher, SmartCompletionItemPriority.CLASS_LITERAL) {
LookupElementBuilder.create(KeywordLookupObject(), "class.java") LookupElementBuilder.create(KeywordLookupObject(), "class.java")
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.idea.completion.handlers.GenerateLambdaInfo
import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler
import org.jetbrains.kotlin.idea.completion.handlers.lambdaPresentation import org.jetbrains.kotlin.idea.completion.handlers.lambdaPresentation
import org.jetbrains.kotlin.idea.util.CallType import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.idea.util.FuzzyType import org.jetbrains.kotlin.idea.util.toFuzzyType
import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.render import org.jetbrains.kotlin.renderer.render
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
@@ -121,7 +121,7 @@ class LookupElementFactory(
if (isSingleParameter) { if (isSingleParameter) {
//TODO: also ::function? at least for local functions //TODO: also ::function? at least for local functions
//TODO: order for them //TODO: order for them
val fuzzyParameterType = FuzzyType(parameterType, descriptor.typeParameters) val fuzzyParameterType = parameterType.toFuzzyType(descriptor.typeParameters)
for ((variable, substitutor) in contextVariablesProvider.functionTypeVariables(fuzzyParameterType)) { for ((variable, substitutor) in contextVariablesProvider.functionTypeVariables(fuzzyParameterType)) {
val substitutedDescriptor = descriptor.substitute(substitutor) val substitutedDescriptor = descriptor.substitute(substitutor)
add(createFunctionCallElementWithArguments(substitutedDescriptor, variable.name.render(), useReceiverTypes)) add(createFunctionCallElementWithArguments(substitutedDescriptor, variable.name.render(), useReceiverTypes))
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.idea.core.completion.PackageLookupObject
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.CallType import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.idea.util.FuzzyType import org.jetbrains.kotlin.idea.util.FuzzyType
import org.jetbrains.kotlin.idea.util.toFuzzyType
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.findOriginalTopMostOverriddenDescriptors import org.jetbrains.kotlin.resolve.findOriginalTopMostOverriddenDescriptors
@@ -231,7 +232,7 @@ class SmartCompletionInBasicWeigher(
descriptor.fuzzyTypesForSmartCompletion(smartCastCalculator, callType, resolutionFacade) to descriptor.name descriptor.fuzzyTypesForSmartCompletion(smartCastCalculator, callType, resolutionFacade) to descriptor.name
} }
is ThisItemLookupObject -> smartCastCalculator.types(o.receiverParameter).map { FuzzyType(it, emptyList()) } to null is ThisItemLookupObject -> smartCastCalculator.types(o.receiverParameter).map { it.toFuzzyType(emptyList()) } to null
else -> return NO_MATCH_WEIGHT else -> return NO_MATCH_WEIGHT
} }
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
import org.jetbrains.kotlin.idea.util.FuzzyType import org.jetbrains.kotlin.idea.util.FuzzyType
import org.jetbrains.kotlin.idea.util.isAlmostEverything import org.jetbrains.kotlin.idea.util.isAlmostEverything
import org.jetbrains.kotlin.idea.util.toFuzzyType
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
@@ -277,7 +278,7 @@ class SmartCompletion(
if (shouldCompleteThisItems(prefixMatcher)) { if (shouldCompleteThisItems(prefixMatcher)) {
val items = thisExpressionItems(bindingContext, place, prefixMatcher.prefix, resolutionFacade) val items = thisExpressionItems(bindingContext, place, prefixMatcher.prefix, resolutionFacade)
for (item in items) { for (item in items) {
val types = smartCastCalculator.types(item.receiverParameter).map { FuzzyType(it, emptyList()) } val types = smartCastCalculator.types(item.receiverParameter).map { it.toFuzzyType(emptyList()) }
val matcher = { expectedInfo: ExpectedInfo -> types.matchExpectedInfo(expectedInfo) } val matcher = { expectedInfo: ExpectedInfo -> types.matchExpectedInfo(expectedInfo) }
addLookupElements(null, expectedInfos, matcher) { addLookupElements(null, expectedInfos, matcher) {
item.createLookupElement().assignSmartCompletionPriority(SmartCompletionItemPriority.THIS).singletonList() item.createLookupElement().assignSmartCompletionPriority(SmartCompletionItemPriority.THIS).singletonList()
@@ -38,10 +38,7 @@ import org.jetbrains.kotlin.idea.core.Tail
import org.jetbrains.kotlin.idea.core.multipleFuzzyTypes import org.jetbrains.kotlin.idea.core.multipleFuzzyTypes
import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.FuzzyType import org.jetbrains.kotlin.idea.util.*
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.makeNotNullable
import org.jetbrains.kotlin.idea.util.presentationType
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
@@ -316,7 +313,7 @@ class TypeInstantiationItems(
private val baseHasTypeArgs = classDescriptor.declaredTypeParameters.isNotEmpty() private val baseHasTypeArgs = classDescriptor.declaredTypeParameters.isNotEmpty()
private val expectedType = KotlinTypeImpl.create(Annotations.EMPTY, classDescriptor, false, typeArgs) private val expectedType = KotlinTypeImpl.create(Annotations.EMPTY, classDescriptor, false, typeArgs)
private val expectedFuzzyType = FuzzyType(expectedType, freeParameters) private val expectedFuzzyType = expectedType.toFuzzyType(freeParameters)
override fun search(nameFilter: (String) -> Boolean, consumer: (LookupElement) -> Unit) { override fun search(nameFilter: (String) -> Boolean, consumer: (LookupElement) -> Unit) {
val parameters = ClassInheritorsSearch.SearchParameters(psiClass, inheritorSearchScope, true, true, false, nameFilter) val parameters = ClassInheritorsSearch.SearchParameters(psiClass, inheritorSearchScope, true, true, false, nameFilter)
@@ -327,13 +324,13 @@ class TypeInstantiationItems(
) ?: continue ) ?: continue
if (!visibilityFilter(descriptor)) continue if (!visibilityFilter(descriptor)) continue
var inheritorFuzzyType = FuzzyType(descriptor.defaultType, descriptor.typeConstructor.parameters) var inheritorFuzzyType = descriptor.defaultType.toFuzzyType(descriptor.typeConstructor.parameters)
val hasTypeArgs = descriptor.declaredTypeParameters.isNotEmpty() val hasTypeArgs = descriptor.declaredTypeParameters.isNotEmpty()
if (hasTypeArgs || baseHasTypeArgs) { if (hasTypeArgs || baseHasTypeArgs) {
val substitutor = inheritorFuzzyType.checkIsSubtypeOf(expectedFuzzyType) ?: continue val substitutor = inheritorFuzzyType.checkIsSubtypeOf(expectedFuzzyType) ?: continue
if (!substitutor.isEmpty) { if (!substitutor.isEmpty) {
val inheritorTypeSubstituted = substitutor.substitute(inheritorFuzzyType.type, Variance.INVARIANT)!! val inheritorTypeSubstituted = substitutor.substitute(inheritorFuzzyType.type, Variance.INVARIANT)!!
inheritorFuzzyType = FuzzyType(inheritorTypeSubstituted, freeParameters + inheritorFuzzyType.freeParameters) inheritorFuzzyType = inheritorTypeSubstituted.toFuzzyType(freeParameters + inheritorFuzzyType.freeParameters)
} }
} }
@@ -248,8 +248,7 @@ private fun MutableCollection<LookupElement>.addLookupElementsForNullable(factor
fun CallableDescriptor.callableReferenceType(resolutionFacade: ResolutionFacade): FuzzyType? { fun CallableDescriptor.callableReferenceType(resolutionFacade: ResolutionFacade): FuzzyType? {
if (!CallType.CALLABLE_REFERENCE.descriptorKindFilter.accepts(this)) return null // not supported by callable references if (!CallType.CALLABLE_REFERENCE.descriptorKindFilter.accepts(this)) return null // not supported by callable references
val type = getReflectionTypeForCandidateDescriptor(this, resolutionFacade.getFrontendService(ReflectionTypes::class.java)) ?: return null return getReflectionTypeForCandidateDescriptor(this, resolutionFacade.getFrontendService(ReflectionTypes::class.java))?.toFuzzyType(emptyList())
return FuzzyType(type, emptyList())
} }
enum class SmartCompletionItemPriority { enum class SmartCompletionItemPriority {
@@ -294,14 +293,14 @@ fun DeclarationDescriptor.fuzzyTypesForSmartCompletion(
if (returnType.type.isNothing() || returnType.isAlmostEverything()) return emptyList() if (returnType.type.isNothing() || returnType.isAlmostEverything()) return emptyList()
if (this is VariableDescriptor) { //TODO: generic properties! if (this is VariableDescriptor) { //TODO: generic properties!
return smartCastCalculator.types(this).map { FuzzyType(it, emptyList()) } return smartCastCalculator.types(this).map { it.toFuzzyType(emptyList()) }
} }
else { else {
return listOf(returnType) return listOf(returnType)
} }
} }
else if (this is ClassDescriptor && kind.isSingleton) { else if (this is ClassDescriptor && kind.isSingleton) {
return listOf(FuzzyType(defaultType, emptyList())) return listOf(defaultType.toFuzzyType(emptyList()))
} }
else { else {
return emptyList() return emptyList()
@@ -100,15 +100,15 @@ class ExpectedInfo(
: this(ByExpectedTypeFilter(fuzzyType), expectedName, tail, itemOptions, additionalData) : this(ByExpectedTypeFilter(fuzzyType), expectedName, tail, itemOptions, additionalData)
constructor(type: KotlinType, expectedName: String?, tail: Tail?, itemOptions: ItemOptions = ItemOptions.DEFAULT, additionalData: ExpectedInfo.AdditionalData? = null) constructor(type: KotlinType, expectedName: String?, tail: Tail?, itemOptions: ItemOptions = ItemOptions.DEFAULT, additionalData: ExpectedInfo.AdditionalData? = null)
: this(FuzzyType(type, emptyList()), expectedName, tail, itemOptions, additionalData) : this(type.toFuzzyType(emptyList()), expectedName, tail, itemOptions, additionalData)
fun matchingSubstitutor(descriptorType: FuzzyType): TypeSubstitutor? = filter.matchingSubstitutor(descriptorType) fun matchingSubstitutor(descriptorType: FuzzyType): TypeSubstitutor? = filter.matchingSubstitutor(descriptorType)
fun matchingSubstitutor(descriptorType: KotlinType): TypeSubstitutor? = matchingSubstitutor(FuzzyType(descriptorType, emptyList())) fun matchingSubstitutor(descriptorType: KotlinType): TypeSubstitutor? = matchingSubstitutor(descriptorType.toFuzzyType(emptyList()))
companion object { companion object {
fun createForArgument(type: KotlinType, expectedName: String?, tail: Tail?, argumentData: ArgumentPositionData, itemOptions: ItemOptions = ItemOptions.DEFAULT): ExpectedInfo { fun createForArgument(type: KotlinType, expectedName: String?, tail: Tail?, argumentData: ArgumentPositionData, itemOptions: ItemOptions = ItemOptions.DEFAULT): ExpectedInfo {
return ExpectedInfo(FuzzyType(type, argumentData.function.typeParameters), expectedName, tail, itemOptions, argumentData) return ExpectedInfo(type.toFuzzyType(argumentData.function.typeParameters), expectedName, tail, itemOptions, argumentData)
} }
fun createForNamedArgumentExpected(argumentData: ArgumentPositionData): ExpectedInfo { fun createForNamedArgumentExpected(argumentData: ArgumentPositionData): ExpectedInfo {
@@ -116,7 +116,7 @@ class ExpectedInfo(
} }
fun createForReturnValue(type: KotlinType?, callable: CallableDescriptor): ExpectedInfo { fun createForReturnValue(type: KotlinType?, callable: CallableDescriptor): ExpectedInfo {
val filter = if (type != null) ByExpectedTypeFilter(FuzzyType(type, emptyList())) else ByTypeFilter.All val filter = if (type != null) ByExpectedTypeFilter(type.toFuzzyType(emptyList())) else ByTypeFilter.All
return ExpectedInfo(filter, callable.name.asString(), null, additionalData = ReturnValueAdditionalData(callable)) return ExpectedInfo(filter, callable.name.asString(), null, additionalData = ReturnValueAdditionalData(callable))
} }
} }
@@ -494,7 +494,7 @@ class ExpectedInfos(
.filter { it.type.isFunctionType } .filter { it.type.isFunctionType }
.map { .map {
val returnType = getReturnTypeFromFunctionType(it.type) val returnType = getReturnTypeFromFunctionType(it.type)
ExpectedInfo(FuzzyType(returnType, it.freeParameters), null, Tail.RBRACE) ExpectedInfo(returnType.toFuzzyType(it.freeParameters), null, Tail.RBRACE)
} }
} }
else { else {
@@ -611,8 +611,8 @@ class ExpectedInfos(
val scope = expressionWithType.getResolutionScope(bindingContext, resolutionFacade) val scope = expressionWithType.getResolutionScope(bindingContext, resolutionFacade)
val propertyOwnerType = property.fuzzyExtensionReceiverType() val propertyOwnerType = property.fuzzyExtensionReceiverType()
?: property.dispatchReceiverParameter?.type?.let { FuzzyType(it, emptyList()) } ?: property.dispatchReceiverParameter?.type?.toFuzzyType(emptyList())
?: FuzzyType(property.builtIns.nullableNothingType, emptyList()) ?: property.builtIns.nullableNothingType.toFuzzyType(emptyList())
val explicitPropertyType = property.fuzzyReturnType()?.check { propertyDeclaration.typeReference != null } val explicitPropertyType = property.fuzzyReturnType()?.check { propertyDeclaration.typeReference != null }
val typesWithGetDetector = TypesWithGetValueDetector(scope, indicesHelper, propertyOwnerType, explicitPropertyType) val typesWithGetDetector = TypesWithGetValueDetector(scope, indicesHelper, propertyOwnerType, explicitPropertyType)
@@ -624,11 +624,11 @@ class ExpectedInfos(
if (typesWithSetDetector == null) return getOperatorSubstitutor if (typesWithSetDetector == null) return getOperatorSubstitutor
val substitutedType = FuzzyType(getOperatorSubstitutor.substitute(descriptorType.type, Variance.INVARIANT)!!, descriptorType.freeParameters) val substitutedType = getOperatorSubstitutor.substitute(descriptorType.type, Variance.INVARIANT)!!.toFuzzyType(descriptorType.freeParameters)
val (setValueOperator, setOperatorSubstitutor) = typesWithSetDetector.findOperator(substitutedType) ?: return null val (setValueOperator, setOperatorSubstitutor) = typesWithSetDetector.findOperator(substitutedType) ?: return null
val propertyType = explicitPropertyType ?: getValueOperator.fuzzyReturnType()!! val propertyType = explicitPropertyType ?: getValueOperator.fuzzyReturnType()!!
val setParamType = FuzzyType(setValueOperator.valueParameters.last().type, setValueOperator.typeParameters) val setParamType = setValueOperator.valueParameters.last().type.toFuzzyType(setValueOperator.typeParameters)
val setParamTypeSubstitutor = setParamType.checkIsSuperTypeOf(propertyType) ?: return null val setParamTypeSubstitutor = setParamType.checkIsSuperTypeOf(propertyType) ?: return null
return getOperatorSubstitutor return getOperatorSubstitutor
.combineIfNoConflicts(setOperatorSubstitutor, descriptorType.freeParameters) .combineIfNoConflicts(setOperatorSubstitutor, descriptorType.freeParameters)
@@ -641,14 +641,14 @@ class ExpectedInfos(
for (classDescriptor in typesWithGetDetector.classesWithMemberOperators) { for (classDescriptor in typesWithGetDetector.classesWithMemberOperators) {
val type = classDescriptor.defaultType val type = classDescriptor.defaultType
val typeParameters = classDescriptor.declaredTypeParameters val typeParameters = classDescriptor.declaredTypeParameters
val substitutor = matchingSubstitutor(FuzzyType(type, typeParameters)) ?: continue val substitutor = matchingSubstitutor(type.toFuzzyType(typeParameters)) ?: continue
result.add(FuzzyType(substitutor.substitute(type, Variance.INVARIANT)!!, typeParameters)) result.add(substitutor.substitute(type, Variance.INVARIANT)!!.toFuzzyType(typeParameters))
} }
for (extensionOperator in typesWithGetDetector.extensionOperators) { for (extensionOperator in typesWithGetDetector.extensionOperators) {
val receiverType = extensionOperator.fuzzyExtensionReceiverType()!! val receiverType = extensionOperator.fuzzyExtensionReceiverType()!!
val substitutor = matchingSubstitutor(receiverType) ?: continue val substitutor = matchingSubstitutor(receiverType) ?: continue
result.add(FuzzyType(substitutor.substitute(receiverType.type, Variance.INVARIANT)!!, receiverType.freeParameters)) result.add(substitutor.substitute(receiverType.type, Variance.INVARIANT)!!.toFuzzyType(receiverType.freeParameters))
} }
result result
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.core
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
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.toFuzzyType
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
@@ -60,14 +61,14 @@ class IterableTypesDetection(
} }
override fun isIterable(type: KotlinType, loopVarType: KotlinType?): Boolean override fun isIterable(type: KotlinType, loopVarType: KotlinType?): Boolean
= isIterable(FuzzyType(type, emptyList()), loopVarType) = isIterable(type.toFuzzyType(emptyList()), loopVarType)
private fun elementType(type: FuzzyType): FuzzyType? { private fun elementType(type: FuzzyType): FuzzyType? {
return cache.getOrPutNullable(type, { elementTypeNoCache(type) }) return cache.getOrPutNullable(type, { elementTypeNoCache(type) })
} }
override fun elementType(type: KotlinType): FuzzyType? override fun elementType(type: KotlinType): FuzzyType?
= elementType(FuzzyType(type, emptyList())) = elementType(type.toFuzzyType(emptyList()))
private fun elementTypeNoCache(type: FuzzyType): FuzzyType? { private fun elementTypeNoCache(type: FuzzyType): FuzzyType? {
// optimization // optimization
@@ -77,14 +78,14 @@ class IterableTypesDetection(
val context = ExpressionTypingContext.newContext(BindingTraceContext(), scope, DataFlowInfo.EMPTY, TypeUtils.NO_EXPECTED_TYPE) val context = ExpressionTypingContext.newContext(BindingTraceContext(), scope, DataFlowInfo.EMPTY, TypeUtils.NO_EXPECTED_TYPE)
val expressionReceiver = ExpressionReceiver.create(expression, type.type, context.trace.bindingContext) val expressionReceiver = ExpressionReceiver.create(expression, type.type, context.trace.bindingContext)
val elementType = forLoopConventionsChecker.checkIterableConvention(expressionReceiver, context) val elementType = forLoopConventionsChecker.checkIterableConvention(expressionReceiver, context)
return elementType?.let { FuzzyType(it, type.freeParameters) } return elementType?.let { it.toFuzzyType(type.freeParameters) }
} }
private fun canBeIterable(type: FuzzyType): Boolean { private fun canBeIterable(type: FuzzyType): Boolean {
return type.type.memberScope.getContributedFunctions(iteratorName, NoLookupLocation.FROM_IDE).isNotEmpty() || return type.type.memberScope.getContributedFunctions(iteratorName, NoLookupLocation.FROM_IDE).isNotEmpty() ||
typesWithExtensionIterator.any { typesWithExtensionIterator.any {
val freeParams = it.arguments.mapNotNull { it.type.constructor.declarationDescriptor as? TypeParameterDescriptor } val freeParams = it.arguments.mapNotNull { it.type.constructor.declarationDescriptor as? TypeParameterDescriptor }
type.checkIsSubtypeOf(FuzzyType(it, freeParams)) != null type.checkIsSubtypeOf(it.toFuzzyType(freeParams)) != null
} }
} }
} }
@@ -19,10 +19,7 @@ package org.jetbrains.kotlin.idea.core
import org.jetbrains.kotlin.descriptors.ClassDescriptor 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.*
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 import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope
@@ -119,7 +116,7 @@ class TypesWithContainsDetector(
override fun checkIsSuitableByType(operator: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): TypeSubstitutor? { override fun checkIsSuitableByType(operator: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): TypeSubstitutor? {
val parameter = operator.valueParameters.single() val parameter = operator.valueParameters.single()
val fuzzyParameterType = FuzzyType(parameter.type, operator.typeParameters + freeTypeParams) val fuzzyParameterType = parameter.type.toFuzzyType(operator.typeParameters + freeTypeParams)
return fuzzyParameterType.checkIsSuperTypeOf(argumentType) return fuzzyParameterType.checkIsSuperTypeOf(argumentType)
} }
} }
@@ -132,12 +129,12 @@ class TypesWithGetValueDetector(
) : TypesWithOperatorDetector(OperatorNameConventions.GET_VALUE, scope, indicesHelper) { ) : TypesWithOperatorDetector(OperatorNameConventions.GET_VALUE, scope, indicesHelper) {
override fun checkIsSuitableByType(operator: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): TypeSubstitutor? { override fun checkIsSuitableByType(operator: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): TypeSubstitutor? {
val paramType = FuzzyType(operator.valueParameters.first().type, freeTypeParams) val paramType = operator.valueParameters.first().type.toFuzzyType(freeTypeParams)
val substitutor = paramType.checkIsSuperTypeOf(propertyOwnerType) ?: return null val substitutor = paramType.checkIsSuperTypeOf(propertyOwnerType) ?: return null
if (propertyType == null) return substitutor if (propertyType == null) return substitutor
val fuzzyReturnType = FuzzyType(operator.returnType ?: return null, freeTypeParams) val fuzzyReturnType = operator.returnType?.toFuzzyType(freeTypeParams) ?: return null
val substitutorFromPropertyType = fuzzyReturnType.checkIsSubtypeOf(propertyType) ?: return null val substitutorFromPropertyType = fuzzyReturnType.checkIsSubtypeOf(propertyType) ?: return null
return substitutor.combineIfNoConflicts(substitutorFromPropertyType, freeTypeParams) return substitutor.combineIfNoConflicts(substitutorFromPropertyType, freeTypeParams)
} }
@@ -150,7 +147,7 @@ class TypesWithSetValueDetector(
) : TypesWithOperatorDetector(OperatorNameConventions.SET_VALUE, scope, indicesHelper) { ) : TypesWithOperatorDetector(OperatorNameConventions.SET_VALUE, scope, indicesHelper) {
override fun checkIsSuitableByType(operator: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): TypeSubstitutor? { override fun checkIsSuitableByType(operator: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): TypeSubstitutor? {
val paramType = FuzzyType(operator.valueParameters.first().type, freeTypeParams) val paramType = operator.valueParameters.first().type.toFuzzyType(freeTypeParams)
return paramType.checkIsSuperTypeOf(propertyOwnerType) return paramType.checkIsSuperTypeOf(propertyOwnerType)
} }
} }
@@ -23,8 +23,8 @@ import org.jetbrains.kotlin.idea.core.ExpectedInfo
import org.jetbrains.kotlin.idea.core.ExpectedInfos import org.jetbrains.kotlin.idea.core.ExpectedInfos
import org.jetbrains.kotlin.idea.core.SmartCastCalculator import org.jetbrains.kotlin.idea.core.SmartCastCalculator
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
import org.jetbrains.kotlin.idea.util.FuzzyType
import org.jetbrains.kotlin.idea.util.getResolutionScope import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.idea.util.toFuzzyType
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtNameReferenceExpression import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
@@ -55,6 +55,6 @@ class SuitableVariableMacro : BaseKotlinVariableMacro<SuitableVariableMacro.Stat
override fun isSuitable(variableDescriptor: VariableDescriptor, project: Project, state: State?): Boolean { override fun isSuitable(variableDescriptor: VariableDescriptor, project: Project, state: State?): Boolean {
if (state == null) return true if (state == null) return true
val types = state.smartCastCalculator.types(variableDescriptor) val types = state.smartCastCalculator.types(variableDescriptor)
return state.expectedInfos.any { expectedInfo -> types.any { expectedInfo.filter.matchingSubstitutor(FuzzyType(it, emptyList())) != null } } return state.expectedInfos.any { expectedInfo -> types.any { expectedInfo.filter.matchingSubstitutor(it.toFuzzyType(emptyList())) != null } }
} }
} }