diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java index d7c401bfefd..8d71a939d30 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java @@ -17,7 +17,6 @@ package org.jetbrains.jet.lang.types.expressions; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiElement; @@ -34,14 +33,8 @@ import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.calls.CallResolver; import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage; -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition; -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem; -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl; -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintsUtil; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults; -import org.jetbrains.jet.lang.resolve.calls.smartcasts.DataFlowInfo; -import org.jetbrains.jet.lang.resolve.calls.smartcasts.SmartCastUtils; import org.jetbrains.jet.lang.resolve.calls.util.CallMaker; import org.jetbrains.jet.lang.resolve.dataClassUtils.DataClassUtilsPackage; import org.jetbrains.jet.lang.resolve.name.Name; @@ -50,13 +43,18 @@ import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; -import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lang.types.ErrorUtils; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.JetTypeInfo; +import org.jetbrains.jet.lang.types.TypeUtils; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.util.slicedmap.WritableSlice; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory; @@ -188,76 +186,6 @@ public class ExpressionTypingUtils { } } - /* - * Checks if receiver declaration could be resolved to call expected receiver. - */ - public static boolean checkIsExtensionCallable ( - @NotNull ReceiverValue receiverArgument, - @NotNull CallableDescriptor callableDescriptor, - boolean isInfixCall, - @NotNull BindingContext bindingContext, - @NotNull DataFlowInfo dataFlowInfo - ) { - if (isInfixCall - && (!(callableDescriptor instanceof SimpleFunctionDescriptor) || callableDescriptor.getValueParameters().size() != 1)) { - return false; - } - - List types = SmartCastUtils.getSmartCastVariants(receiverArgument, bindingContext, dataFlowInfo); - - for (JetType type : types) { - if (checkReceiverResolution(receiverArgument, type, callableDescriptor)) return true; - } - - return false; - } - - private static boolean checkReceiverResolution ( - @NotNull ReceiverValue receiverArgument, - @NotNull JetType receiverType, - @NotNull CallableDescriptor callableDescriptor - ) { - ReceiverParameterDescriptor receiverParameter = callableDescriptor.getExtensionReceiverParameter(); - - if (!receiverArgument.exists() && receiverParameter == null) { - // Both receivers do not exist - return true; - } - - if (!(receiverArgument.exists() && receiverParameter != null)) { - return false; - } - - Set typeNamesInReceiver = collectUsedTypeNames(receiverParameter.getType()); - - ConstraintSystem constraintSystem = new ConstraintSystemImpl(); - Map typeVariables = Maps.newLinkedHashMap(); - for (TypeParameterDescriptor typeParameterDescriptor : callableDescriptor.getTypeParameters()) { - if (typeNamesInReceiver.contains(typeParameterDescriptor.getName())) { - typeVariables.put(typeParameterDescriptor, Variance.INVARIANT); - } - } - constraintSystem.registerTypeVariables(typeVariables); - - constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), ConstraintPosition.RECEIVER_POSITION); - return constraintSystem.getStatus().isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, true); - } - - private static Set collectUsedTypeNames(@NotNull JetType jetType) { - Set typeNames = new HashSet(); - - ClassifierDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); - if (descriptor != null) { - typeNames.add(descriptor.getName()); - } - - for (TypeProjection argument : jetType.getArguments()) { - typeNames.addAll(collectUsedTypeNames(argument.getType())); - } - - return typeNames; - } - @NotNull public OverloadResolutionResults resolveFakeCall( @NotNull ExpressionTypingContext context, diff --git a/idea/src/org/jetbrains/jet/plugin/caches/KotlinIndicesHelper.kt b/idea/src/org/jetbrains/jet/plugin/caches/KotlinIndicesHelper.kt index b78fdfa3fe4..5f3b4a25c1f 100644 --- a/idea/src/org/jetbrains/jet/plugin/caches/KotlinIndicesHelper.kt +++ b/idea/src/org/jetbrains/jet/plugin/caches/KotlinIndicesHelper.kt @@ -26,7 +26,6 @@ import org.jetbrains.jet.lang.psi.* import org.jetbrains.jet.lang.resolve.* import org.jetbrains.jet.lang.resolve.name.Name import org.jetbrains.jet.lang.psi.psiUtil.getReceiverExpression -import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils import org.jetbrains.jet.lang.resolve.scopes.JetScope import com.intellij.openapi.project.Project import java.util.HashSet @@ -36,7 +35,7 @@ import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver.LookupMode import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue import org.jetbrains.jet.lang.resolve.calls.smartcasts.DataFlowInfo import com.intellij.psi.stubs.StringStubIndexExtension -import org.jetbrains.jet.plugin.caches.resolve.getLazyResolveSession +import org.jetbrains.jet.plugin.codeInsight.TipsManager public class KotlinIndicesHelper(private val project: Project, private val resolveSession: ResolveSessionForBodies, @@ -213,7 +212,7 @@ public class KotlinIndicesHelper(private val project: Project, } return descriptors.filter { visibilityFilter(it) && - ExpressionTypingUtils.checkIsExtensionCallable(receiverValue, it, isInfixCall, bindingContext, dataFlowInfo) } + TipsManager.checkIsExtensionCallable(receiverValue, it, isInfixCall, bindingContext, dataFlowInfo) } } public fun getClassDescriptors(nameFilter: (String) -> Boolean, kindFilter: (ClassKind) -> Boolean): Collection { diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.kt b/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.kt index cae9d2a6913..9e712b525a4 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.kt +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.kt @@ -24,7 +24,6 @@ import org.jetbrains.jet.lang.resolve.calls.smartcasts.SmartCastUtils import org.jetbrains.jet.lang.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.jet.lang.resolve.scopes.JetScope import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver -import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils import java.util.* import org.jetbrains.jet.lang.resolve.bindingContextUtil.getDataFlowInfo @@ -33,6 +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.lang.types.JetType +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl +import com.google.dart.compiler.util.Maps +import org.jetbrains.jet.lang.types.Variance +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintsUtil public object TipsManager{ @@ -148,7 +153,7 @@ public object TipsManager{ resolutionScope.getDescriptorsFiltered(kindFilter, nameFilter) .stream() .filterIsInstance(javaClass()) - .filterTo(this) { ExpressionTypingUtils.checkIsExtensionCallable(receiver, it, isInfixCall, context, dataFlowInfo) } + .filterTo(this) { checkIsExtensionCallable(receiver, it, isInfixCall, context, dataFlowInfo) } } } @@ -156,7 +161,7 @@ public object TipsManager{ context: BindingContext, dataFlowInfo: DataFlowInfo, isInfixCall: Boolean): Boolean - = receivers.any { ExpressionTypingUtils.checkIsExtensionCallable(it, this, isInfixCall, context, dataFlowInfo) } + = receivers.any { checkIsExtensionCallable(it, this, isInfixCall, context, dataFlowInfo) } public fun CallableDescriptor.isExtensionCallableWithImplicitReceiver(scope: JetScope, context: BindingContext, dataFlowInfo: DataFlowInfo): Boolean = isExtensionCallable(scope.getImplicitReceiversHierarchy().map { it.getValue() }, context, dataFlowInfo, false) @@ -167,4 +172,69 @@ public object TipsManager{ val resolutionScope = context[BindingContext.RESOLUTION_SCOPE, expression] ?: return listOf() return resolutionScope.getDescriptorsFiltered(DescriptorKindFilter.PACKAGES, nameFilter) } + + /* + * Checks if receiver declaration could be resolved to call expected receiver. + */ + public fun checkIsExtensionCallable( + receiverArgument: ReceiverValue, + callableDescriptor: CallableDescriptor, + isInfixCall: Boolean, + bindingContext: BindingContext, + dataFlowInfo: DataFlowInfo + ): Boolean { + if (isInfixCall && (callableDescriptor !is SimpleFunctionDescriptor || callableDescriptor.getValueParameters().size() != 1)) { + return false + } + + val types = SmartCastUtils.getSmartCastVariants(receiverArgument, bindingContext, dataFlowInfo) + + for (type in types) { + if (checkReceiverResolution(receiverArgument, type, callableDescriptor)) return true + } + + return false + } + + private fun checkReceiverResolution(receiverArgument: ReceiverValue, receiverType: JetType, callableDescriptor: CallableDescriptor): Boolean { + val receiverParameter = callableDescriptor.getExtensionReceiverParameter() + + if (!receiverArgument.exists() && receiverParameter == null) { + // Both receivers do not exist + return true + } + + if (!(receiverArgument.exists() && receiverParameter != null)) { + return false + } + + val typeNamesInReceiver = collectUsedTypeNames(receiverParameter.getType()) + + val constraintSystem = ConstraintSystemImpl() + val typeVariables = LinkedHashMap() + for (typeParameterDescriptor in callableDescriptor.getTypeParameters()) { + if (typeNamesInReceiver.contains(typeParameterDescriptor.getName())) { + typeVariables.put(typeParameterDescriptor, Variance.INVARIANT) + } + } + constraintSystem.registerTypeVariables(typeVariables) + + constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), ConstraintPosition.RECEIVER_POSITION) + return constraintSystem.getStatus().isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, true) + } + + private fun collectUsedTypeNames(jetType: JetType): Set { + val typeNames = HashSet() + + val descriptor = jetType.getConstructor().getDeclarationDescriptor() + if (descriptor != null) { + typeNames.add(descriptor.getName()) + } + + for (argument in jetType.getArguments()) { + typeNames.addAll(collectUsedTypeNames(argument.getType())) + } + + return typeNames + } }