Extract method to fully or partially resolve callable reference

Reuse it in the main type-checking path in DoubleColonExpressionResolver, as
well as in ArgumentTypeResolver which handles the case when a callable
reference appears as an argument to another call
This commit is contained in:
Alexander Udalov
2016-05-04 15:09:48 +03:00
parent 693c753988
commit a3b38cf6ed
4 changed files with 65 additions and 65 deletions
@@ -53,15 +53,6 @@ import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
import org.jetbrains.kotlin.utils.Printer import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.kotlin.utils.ThrowingList import org.jetbrains.kotlin.utils.ThrowingList
fun resolveCallableReferenceReceiverType(
callableReferenceExpression: KtCallableReferenceExpression,
context: ResolutionContext<*>,
typeResolver: TypeResolver
): KotlinType? =
callableReferenceExpression.typeReference?.let {
typeResolver.resolveType(context.scope, it, context.trace, false)
}
private fun <D : CallableDescriptor> ResolveArgumentsMode.acceptResolution(results: OverloadResolutionResults<D>, trace: TemporaryTraceAndCache) { private fun <D : CallableDescriptor> ResolveArgumentsMode.acceptResolution(results: OverloadResolutionResults<D>, trace: TemporaryTraceAndCache) {
when (this) { when (this) {
ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS -> ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS ->
@@ -159,28 +150,6 @@ fun resolvePossiblyAmbiguousCallableReference(
return null return null
} }
fun resolveCallableReferenceTarget(
callableReferenceExpression: KtCallableReferenceExpression,
lhsType: KotlinType?,
context: ResolutionContext<*>,
resolvedToSomething: BooleanArray,
callResolver: CallResolver
): CallableDescriptor? {
val resolutionResults = resolvePossiblyAmbiguousCallableReference(
callableReferenceExpression, lhsType, context, ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS, callResolver)
return resolutionResults?.let { results ->
if (results.isSomething()) {
resolvedToSomething[0] = true
OverloadResolutionResultsUtil.getResultingCall(results, context.contextDependency)?.let { call ->
call.resultingDescriptor
}
}
else {
null
}
}
}
private fun bindFunctionReference(expression: KtCallableReferenceExpression, type: KotlinType, context: ResolutionContext<*>) { private fun bindFunctionReference(expression: KtCallableReferenceExpression, type: KotlinType, context: ResolutionContext<*>) {
val functionDescriptor = AnonymousFunctionDescriptor( val functionDescriptor = AnonymousFunctionDescriptor(
context.scope.ownerDescriptor, context.scope.ownerDescriptor,
@@ -287,7 +256,7 @@ fun createReflectionTypeForResolvedCallableReference(
fun getResolvedCallableReferenceShapeType( fun getResolvedCallableReferenceShapeType(
reference: KtCallableReferenceExpression, reference: KtCallableReferenceExpression,
lhsType: KotlinType?, lhsType: KotlinType?,
overloadResolutionResults: OverloadResolutionResults<CallableDescriptor>?, overloadResolutionResults: OverloadResolutionResults<*>?,
context: ResolutionContext<*>, context: ResolutionContext<*>,
expectedTypeUnknown: Boolean, expectedTypeUnknown: Boolean,
reflectionTypes: ReflectionTypes, reflectionTypes: ReflectionTypes,
@@ -17,11 +17,11 @@
package org.jetbrains.kotlin.resolve.calls; package org.jetbrains.kotlin.resolve.calls;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import kotlin.Pair;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.builtins.ReflectionTypes; import org.jetbrains.kotlin.builtins.ReflectionTypes;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.annotations.Annotations; import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
@@ -45,10 +45,10 @@ import org.jetbrains.kotlin.types.FunctionPlaceholdersKt;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeUtils; import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices; import org.jetbrains.kotlin.types.expressions.*;
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo;
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt; import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
import javax.inject.Inject;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@@ -63,31 +63,36 @@ import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
public class ArgumentTypeResolver { public class ArgumentTypeResolver {
@NotNull private final TypeResolver typeResolver; @NotNull private final TypeResolver typeResolver;
@NotNull private final CallResolver callResolver; @NotNull private final DoubleColonExpressionResolver doubleColonExpressionResolver;
@NotNull private final ExpressionTypingServices expressionTypingServices;
@NotNull private final KotlinBuiltIns builtIns; @NotNull private final KotlinBuiltIns builtIns;
@NotNull private final ReflectionTypes reflectionTypes; @NotNull private final ReflectionTypes reflectionTypes;
@NotNull private final ConstantExpressionEvaluator constantExpressionEvaluator; @NotNull private final ConstantExpressionEvaluator constantExpressionEvaluator;
@NotNull private final FunctionPlaceholders functionPlaceholders; @NotNull private final FunctionPlaceholders functionPlaceholders;
private ExpressionTypingServices expressionTypingServices;
public ArgumentTypeResolver( public ArgumentTypeResolver(
@NotNull TypeResolver typeResolver, @NotNull TypeResolver typeResolver,
@NotNull CallResolver callResolver, @NotNull DoubleColonExpressionResolver doubleColonExpressionResolver,
@NotNull ExpressionTypingServices expressionTypingServices,
@NotNull KotlinBuiltIns builtIns, @NotNull KotlinBuiltIns builtIns,
@NotNull ReflectionTypes reflectionTypes, @NotNull ReflectionTypes reflectionTypes,
@NotNull ConstantExpressionEvaluator constantExpressionEvaluator, @NotNull ConstantExpressionEvaluator constantExpressionEvaluator,
@NotNull FunctionPlaceholders functionPlaceholders @NotNull FunctionPlaceholders functionPlaceholders
) { ) {
this.typeResolver = typeResolver; this.typeResolver = typeResolver;
this.callResolver = callResolver; this.doubleColonExpressionResolver = doubleColonExpressionResolver;
this.expressionTypingServices = expressionTypingServices;
this.builtIns = builtIns; this.builtIns = builtIns;
this.reflectionTypes = reflectionTypes; this.reflectionTypes = reflectionTypes;
this.constantExpressionEvaluator = constantExpressionEvaluator; this.constantExpressionEvaluator = constantExpressionEvaluator;
this.functionPlaceholders = functionPlaceholders; this.functionPlaceholders = functionPlaceholders;
} }
// component dependency cycle
@Inject
public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) {
this.expressionTypingServices = expressionTypingServices;
}
public static boolean isSubtypeOfForArgumentType( public static boolean isSubtypeOfForArgumentType(
@NotNull KotlinType actualType, @NotNull KotlinType actualType,
@NotNull KotlinType expectedType @NotNull KotlinType expectedType
@@ -238,14 +243,17 @@ public class ArgumentTypeResolver {
@NotNull CallResolutionContext<?> context, @NotNull CallResolutionContext<?> context,
boolean expectedTypeIsUnknown boolean expectedTypeIsUnknown
) { ) {
KotlinType receiverType = Pair<DoubleColonLHS, OverloadResolutionResults<?>> pair =
CallableReferencesResolutionUtilsKt.resolveCallableReferenceReceiverType(callableReferenceExpression, context, typeResolver); doubleColonExpressionResolver.resolveCallableReference(
OverloadResolutionResults<CallableDescriptor> overloadResolutionResults = callableReferenceExpression,
CallableReferencesResolutionUtilsKt.resolvePossiblyAmbiguousCallableReference( ExpressionTypingContext.newContext(context),
callableReferenceExpression, receiverType, context, ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS, SHAPE_FUNCTION_ARGUMENTS
callResolver); );
DoubleColonLHS lhs = pair.getFirst();
KotlinType receiverType = lhs != null ? lhs.getType() : null;
return CallableReferencesResolutionUtilsKt.getResolvedCallableReferenceShapeType( return CallableReferencesResolutionUtilsKt.getResolvedCallableReferenceShapeType(
callableReferenceExpression, receiverType, overloadResolutionResults, context, expectedTypeIsUnknown, callableReferenceExpression, receiverType, pair.getSecond(), context, expectedTypeIsUnknown,
reflectionTypes, builtIns, functionPlaceholders reflectionTypes, builtIns, functionPlaceholders
); );
} }
@@ -28,11 +28,14 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode
import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.callableReferences.createReflectionTypeForResolvedCallableReference import org.jetbrains.kotlin.resolve.callableReferences.createReflectionTypeForResolvedCallableReference
import org.jetbrains.kotlin.resolve.callableReferences.resolveCallableReferenceTarget import org.jetbrains.kotlin.resolve.callableReferences.resolvePossiblyAmbiguousCallableReference
import org.jetbrains.kotlin.resolve.calls.CallExpressionResolver import org.jetbrains.kotlin.resolve.calls.CallExpressionResolver
import org.jetbrains.kotlin.resolve.calls.CallResolver import org.jetbrains.kotlin.resolve.calls.CallResolver
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -202,18 +205,18 @@ class DoubleColonExpressionResolver(
} }
fun visitCallableReferenceExpression(expression: KtCallableReferenceExpression, c: ExpressionTypingContext): KotlinTypeInfo { fun visitCallableReferenceExpression(expression: KtCallableReferenceExpression, c: ExpressionTypingContext): KotlinTypeInfo {
val lhs = expression.receiverExpression?.let { resolveDoubleColonLHS(it, expression, c) }
val receiverType = lhs?.type // TODO: handle .Expression and .Type
val callableReference = expression.callableReference val callableReference = expression.callableReference
if (callableReference.getReferencedName().isEmpty()) { if (callableReference.getReferencedName().isEmpty()) {
expression.receiverExpression?.let { resolveDoubleColonLHS(it, expression, c) }
c.trace.report(UNRESOLVED_REFERENCE.on(callableReference, callableReference)) c.trace.report(UNRESOLVED_REFERENCE.on(callableReference, callableReference))
val errorType = ErrorUtils.createErrorType("Empty callable reference") val errorType = ErrorUtils.createErrorType("Empty callable reference")
return dataFlowAnalyzer.createCheckedTypeInfo(errorType, c, expression) return dataFlowAnalyzer.createCheckedTypeInfo(errorType, c, expression)
} }
val trace = TemporaryBindingTrace.create(c.trace, "Callable reference type") val trace = TemporaryBindingTrace.create(c.trace, "Callable reference type")
val result = getCallableReferenceType(expression, receiverType, lhs is DoubleColonLHS.Expression, c.replaceBindingTrace(trace)) val context = c.replaceBindingTrace(trace)
val (lhs, resolutionResults) = resolveCallableReference(expression, context, ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS)
val result = getCallableReferenceType(expression, lhs, resolutionResults, context)
val hasErrors = hasErrors(trace) // Do not inline this local variable (execution order is important) val hasErrors = hasErrors(trace) // Do not inline this local variable (execution order is important)
trace.commit() trace.commit()
if (!hasErrors && result != null) { if (!hasErrors && result != null) {
@@ -257,18 +260,22 @@ class DoubleColonExpressionResolver(
private fun getCallableReferenceType( private fun getCallableReferenceType(
expression: KtCallableReferenceExpression, expression: KtCallableReferenceExpression,
lhsType: KotlinType?, lhs: DoubleColonLHS?,
isBound: Boolean, resolutionResults: OverloadResolutionResults<*>?,
context: ExpressionTypingContext context: ExpressionTypingContext
): KotlinType? { ): KotlinType? {
val reference = expression.callableReference val reference = expression.callableReference
val resolved = BooleanArray(1) val descriptor =
val descriptor = resolveCallableReferenceTarget(expression, lhsType, context, resolved, callResolver) if (resolutionResults != null && !resolutionResults.isNothing) {
if (!resolved[0]) { OverloadResolutionResultsUtil.getResultingCall(resolutionResults, context.contextDependency)?.let { call ->
context.trace.report(UNRESOLVED_REFERENCE.on(reference, reference)) call.resultingDescriptor
} } ?: return null
if (descriptor == null) return null }
else {
context.trace.report(UNRESOLVED_REFERENCE.on(reference, reference))
return null
}
if (expression.isEmptyLHS && if (expression.isEmptyLHS &&
(descriptor.dispatchReceiverParameter != null || descriptor.extensionReceiverParameter != null)) { (descriptor.dispatchReceiverParameter != null || descriptor.extensionReceiverParameter != null)) {
@@ -283,7 +290,23 @@ class DoubleColonExpressionResolver(
context.trace.report(CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR.on(reference)) context.trace.report(CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR.on(reference))
} }
val ignoreReceiver = isBound || expression.isEmptyLHS val ignoreReceiver = lhs is DoubleColonLHS.Expression || expression.isEmptyLHS
return createReflectionTypeForResolvedCallableReference(expression, lhsType, ignoreReceiver, descriptor, context, reflectionTypes) return createReflectionTypeForResolvedCallableReference(
expression, lhs?.type, ignoreReceiver, descriptor, context, reflectionTypes
)
}
fun resolveCallableReference(
expression: KtCallableReferenceExpression,
context: ExpressionTypingContext,
resolveArgumentsMode: ResolveArgumentsMode
): Pair<DoubleColonLHS?, OverloadResolutionResults<*>?> {
val lhsResult = expression.receiverExpression?.let { resolveDoubleColonLHS(it, expression, context) }
val resolutionResults = resolvePossiblyAmbiguousCallableReference(
expression, lhsResult?.type, context, resolveArgumentsMode, callResolver
)
return lhsResult to resolutionResults
} }
} }
@@ -8,5 +8,5 @@ fun main() {
A::<!UNRESOLVED_REFERENCE!>bar<!> A::<!UNRESOLVED_REFERENCE!>bar<!>
<!UNRESOLVED_REFERENCE!>B<!>::<!OVERLOAD_RESOLUTION_AMBIGUITY!>bar<!> <!UNRESOLVED_REFERENCE!>B<!>::<!UNRESOLVED_REFERENCE!>bar<!>
} }