Improve inference on generics for callable references
#KT-10711 Fixed #KT-12802 Fixed #KT-12964 Fixed #KT-15439 Fixed Analyze callable references in `dependent` mode, then complete them with respect to expected types
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
@@ -157,14 +158,13 @@ class CallCompleter(
|
||||
val expectedReturnType =
|
||||
if (call.isCallableReference()) {
|
||||
// TODO: compute generic type argument for R in the kotlin.Function<R> supertype (KT-12963)
|
||||
// TODO: also add constraints for parameter types (KT-12964)
|
||||
if (!TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) expectedType.getReturnTypeFromFunctionType()
|
||||
else TypeUtils.NO_EXPECTED_TYPE
|
||||
}
|
||||
else expectedType
|
||||
|
||||
fun ConstraintSystem.Builder.returnTypeInSystem(): KotlinType? =
|
||||
returnType?.let {
|
||||
fun ConstraintSystem.Builder.typeInSystem(type: KotlinType?): KotlinType? =
|
||||
type?.let {
|
||||
val substitutor = typeVariableSubstitutors[call.toHandle()] ?: error("No substitutor for call: $call")
|
||||
substitutor.substitute(it, Variance.INVARIANT)
|
||||
}
|
||||
@@ -178,7 +178,7 @@ class CallCompleter(
|
||||
|
||||
if (returnType != null && !TypeUtils.noExpectedType(expectedReturnType)) {
|
||||
updateSystemIfNeeded { builder ->
|
||||
val returnTypeInSystem = builder.returnTypeInSystem()
|
||||
val returnTypeInSystem = builder.typeInSystem(returnType)
|
||||
if (returnTypeInSystem != null) {
|
||||
builder.addSubtypeConstraint(returnTypeInSystem, expectedReturnType, EXPECTED_TYPE_POSITION.position())
|
||||
builder.build()
|
||||
@@ -202,7 +202,7 @@ class CallCompleter(
|
||||
|
||||
if (returnType != null && expectedReturnType === TypeUtils.UNIT_EXPECTED_TYPE) {
|
||||
updateSystemIfNeeded { builder ->
|
||||
val returnTypeInSystem = builder.returnTypeInSystem()
|
||||
val returnTypeInSystem = builder.typeInSystem(returnType)
|
||||
if (returnTypeInSystem != null) {
|
||||
builder.addSubtypeConstraint(returnTypeInSystem, builtIns.unitType, EXPECTED_TYPE_POSITION.position())
|
||||
val system = builder.build()
|
||||
@@ -212,6 +212,16 @@ class CallCompleter(
|
||||
}
|
||||
}
|
||||
|
||||
if (call.isCallableReference() && !TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) {
|
||||
updateSystemIfNeeded { builder ->
|
||||
candidateDescriptor.valueParameters.zip(expectedType.getValueParameterTypesFromFunctionType()).forEach { (parameter, argument) ->
|
||||
val valueParameterInSystem = builder.typeInSystem(parameter.type)
|
||||
builder.addSubtypeConstraint(valueParameterInSystem, argument.type, VALUE_PARAMETER_POSITION.position(parameter.index))
|
||||
}
|
||||
|
||||
builder.build()
|
||||
}
|
||||
}
|
||||
|
||||
val builder = constraintSystem!!.toBuilder()
|
||||
builder.fixVariables()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+29
-2
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.FunctionDescriptorUtil
|
||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.*
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS
|
||||
@@ -51,8 +52,11 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.ResolveConstruct
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||
|
||||
private val SPECIAL_FUNCTION_NAMES = ResolveConstruct.values().map { it.specialFunctionName }.toSet()
|
||||
|
||||
class GenericCandidateResolver(
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val coroutineInferenceSupport: CoroutineInferenceSupport
|
||||
@@ -186,6 +190,9 @@ class GenericCandidateResolver(
|
||||
if (addConstraintForNestedCall(argumentExpression, constraintPosition, builder, newContext, effectiveExpectedType)) return
|
||||
|
||||
val type = updateResultTypeForSmartCasts(typeInfoForCall.type, argumentExpression, context.replaceDataFlowInfo(dataFlowInfoForArgument))
|
||||
|
||||
if (argumentExpression is KtCallableReferenceExpression && type == null) return
|
||||
|
||||
builder.addSubtypeConstraint(
|
||||
type,
|
||||
builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT),
|
||||
@@ -273,8 +280,28 @@ class GenericCandidateResolver(
|
||||
addConstraintForFunctionLiteralArgument(functionLiteral, valueArgument, valueParameterDescriptor, constraintSystem, newContext,
|
||||
resolvedCall.candidateDescriptor.returnType)
|
||||
}
|
||||
|
||||
// as inference for callable references depends on expected type,
|
||||
// we should postpone reporting errors on them until all types will be inferred
|
||||
|
||||
// We do not replace trace for special calls (e.g. if-expressions) because of their specific analysis
|
||||
// For example, type info for arguments is needed before call will be completed (See ControlStructureTypingVisitor.visitIfExpression)
|
||||
val temporaryContextForCall = if (resolvedCall.candidateDescriptor.name in SPECIAL_FUNCTION_NAMES) {
|
||||
newContext
|
||||
}
|
||||
else {
|
||||
val temporaryBindingTrace = TemporaryBindingTrace.create(
|
||||
newContext.trace, "Trace to complete argument for call that might be not resulting call")
|
||||
newContext.replaceBindingTrace(temporaryBindingTrace)
|
||||
}
|
||||
|
||||
ArgumentTypeResolver.getCallableReferenceExpressionIfAny(argumentExpression, newContext)?.let { callableReference ->
|
||||
addConstraintForCallableReference(callableReference, valueArgument, valueParameterDescriptor, constraintSystem, newContext)
|
||||
addConstraintForCallableReference(
|
||||
callableReference,
|
||||
valueArgument,
|
||||
valueParameterDescriptor,
|
||||
constraintSystem,
|
||||
temporaryContextForCall)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -376,7 +403,7 @@ class GenericCandidateResolver(
|
||||
val expectedType = getExpectedTypeForCallableReference(callableReference, constraintSystem, context, effectiveExpectedType)
|
||||
?: return
|
||||
if (!ReflectionTypes.isCallableType(expectedType)) return
|
||||
val resolvedType = getResolvedTypeForCallableReference(callableReference, context, expectedType, valueArgument)
|
||||
val resolvedType = getResolvedTypeForCallableReference(callableReference, context, expectedType, valueArgument) ?: return
|
||||
val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
|
||||
constraintSystem.addSubtypeConstraint(
|
||||
resolvedType,
|
||||
|
||||
+12
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -77,6 +77,14 @@ public class ControlStructureTypingUtils {
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Name getSpecialFunctionName() {
|
||||
return Name.identifier("<SPECIAL-FUNCTION-FOR-" + name.toUpperCase() + "-RESOLVE>");
|
||||
}
|
||||
|
||||
public Name getSpecialTypeParameterName() {
|
||||
return Name.identifier("<TYPE-PARAMETER-FOR-" + name.toUpperCase() + "-RESOLVE>");
|
||||
}
|
||||
}
|
||||
|
||||
private final CallResolver callResolver;
|
||||
@@ -139,16 +147,14 @@ public class ControlStructureTypingUtils {
|
||||
) {
|
||||
assert argumentNames.size() == isArgumentNullable.size();
|
||||
|
||||
String constructionName = construct.getName().toUpperCase();
|
||||
Name specialFunctionName = Name.identifier("<SPECIAL-FUNCTION-FOR-" + constructionName + "-RESOLVE>");
|
||||
|
||||
SimpleFunctionDescriptorImpl function = SimpleFunctionDescriptorImpl.create(
|
||||
moduleDescriptor, Annotations.Companion.getEMPTY(), specialFunctionName, CallableMemberDescriptor.Kind.DECLARATION, SourceElement.NO_SOURCE
|
||||
moduleDescriptor, Annotations.Companion.getEMPTY(), construct.getSpecialFunctionName(),
|
||||
CallableMemberDescriptor.Kind.DECLARATION, SourceElement.NO_SOURCE
|
||||
);
|
||||
|
||||
TypeParameterDescriptor typeParameter = TypeParameterDescriptorImpl.createWithDefaultBound(
|
||||
function, Annotations.Companion.getEMPTY(), false, Variance.INVARIANT,
|
||||
Name.identifier("<TYPE-PARAMETER-FOR-" + constructionName + "-RESOLVE>"), 0);
|
||||
construct.getSpecialTypeParameterName(), 0);
|
||||
|
||||
KotlinType type = typeParameter.getDefaultType();
|
||||
KotlinType nullableType = TypeUtils.makeNullable(type);
|
||||
|
||||
+8
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -606,11 +606,16 @@ class DoubleColonExpressionResolver(
|
||||
outerContext: ResolutionContext<*>,
|
||||
resolutionMode: ResolveArgumentsMode
|
||||
): OverloadResolutionResults<CallableDescriptor>? {
|
||||
val call = CallMaker.makeCall(reference, receiver, null, reference, emptyList())
|
||||
// we should preserve information about `call` because callable references are analyzed two times,
|
||||
// otherwise there will be not completed calls in trace
|
||||
val call = outerContext.trace[BindingContext.CALL, reference] ?: CallMaker.makeCall(reference, receiver, null, reference, emptyList())
|
||||
val temporaryTrace = TemporaryTraceAndCache.create(outerContext, traceTitle, reference)
|
||||
val newContext =
|
||||
if (resolutionMode == ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS)
|
||||
outerContext.replaceTraceAndCache(temporaryTrace).replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE)
|
||||
outerContext
|
||||
.replaceTraceAndCache(temporaryTrace)
|
||||
.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE)
|
||||
.replaceContextDependency(ContextDependency.DEPENDENT)
|
||||
else
|
||||
outerContext.replaceTraceAndCache(temporaryTrace)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user