Extension methods shown with type arguments substituted in completion list

This commit is contained in:
Valentin Kipyatkov
2014-12-02 13:23:20 +03:00
parent 3df3e57b05
commit 2c08b3e229
9 changed files with 79 additions and 36 deletions
@@ -32,12 +32,12 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.jet.lang.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.jet.lang.resolve.scopes.DescriptorKindFilter
import org.jetbrains.jet.lang.resolve.scopes.DescriptorKindExclude
import org.jetbrains.jet.plugin.util.extensionsUtils.isExtensionCallable
import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.lang.types.TypeUtils
import org.jetbrains.jet.lang.types.checker.JetTypeChecker
import org.jetbrains.jet.lexer.JetTokens
import org.jetbrains.jet.lang.resolve.calls.callUtil.getCall
import org.jetbrains.jet.utils.addIfNotNull
import org.jetbrains.jet.plugin.util.extensionsUtils.substituteExtensionIfCallable
public class ReferenceVariantsHelper(
private val context: BindingContext,
@@ -131,11 +131,13 @@ public class ReferenceVariantsHelper(
val dataFlowInfo = context.getDataFlowInfo(expression)
val receiverValues = receivers.map { it.getValue() }
resolutionScope.getDescriptorsFiltered(kindFilter, nameFilter).filterTo(descriptorsSet) {
if (it is CallableDescriptor && it.getExtensionReceiverParameter() != null)
it.isExtensionCallable(receiverValues, context, dataFlowInfo, false)
else
true
for (descriptor in resolutionScope.getDescriptorsFiltered(kindFilter, nameFilter)) {
if (descriptor is CallableDescriptor && descriptor.getExtensionReceiverParameter() != null) {
descriptorsSet.addIfNotNull(descriptor.substituteExtensionIfCallable(receiverValues, context, dataFlowInfo, false))
}
else {
descriptorsSet.add(descriptor)
}
}
return descriptorsSet
@@ -198,8 +200,10 @@ public class ReferenceVariantsHelper(
nameFilter: (Name) -> Boolean
) {
if (!kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) {
resolutionScope.getDescriptorsFiltered(kindFilter.exclude(DescriptorKindExclude.NonExtensions), nameFilter)
.filterTo(this) { (it as CallableDescriptor).isExtensionCallable(receiver, isInfixCall, context, dataFlowInfo) }
for (callable in resolutionScope.getDescriptorsFiltered(kindFilter.exclude(DescriptorKindExclude.NonExtensions), nameFilter)) {
val substituted = (callable as CallableDescriptor).substituteExtensionIfCallable(receiver, isInfixCall, context, dataFlowInfo)
addIfNotNull(substituted)
}
}
}
@@ -33,52 +33,69 @@ import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintsUtil
import org.jetbrains.jet.utils.addIfNotNull
import java.util.HashSet
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor
import org.jetbrains.jet.lang.types.TypeSubstitutor
public fun CallableDescriptor.isExtensionCallable(receivers: Collection<ReceiverValue>,
//TODO: what if multiple receiver types match? this can result in different substitutions
public fun CallableDescriptor.substituteExtensionIfCallable(receivers: Collection<ReceiverValue>,
context: BindingContext,
dataFlowInfo: DataFlowInfo,
isInfixCall: Boolean): Boolean
= receivers.any { isExtensionCallable(it, isInfixCall, context, dataFlowInfo) }
isInfixCall: Boolean): CallableDescriptor? {
return receivers.stream()
.map { substituteExtensionIfCallable(it, isInfixCall, context, dataFlowInfo) }
.firstOrNull { it != null }
}
public fun CallableDescriptor.isExtensionCallableWithImplicitReceiver(scope: JetScope, context: BindingContext, dataFlowInfo: DataFlowInfo): Boolean
= isExtensionCallable(scope.getImplicitReceiversHierarchy().map { it.getValue() }, context, dataFlowInfo, false)
public fun CallableDescriptor.substituteExtensionIfCallableWithImplicitReceiver(scope: JetScope, context: BindingContext, dataFlowInfo: DataFlowInfo): CallableDescriptor?
= substituteExtensionIfCallable(scope.getImplicitReceiversHierarchy().map { it.getValue() }, context, dataFlowInfo, false)
public fun CallableDescriptor.isExtensionCallable(
public fun CallableDescriptor.substituteExtensionIfCallable(
receiver: ReceiverValue,
isInfixCall: Boolean,
bindingContext: BindingContext,
dataFlowInfo: DataFlowInfo
): Boolean {
): CallableDescriptor? {
val receiverParameter = getExtensionReceiverParameter()!!
if (!receiver.exists()) return false
if (!receiver.exists()) return null
if (isInfixCall && (this !is SimpleFunctionDescriptor || getValueParameters().size() != 1)) {
return false
return null
}
return SmartCastUtils.getSmartCastVariants(receiver, bindingContext, dataFlowInfo)
.any { checkReceiverResolution(it, receiverParameter, getTypeParameters()) }
for (type in SmartCastUtils.getSmartCastVariants(receiver, bindingContext, dataFlowInfo)) {
val substitutor = checkReceiverResolution(type, receiverParameter, getTypeParameters())
if (substitutor != null) {
return substitute(substitutor)
}
}
return null
}
private fun checkReceiverResolution(
receiverType: JetType,
receiverParameter: ReceiverParameterDescriptor,
typeParameters: List<TypeParameterDescriptor>
): Boolean {
val typeNamesInReceiver = HashSet<TypeParameterDescriptor>()
typeNamesInReceiver.addUsedTypeParameters(receiverParameter.getType())
): TypeSubstitutor? {
val typeParamsInReceiver = HashSet<TypeParameterDescriptor>()
typeParamsInReceiver.addUsedTypeParameters(receiverParameter.getType())
val constraintSystem = ConstraintSystemImpl()
val typeVariables = LinkedHashMap<TypeParameterDescriptor, Variance>()
for (typeParameter in typeParameters) {
if (typeNamesInReceiver.contains(typeParameter)) {
if (typeParamsInReceiver.contains(typeParameter)) {
typeVariables[typeParameter] = Variance.INVARIANT
}
}
constraintSystem.registerTypeVariables(typeVariables)
constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), ConstraintPosition.RECEIVER_POSITION)
return constraintSystem.getStatus().isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, true)
if (constraintSystem.getStatus().isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, true)) {
return constraintSystem.getResultingSubstitutor()
}
else {
return null
}
}
private fun MutableSet<TypeParameterDescriptor>.addUsedTypeParameters(jetType: JetType) {