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 java.util.*
fun CallableDescriptor.fuzzyReturnType(): FuzzyType? {
val returnType = returnType ?: return null
return FuzzyType(returnType, typeParameters)
}
fun CallableDescriptor.fuzzyReturnType() = returnType?.toFuzzyType(typeParameters)
fun CallableDescriptor.fuzzyExtensionReceiverType() = extensionReceiverParameter?.type?.toFuzzyType(typeParameters)
fun CallableDescriptor.fuzzyExtensionReceiverType(): FuzzyType? {
val receiverParameter = extensionReceiverParameter
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.makeNotNullable() = type.makeNotNullable().toFuzzyType(freeParameters)
fun FuzzyType.makeNullable() = type.makeNullable().toFuzzyType(freeParameters)
fun FuzzyType.nullability() = type.nullability()
fun FuzzyType.isAlmostEverything(): Boolean {
@@ -70,6 +63,8 @@ fun FuzzyType.presentationType(): KotlinType {
return substitutor.substitute(type, Variance.INVARIANT)!!
}
fun KotlinType.toFuzzyType(freeParameters: Collection<TypeParameterDescriptor>) = FuzzyType(this, freeParameters)
class FuzzyType(
val type: KotlinType,
freeParameters: Collection<TypeParameterDescriptor>
@@ -122,10 +117,10 @@ class FuzzyType(
= matchedSubstitutor(otherType, MatchKind.IS_SUPERTYPE)
fun checkIsSubtypeOf(otherType: KotlinType): TypeSubstitutor?
= checkIsSubtypeOf(FuzzyType(otherType, emptyList()))
= checkIsSubtypeOf(otherType.toFuzzyType(emptyList()))
fun checkIsSuperTypeOf(otherType: KotlinType): TypeSubstitutor?
= checkIsSuperTypeOf(FuzzyType(otherType, emptyList()))
= checkIsSuperTypeOf(otherType.toFuzzyType(emptyList()))
private enum class MatchKind {
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.resolve.ResolutionFacade
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.resolve.BindingContext
import org.jetbrains.kotlin.types.KotlinTypeImpl
@@ -98,7 +98,7 @@ object KeywordValues {
if (qualifierType != null) {
val kClassDescriptor = resolutionFacade.getFrontendService(ReflectionTypes::class.java).kClass
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) }
consumer.consume("class", kClassMatcher, SmartCompletionItemPriority.CLASS_LITERAL) {
LookupElementBuilder.create(KeywordLookupObject(), "class").bold()
@@ -110,7 +110,7 @@ object KeywordValues {
if (javaLangClassDescriptor != null) {
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) }
consumer.consume("class", javaClassMatcher, SmartCompletionItemPriority.CLASS_LITERAL) {
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.lambdaPresentation
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.render
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
@@ -121,7 +121,7 @@ class LookupElementFactory(
if (isSingleParameter) {
//TODO: also ::function? at least for local functions
//TODO: order for them
val fuzzyParameterType = FuzzyType(parameterType, descriptor.typeParameters)
val fuzzyParameterType = parameterType.toFuzzyType(descriptor.typeParameters)
for ((variable, substitutor) in contextVariablesProvider.functionTypeVariables(fuzzyParameterType)) {
val substitutedDescriptor = descriptor.substitute(substitutor)
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.util.CallType
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.findOriginalTopMostOverriddenDescriptors
@@ -231,7 +232,7 @@ class SmartCompletionInBasicWeigher(
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
}
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
import org.jetbrains.kotlin.idea.util.FuzzyType
import org.jetbrains.kotlin.idea.util.isAlmostEverything
import org.jetbrains.kotlin.idea.util.toFuzzyType
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
@@ -277,7 +278,7 @@ class SmartCompletion(
if (shouldCompleteThisItems(prefixMatcher)) {
val items = thisExpressionItems(bindingContext, place, prefixMatcher.prefix, resolutionFacade)
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) }
addLookupElements(null, expectedInfos, matcher) {
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.overrideImplement.ImplementMembersHandler
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.FuzzyType
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.idea.util.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
@@ -316,7 +313,7 @@ class TypeInstantiationItems(
private val baseHasTypeArgs = classDescriptor.declaredTypeParameters.isNotEmpty()
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) {
val parameters = ClassInheritorsSearch.SearchParameters(psiClass, inheritorSearchScope, true, true, false, nameFilter)
@@ -327,13 +324,13 @@ class TypeInstantiationItems(
) ?: 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()
if (hasTypeArgs || baseHasTypeArgs) {
val substitutor = inheritorFuzzyType.checkIsSubtypeOf(expectedFuzzyType) ?: continue
if (!substitutor.isEmpty) {
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? {
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 FuzzyType(type, emptyList())
return getReflectionTypeForCandidateDescriptor(this, resolutionFacade.getFrontendService(ReflectionTypes::class.java))?.toFuzzyType(emptyList())
}
enum class SmartCompletionItemPriority {
@@ -294,14 +293,14 @@ fun DeclarationDescriptor.fuzzyTypesForSmartCompletion(
if (returnType.type.isNothing() || returnType.isAlmostEverything()) return emptyList()
if (this is VariableDescriptor) { //TODO: generic properties!
return smartCastCalculator.types(this).map { FuzzyType(it, emptyList()) }
return smartCastCalculator.types(this).map { it.toFuzzyType(emptyList()) }
}
else {
return listOf(returnType)
}
}
else if (this is ClassDescriptor && kind.isSingleton) {
return listOf(FuzzyType(defaultType, emptyList()))
return listOf(defaultType.toFuzzyType(emptyList()))
}
else {
return emptyList()
@@ -100,15 +100,15 @@ class ExpectedInfo(
: this(ByExpectedTypeFilter(fuzzyType), expectedName, tail, itemOptions, additionalData)
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: KotlinType): TypeSubstitutor? = matchingSubstitutor(FuzzyType(descriptorType, emptyList()))
fun matchingSubstitutor(descriptorType: KotlinType): TypeSubstitutor? = matchingSubstitutor(descriptorType.toFuzzyType(emptyList()))
companion object {
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 {
@@ -116,7 +116,7 @@ class 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))
}
}
@@ -494,7 +494,7 @@ class ExpectedInfos(
.filter { it.type.isFunctionType }
.map {
val returnType = getReturnTypeFromFunctionType(it.type)
ExpectedInfo(FuzzyType(returnType, it.freeParameters), null, Tail.RBRACE)
ExpectedInfo(returnType.toFuzzyType(it.freeParameters), null, Tail.RBRACE)
}
}
else {
@@ -611,8 +611,8 @@ class ExpectedInfos(
val scope = expressionWithType.getResolutionScope(bindingContext, resolutionFacade)
val propertyOwnerType = property.fuzzyExtensionReceiverType()
?: property.dispatchReceiverParameter?.type?.let { FuzzyType(it, emptyList()) }
?: FuzzyType(property.builtIns.nullableNothingType, emptyList())
?: property.dispatchReceiverParameter?.type?.toFuzzyType(emptyList())
?: property.builtIns.nullableNothingType.toFuzzyType(emptyList())
val explicitPropertyType = property.fuzzyReturnType()?.check { propertyDeclaration.typeReference != null }
val typesWithGetDetector = TypesWithGetValueDetector(scope, indicesHelper, propertyOwnerType, explicitPropertyType)
@@ -624,11 +624,11 @@ class ExpectedInfos(
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 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
return getOperatorSubstitutor
.combineIfNoConflicts(setOperatorSubstitutor, descriptorType.freeParameters)
@@ -641,14 +641,14 @@ class ExpectedInfos(
for (classDescriptor in typesWithGetDetector.classesWithMemberOperators) {
val type = classDescriptor.defaultType
val typeParameters = classDescriptor.declaredTypeParameters
val substitutor = matchingSubstitutor(FuzzyType(type, typeParameters)) ?: continue
result.add(FuzzyType(substitutor.substitute(type, Variance.INVARIANT)!!, typeParameters))
val substitutor = matchingSubstitutor(type.toFuzzyType(typeParameters)) ?: continue
result.add(substitutor.substitute(type, Variance.INVARIANT)!!.toFuzzyType(typeParameters))
}
for (extensionOperator in typesWithGetDetector.extensionOperators) {
val receiverType = extensionOperator.fuzzyExtensionReceiverType()!!
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
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.core
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
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.name.Name
import org.jetbrains.kotlin.psi.KtPsiFactory
@@ -60,14 +61,14 @@ class IterableTypesDetection(
}
override fun isIterable(type: KotlinType, loopVarType: KotlinType?): Boolean
= isIterable(FuzzyType(type, emptyList()), loopVarType)
= isIterable(type.toFuzzyType(emptyList()), loopVarType)
private fun elementType(type: FuzzyType): FuzzyType? {
return cache.getOrPutNullable(type, { elementTypeNoCache(type) })
}
override fun elementType(type: KotlinType): FuzzyType?
= elementType(FuzzyType(type, emptyList()))
= elementType(type.toFuzzyType(emptyList()))
private fun elementTypeNoCache(type: FuzzyType): FuzzyType? {
// optimization
@@ -77,14 +78,14 @@ class IterableTypesDetection(
val context = ExpressionTypingContext.newContext(BindingTraceContext(), scope, DataFlowInfo.EMPTY, TypeUtils.NO_EXPECTED_TYPE)
val expressionReceiver = ExpressionReceiver.create(expression, type.type, context.trace.bindingContext)
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 {
return type.type.memberScope.getContributedFunctions(iteratorName, NoLookupLocation.FROM_IDE).isNotEmpty() ||
typesWithExtensionIterator.any {
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.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.idea.util.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
@@ -119,7 +116,7 @@ class TypesWithContainsDetector(
override fun checkIsSuitableByType(operator: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): TypeSubstitutor? {
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)
}
}
@@ -132,12 +129,12 @@ class TypesWithGetValueDetector(
) : TypesWithOperatorDetector(OperatorNameConventions.GET_VALUE, scope, indicesHelper) {
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
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
return substitutor.combineIfNoConflicts(substitutorFromPropertyType, freeTypeParams)
}
@@ -150,7 +147,7 @@ class TypesWithSetValueDetector(
) : TypesWithOperatorDetector(OperatorNameConventions.SET_VALUE, scope, indicesHelper) {
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)
}
}
@@ -23,8 +23,8 @@ import org.jetbrains.kotlin.idea.core.ExpectedInfo
import org.jetbrains.kotlin.idea.core.ExpectedInfos
import org.jetbrains.kotlin.idea.core.SmartCastCalculator
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.toFuzzyType
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
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 {
if (state == null) return true
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 } }
}
}