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.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) {
when (this) {
ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS ->
@@ -159,28 +150,6 @@ fun resolvePossiblyAmbiguousCallableReference(
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<*>) {
val functionDescriptor = AnonymousFunctionDescriptor(
context.scope.ownerDescriptor,
@@ -287,7 +256,7 @@ fun createReflectionTypeForResolvedCallableReference(
fun getResolvedCallableReferenceShapeType(
reference: KtCallableReferenceExpression,
lhsType: KotlinType?,
overloadResolutionResults: OverloadResolutionResults<CallableDescriptor>?,
overloadResolutionResults: OverloadResolutionResults<*>?,
context: ResolutionContext<*>,
expectedTypeUnknown: Boolean,
reflectionTypes: ReflectionTypes,
@@ -17,11 +17,11 @@
package org.jetbrains.kotlin.resolve.calls;
import com.google.common.collect.Lists;
import kotlin.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.builtins.ReflectionTypes;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.diagnostics.Errors;
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.TypeUtils;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo;
import org.jetbrains.kotlin.types.expressions.*;
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
import javax.inject.Inject;
import java.util.Collections;
import java.util.List;
@@ -63,31 +63,36 @@ import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
public class ArgumentTypeResolver {
@NotNull private final TypeResolver typeResolver;
@NotNull private final CallResolver callResolver;
@NotNull private final ExpressionTypingServices expressionTypingServices;
@NotNull private final DoubleColonExpressionResolver doubleColonExpressionResolver;
@NotNull private final KotlinBuiltIns builtIns;
@NotNull private final ReflectionTypes reflectionTypes;
@NotNull private final ConstantExpressionEvaluator constantExpressionEvaluator;
@NotNull private final FunctionPlaceholders functionPlaceholders;
private ExpressionTypingServices expressionTypingServices;
public ArgumentTypeResolver(
@NotNull TypeResolver typeResolver,
@NotNull CallResolver callResolver,
@NotNull ExpressionTypingServices expressionTypingServices,
@NotNull DoubleColonExpressionResolver doubleColonExpressionResolver,
@NotNull KotlinBuiltIns builtIns,
@NotNull ReflectionTypes reflectionTypes,
@NotNull ConstantExpressionEvaluator constantExpressionEvaluator,
@NotNull FunctionPlaceholders functionPlaceholders
) {
this.typeResolver = typeResolver;
this.callResolver = callResolver;
this.expressionTypingServices = expressionTypingServices;
this.doubleColonExpressionResolver = doubleColonExpressionResolver;
this.builtIns = builtIns;
this.reflectionTypes = reflectionTypes;
this.constantExpressionEvaluator = constantExpressionEvaluator;
this.functionPlaceholders = functionPlaceholders;
}
// component dependency cycle
@Inject
public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) {
this.expressionTypingServices = expressionTypingServices;
}
public static boolean isSubtypeOfForArgumentType(
@NotNull KotlinType actualType,
@NotNull KotlinType expectedType
@@ -238,14 +243,17 @@ public class ArgumentTypeResolver {
@NotNull CallResolutionContext<?> context,
boolean expectedTypeIsUnknown
) {
KotlinType receiverType =
CallableReferencesResolutionUtilsKt.resolveCallableReferenceReceiverType(callableReferenceExpression, context, typeResolver);
OverloadResolutionResults<CallableDescriptor> overloadResolutionResults =
CallableReferencesResolutionUtilsKt.resolvePossiblyAmbiguousCallableReference(
callableReferenceExpression, receiverType, context, ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS,
callResolver);
Pair<DoubleColonLHS, OverloadResolutionResults<?>> pair =
doubleColonExpressionResolver.resolveCallableReference(
callableReferenceExpression,
ExpressionTypingContext.newContext(context),
SHAPE_FUNCTION_ARGUMENTS
);
DoubleColonLHS lhs = pair.getFirst();
KotlinType receiverType = lhs != null ? lhs.getType() : null;
return CallableReferencesResolutionUtilsKt.getResolvedCallableReferenceShapeType(
callableReferenceExpression, receiverType, overloadResolutionResults, context, expectedTypeIsUnknown,
callableReferenceExpression, receiverType, pair.getSecond(), context, expectedTypeIsUnknown,
reflectionTypes, builtIns, functionPlaceholders
);
}
@@ -28,11 +28,14 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode
import org.jetbrains.kotlin.resolve.*
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.CallResolver
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
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.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
@@ -202,18 +205,18 @@ class DoubleColonExpressionResolver(
}
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
if (callableReference.getReferencedName().isEmpty()) {
expression.receiverExpression?.let { resolveDoubleColonLHS(it, expression, c) }
c.trace.report(UNRESOLVED_REFERENCE.on(callableReference, callableReference))
val errorType = ErrorUtils.createErrorType("Empty callable reference")
return dataFlowAnalyzer.createCheckedTypeInfo(errorType, c, expression)
}
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)
trace.commit()
if (!hasErrors && result != null) {
@@ -257,18 +260,22 @@ class DoubleColonExpressionResolver(
private fun getCallableReferenceType(
expression: KtCallableReferenceExpression,
lhsType: KotlinType?,
isBound: Boolean,
lhs: DoubleColonLHS?,
resolutionResults: OverloadResolutionResults<*>?,
context: ExpressionTypingContext
): KotlinType? {
val reference = expression.callableReference
val resolved = BooleanArray(1)
val descriptor = resolveCallableReferenceTarget(expression, lhsType, context, resolved, callResolver)
if (!resolved[0]) {
context.trace.report(UNRESOLVED_REFERENCE.on(reference, reference))
}
if (descriptor == null) return null
val descriptor =
if (resolutionResults != null && !resolutionResults.isNothing) {
OverloadResolutionResultsUtil.getResultingCall(resolutionResults, context.contextDependency)?.let { call ->
call.resultingDescriptor
} ?: return null
}
else {
context.trace.report(UNRESOLVED_REFERENCE.on(reference, reference))
return null
}
if (expression.isEmptyLHS &&
(descriptor.dispatchReceiverParameter != null || descriptor.extensionReceiverParameter != null)) {
@@ -283,7 +290,23 @@ class DoubleColonExpressionResolver(
context.trace.report(CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR.on(reference))
}
val ignoreReceiver = isBound || expression.isEmptyLHS
return createReflectionTypeForResolvedCallableReference(expression, lhsType, ignoreReceiver, descriptor, context, reflectionTypes)
val ignoreReceiver = lhs is DoubleColonLHS.Expression || expression.isEmptyLHS
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<!>
<!UNRESOLVED_REFERENCE!>B<!>::<!OVERLOAD_RESOLUTION_AMBIGUITY!>bar<!>
}
<!UNRESOLVED_REFERENCE!>B<!>::<!UNRESOLVED_REFERENCE!>bar<!>
}