Added GenericCandidateResolver

This commit is contained in:
Svetlana Isakova
2015-06-26 22:07:34 +03:00
parent 0fdfb6b5db
commit 07937a27eb
5 changed files with 307 additions and 269 deletions
@@ -16,35 +16,34 @@
package org.jetbrains.kotlin.resolve.calls
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
import org.jetbrains.kotlin.resolve.calls.context.CheckValueArgumentsMode
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext.CONSTRAINT_SYSTEM_COMPLETER
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.callUtil.*
import org.jetbrains.kotlin.resolve.BindingContextUtils
import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
import org.jetbrains.kotlin.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS
import org.jetbrains.kotlin.resolve.calls.CallResolverUtil.getEffectiveExpectedType
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.CheckValueArgumentsMode
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.EXPECTED_TYPE_POSITION
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.FROM_COMPLETER
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.expressions.DataFlowUtils
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
import org.jetbrains.kotlin.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
import java.util.ArrayList
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.*
import org.jetbrains.kotlin.resolve.calls.model.*
public class CallCompleter(
val argumentTypeResolver: ArgumentTypeResolver,
@@ -211,7 +210,7 @@ public class CallCompleter(
for (valueArgument in context.call.getValueArguments()) {
val argumentMapping = getArgumentMapping(valueArgument!!)
val expectedType = when (argumentMapping) {
is ArgumentMatch -> CandidateResolver.getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument)
is ArgumentMatch -> getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument)
else -> TypeUtils.NO_EXPECTED_TYPE
}
val newContext = context.replaceDataFlowInfo(getDataFlowInfoForArgument(valueArgument)).replaceExpectedType(expectedType)
@@ -226,8 +225,7 @@ public class CallCompleter(
if (valueArgument.isExternal()) return
val expression = valueArgument.getArgumentExpression() ?: return
val deparenthesized = ArgumentTypeResolver.getLastElementDeparenthesized(expression, context)
if (deparenthesized == null) return
val deparenthesized = ArgumentTypeResolver.getLastElementDeparenthesized(expression, context) ?: return
val recordedType = expression.let { context.trace.getType(it) }
var updatedType: JetType? = recordedType
@@ -263,11 +261,9 @@ public class CallCompleter(
): OverloadResolutionResultsImpl<*>? {
if (!ExpressionTypingUtils.dependsOnExpectedType(expression)) return null
val argumentCall = expression.getCall(context.trace.getBindingContext())
if (argumentCall == null) return null
val argumentCall = expression.getCall(context.trace.getBindingContext()) ?: return null
val cachedDataForCall = context.resolutionResultsCache[argumentCall]
if (cachedDataForCall == null) return null
val cachedDataForCall = context.resolutionResultsCache[argumentCall] ?: return null
val (cachedResolutionResults, cachedContext, tracing) = cachedDataForCall
@suppress("UNCHECKED_CAST")
@@ -71,6 +71,7 @@ public class CallResolver {
private TypeResolver typeResolver;
private CandidateResolver candidateResolver;
private ArgumentTypeResolver argumentTypeResolver;
private GenericCandidateResolver genericCandidateResolver;
private CallCompleter callCompleter;
private TaskPrioritizer taskPrioritizer;
private AdditionalCheckerProvider additionalCheckerProvider;
@@ -98,6 +99,11 @@ public class CallResolver {
this.argumentTypeResolver = argumentTypeResolver;
}
@Inject
public void setGenericCandidateResolver(GenericCandidateResolver genericCandidateResolver) {
this.genericCandidateResolver = genericCandidateResolver;
}
@Inject
public void setCallCompleter(@NotNull CallCompleter callCompleter) {
this.callCompleter = callCompleter;
@@ -480,7 +486,7 @@ public class CallResolver {
CallCandidateResolutionContext<D> candidateContext = CallCandidateResolutionContext.createForCallBeingAnalyzed(
results.getResultingCall(), context, tracing);
candidateResolver.completeTypeInferenceDependentOnFunctionLiteralsForCall(candidateContext);
genericCandidateResolver.completeTypeInferenceDependentOnFunctionLiteralsForCall(candidateContext);
}
private static <F extends CallableDescriptor> void cacheResults(
@@ -21,14 +21,8 @@ import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor;
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
import org.jetbrains.kotlin.psi.Call;
import org.jetbrains.kotlin.psi.JetExpression;
import org.jetbrains.kotlin.psi.JetSimpleNameExpression;
import org.jetbrains.kotlin.psi.JetSuperExpression;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
@@ -165,4 +159,25 @@ public class CallResolverUtil {
}
return null;
}
@NotNull
public static JetType getEffectiveExpectedType(@NotNull ValueParameterDescriptor parameterDescriptor, @NotNull ValueArgument argument) {
if (argument.getSpreadElement() != null) {
if (parameterDescriptor.getVarargElementType() == null) {
// Spread argument passed to a non-vararg parameter, an error is already reported by ValueArgumentsToParametersMapper
return DONT_CARE;
}
else {
return parameterDescriptor.getType();
}
}
else {
JetType varargElementType = parameterDescriptor.getVarargElementType();
if (varargElementType != null) {
return varargElementType;
}
return parameterDescriptor.getType();
}
}
}
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.resolve.calls;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
@@ -28,12 +27,12 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
import org.jetbrains.kotlin.resolve.calls.context.*;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl;
import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext;
import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext;
import org.jetbrains.kotlin.resolve.calls.context.CheckValueArgumentsMode;
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
import org.jetbrains.kotlin.resolve.calls.model.*;
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils;
@@ -49,29 +48,35 @@ import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils;
import org.jetbrains.kotlin.types.expressions.JetTypeInfo;
import javax.inject.Inject;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static org.jetbrains.kotlin.diagnostics.Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT;
import static org.jetbrains.kotlin.diagnostics.Errors.SUPER_CANT_BE_EXTENSION_RECEIVER;
import static org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver.getLastElementDeparenthesized;
import static org.jetbrains.kotlin.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS;
import static org.jetbrains.kotlin.resolve.calls.CallResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS;
import static org.jetbrains.kotlin.resolve.calls.CallResolverUtil.getEffectiveExpectedType;
import static org.jetbrains.kotlin.resolve.calls.CallTransformer.CallForImplicitInvoke;
import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION;
import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION;
import static org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.*;
import static org.jetbrains.kotlin.types.TypeUtils.*;
import static org.jetbrains.kotlin.types.TypeUtils.noExpectedType;
public class CandidateResolver {
@NotNull
private ArgumentTypeResolver argumentTypeResolver;
@NotNull
private GenericCandidateResolver genericCandidateResolver;
@Inject
public void setArgumentTypeResolver(@NotNull ArgumentTypeResolver argumentTypeResolver) {
this.argumentTypeResolver = argumentTypeResolver;
}
@Inject
public void setGenericCandidateResolver(@NotNull GenericCandidateResolver genericCandidateResolver) {
this.genericCandidateResolver = genericCandidateResolver;
}
public <D extends CallableDescriptor, F extends D> void performResolutionForCandidateCall(
@NotNull CallCandidateResolutionContext<D> context,
@NotNull ResolutionTask<D, F> task) {
@@ -160,7 +165,7 @@ public class CandidateResolver {
if (jetTypeArguments.isEmpty() &&
!candidate.getTypeParameters().isEmpty() &&
candidateCall.getKnownTypeParametersSubstitutor() == null) {
candidateCall.addStatus(inferTypeArguments(context));
candidateCall.addStatus(genericCandidateResolver.inferTypeArguments(context));
}
else {
candidateCall.addStatus(checkAllValueArguments(context, SHAPE_FUNCTION_ARGUMENTS).status);
@@ -287,203 +292,6 @@ public class CandidateResolver {
return descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null;
}
public <D extends CallableDescriptor> void completeTypeInferenceDependentOnFunctionLiteralsForCall(
CallCandidateResolutionContext<D> context
) {
MutableResolvedCall<D> resolvedCall = context.candidateCall;
ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
if (constraintSystem == null) return;
// constraints for function literals
// Value parameters
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : resolvedCall.getValueArguments().entrySet()) {
ResolvedValueArgument resolvedValueArgument = entry.getValue();
ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) {
addConstraintForFunctionLiteral(valueArgument, valueParameterDescriptor, constraintSystem, context);
}
}
resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
}
private <D extends CallableDescriptor> void addConstraintForFunctionLiteral(
@NotNull ValueArgument valueArgument,
@NotNull ValueParameterDescriptor valueParameterDescriptor,
@NotNull ConstraintSystem constraintSystem,
@NotNull CallCandidateResolutionContext<D> context
) {
JetExpression argumentExpression = valueArgument.getArgumentExpression();
if (argumentExpression == null) return;
if (!ArgumentTypeResolver.isFunctionLiteralArgument(argumentExpression, context)) return;
JetFunction functionLiteral = ArgumentTypeResolver.getFunctionLiteralArgument(argumentExpression, context);
JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument);
JetType expectedType = constraintSystem.getCurrentSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT);
if (expectedType == null || TypeUtils.isDontCarePlaceholder(expectedType)) {
expectedType = argumentTypeResolver.getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, false);
}
if (expectedType == null || !KotlinBuiltIns.isFunctionOrExtensionFunctionType(expectedType)
|| CallResolverUtil.hasUnknownFunctionParameter(expectedType)) {
return;
}
MutableDataFlowInfoForArguments dataFlowInfoForArguments = context.candidateCall.getDataFlowInfoForArguments();
DataFlowInfo dataFlowInfoForArgument = dataFlowInfoForArguments.getInfo(valueArgument);
//todo analyze function literal body once in 'dependent' mode, then complete it with respect to expected type
boolean hasExpectedReturnType = !CallResolverUtil.hasUnknownReturnType(expectedType);
if (hasExpectedReturnType) {
TemporaryTraceAndCache temporaryToResolveFunctionLiteral = TemporaryTraceAndCache.create(
context, "trace to resolve function literal with expected return type", argumentExpression);
JetExpression statementExpression = JetPsiUtil.getExpressionOrLastStatementInBlock(functionLiteral.getBodyExpression());
if (statementExpression == null) return;
boolean[] mismatch = new boolean[1];
ObservableBindingTrace errorInterceptingTrace = ExpressionTypingUtils.makeTraceInterceptingTypeMismatch(
temporaryToResolveFunctionLiteral.trace, statementExpression, mismatch);
CallCandidateResolutionContext<D> newContext = context
.replaceBindingTrace(errorInterceptingTrace).replaceExpectedType(expectedType)
.replaceDataFlowInfo(dataFlowInfoForArgument).replaceResolutionResultsCache(temporaryToResolveFunctionLiteral.cache)
.replaceContextDependency(INDEPENDENT);
JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo(
argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS).getType();
if (!mismatch[0]) {
constraintSystem.addSubtypeConstraint(
type, effectiveExpectedType, VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.getIndex()));
temporaryToResolveFunctionLiteral.commit();
return;
}
}
JetType expectedTypeWithoutReturnType = hasExpectedReturnType ? CallResolverUtil.replaceReturnTypeByUnknown(expectedType) : expectedType;
CallCandidateResolutionContext<D> newContext = context
.replaceExpectedType(expectedTypeWithoutReturnType).replaceDataFlowInfo(dataFlowInfoForArgument)
.replaceContextDependency(INDEPENDENT);
JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext,
RESOLVE_FUNCTION_ARGUMENTS).getType();
constraintSystem.addSubtypeConstraint(
type, effectiveExpectedType, VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.getIndex()));
}
private <D extends CallableDescriptor> ResolutionStatus inferTypeArguments(CallCandidateResolutionContext<D> context) {
MutableResolvedCall<D> candidateCall = context.candidateCall;
final D candidate = candidateCall.getCandidateDescriptor();
ConstraintSystemImpl constraintSystem = new ConstraintSystemImpl();
// If the call is recursive, e.g.
// fun foo<T>(t : T) : T = foo(t)
// we can't use same descriptor objects for T's as actual type values and same T's as unknowns,
// because constraints become trivial (T :< T), and inference fails
//
// Thus, we replace the parameters of our descriptor with fresh objects (perform alpha-conversion)
CallableDescriptor candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidate);
Map<TypeParameterDescriptor, Variance> typeVariables = Maps.newLinkedHashMap();
for (TypeParameterDescriptor typeParameterDescriptor : candidateWithFreshVariables.getTypeParameters()) {
typeVariables.put(typeParameterDescriptor, Variance.INVARIANT); // TODO: variance of the occurrences
}
constraintSystem.registerTypeVariables(typeVariables);
TypeSubstitutor substituteDontCare =
makeConstantSubstitutor(candidateWithFreshVariables.getTypeParameters(), DONT_CARE);
// Value parameters
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
ResolvedValueArgument resolvedValueArgument = entry.getValue();
ValueParameterDescriptor valueParameterDescriptor = candidateWithFreshVariables.getValueParameters().get(entry.getKey().getIndex());
for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) {
// TODO : more attempts, with different expected types
// Here we type check expecting an error type (DONT_CARE, substitution with substituteDontCare)
// and throw the results away
// We'll type check the arguments later, with the inferred types expected
addConstraintForValueArgument(valueArgument, valueParameterDescriptor, substituteDontCare, constraintSystem,
context, SHAPE_FUNCTION_ARGUMENTS);
}
}
// Receiver
// Error is already reported if something is missing
ReceiverValue receiverArgument = candidateCall.getExtensionReceiver();
ReceiverParameterDescriptor receiverParameter = candidateWithFreshVariables.getExtensionReceiverParameter();
if (receiverArgument.exists() && receiverParameter != null) {
JetType receiverType =
context.candidateCall.isSafeCall()
? TypeUtils.makeNotNullable(receiverArgument.getType())
: receiverArgument.getType();
if (receiverArgument instanceof ExpressionReceiver) {
receiverType = updateResultTypeForSmartCasts(
receiverType, ((ExpressionReceiver) receiverArgument).getExpression(), context);
}
constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), RECEIVER_POSITION.position());
}
// Restore type variables before alpha-conversion
ConstraintSystem constraintSystemWithRightTypeParameters = constraintSystem.substituteTypeVariables(
new Function1<TypeParameterDescriptor, TypeParameterDescriptor>() {
@Override
public TypeParameterDescriptor invoke(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
return candidate.getTypeParameters().get(typeParameterDescriptor.getIndex());
}
}
);
candidateCall.setConstraintSystem(constraintSystemWithRightTypeParameters);
// Solution
boolean hasContradiction = constraintSystem.getStatus().hasContradiction();
if (!hasContradiction) {
return INCOMPLETE_TYPE_INFERENCE;
}
return OTHER_ERROR;
}
private void addConstraintForValueArgument(
@NotNull ValueArgument valueArgument,
@NotNull ValueParameterDescriptor valueParameterDescriptor,
@NotNull TypeSubstitutor substitutor,
@NotNull ConstraintSystem constraintSystem,
@NotNull CallCandidateResolutionContext<?> context,
@NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies) {
JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument);
JetExpression argumentExpression = valueArgument.getArgumentExpression();
JetType expectedType = substitutor.substitute(effectiveExpectedType, Variance.INVARIANT);
DataFlowInfo dataFlowInfoForArgument = context.candidateCall.getDataFlowInfoForArguments().getInfo(valueArgument);
CallResolutionContext<?> newContext = context.replaceExpectedType(expectedType).replaceDataFlowInfo(dataFlowInfoForArgument);
JetTypeInfo typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(
argumentExpression, newContext, resolveFunctionArgumentBodies);
context.candidateCall.getDataFlowInfoForArguments().updateInfo(valueArgument, typeInfoForCall.getDataFlowInfo());
JetType type = updateResultTypeForSmartCasts(
typeInfoForCall.getType(), argumentExpression, context.replaceDataFlowInfo(dataFlowInfoForArgument));
constraintSystem.addSubtypeConstraint(
type, effectiveExpectedType, VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.getIndex()));
}
@Nullable
private static JetType updateResultTypeForSmartCasts(
@Nullable JetType type,
@Nullable JetExpression argumentExpression,
@NotNull ResolutionContext context
) {
JetExpression deparenthesizedArgument = getLastElementDeparenthesized(argumentExpression, context);
if (deparenthesizedArgument == null || type == null) return type;
DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(deparenthesizedArgument, type, context);
if (!dataFlowValue.isPredictable()) return type;
Set<JetType> possibleTypes = context.dataFlowInfo.getPossibleTypes(dataFlowValue);
if (possibleTypes.isEmpty()) return type;
return TypeUtils.intersect(JetTypeChecker.DEFAULT, possibleTypes);
}
@NotNull
private <D extends CallableDescriptor> ValueArgumentsCheckingResult checkAllValueArguments(
@NotNull CallCandidateResolutionContext<D> context,
@@ -696,27 +504,6 @@ public class CandidateResolver {
}
}
@NotNull
public static JetType getEffectiveExpectedType(ValueParameterDescriptor parameterDescriptor, ValueArgument argument) {
if (argument.getSpreadElement() != null) {
if (parameterDescriptor.getVarargElementType() == null) {
// Spread argument passed to a non-vararg parameter, an error is already reported by ValueArgumentsToParametersMapper
return DONT_CARE;
}
else {
return parameterDescriptor.getType();
}
}
else {
JetType varargElementType = parameterDescriptor.getVarargElementType();
if (varargElementType != null) {
return varargElementType;
}
return parameterDescriptor.getType();
}
}
private static void checkGenericBoundsInAFunctionCall(
@NotNull List<JetTypeProjection> jetTypeArguments,
@NotNull List<JetType> typeArguments,
@@ -0,0 +1,234 @@
/*
* Copyright 2010-2015 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve.calls
import com.google.common.collect.Maps
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.psi.JetPsiUtil
import org.jetbrains.kotlin.psi.ValueArgument
import org.jetbrains.kotlin.resolve.FunctionDescriptorUtil
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver.getLastElementDeparenthesized
import org.jetbrains.kotlin.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS
import org.jetbrains.kotlin.resolve.calls.CallResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS
import org.jetbrains.kotlin.resolve.calls.CallResolverUtil.getEffectiveExpectedType
import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.INCOMPLETE_TYPE_INFERENCE
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.OTHER_ERROR
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE
import org.jetbrains.kotlin.types.TypeUtils.makeConstantSubstitutor
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.checker.JetTypeChecker
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
class GenericCandidateResolver(
val argumentTypeResolver: ArgumentTypeResolver
) {
fun <D : CallableDescriptor> inferTypeArguments(context: CallCandidateResolutionContext<D>): ResolutionStatus {
val candidateCall = context.candidateCall
val candidate = candidateCall.getCandidateDescriptor()
val constraintSystem = ConstraintSystemImpl()
// If the call is recursive, e.g.
// fun foo<T>(t : T) : T = foo(t)
// we can't use same descriptor objects for T's as actual type values and same T's as unknowns,
// because constraints become trivial (T :< T), and inference fails
//
// Thus, we replace the parameters of our descriptor with fresh objects (perform alpha-conversion)
val candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidate)
val typeVariables = Maps.newLinkedHashMap<TypeParameterDescriptor, Variance>()
for (typeParameterDescriptor in candidateWithFreshVariables.getTypeParameters()) {
typeVariables.put(typeParameterDescriptor, Variance.INVARIANT) // TODO: variance of the occurrences
}
constraintSystem.registerTypeVariables(typeVariables)
val substituteDontCare = makeConstantSubstitutor(candidateWithFreshVariables.getTypeParameters(), DONT_CARE)
// Value parameters
for (entry in candidateCall.getValueArguments().entrySet()) {
val resolvedValueArgument = entry.getValue()
val valueParameterDescriptor = candidateWithFreshVariables.getValueParameters().get(entry.getKey().getIndex())
for (valueArgument in resolvedValueArgument.getArguments()) {
// TODO : more attempts, with different expected types
// Here we type check expecting an error type (DONT_CARE, substitution with substituteDontCare)
// and throw the results away
// We'll type check the arguments later, with the inferred types expected
addConstraintForValueArgument(valueArgument, valueParameterDescriptor, substituteDontCare,
constraintSystem, context, SHAPE_FUNCTION_ARGUMENTS)
}
}
// Receiver
// Error is already reported if something is missing
val receiverArgument = candidateCall.getExtensionReceiver()
val receiverParameter = candidateWithFreshVariables.getExtensionReceiverParameter()
if (receiverArgument.exists() && receiverParameter != null) {
var receiverType: JetType? = if (context.candidateCall.isSafeCall())
TypeUtils.makeNotNullable(receiverArgument.getType())
else
receiverArgument.getType()
if (receiverArgument is ExpressionReceiver) {
receiverType = updateResultTypeForSmartCasts(receiverType, receiverArgument.getExpression(), context)
}
constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), RECEIVER_POSITION.position())
}
// Restore type variables before alpha-conversion
val constraintSystemWithRightTypeParameters = constraintSystem.substituteTypeVariables {
candidate.getTypeParameters().get(it.getIndex())
}
candidateCall.setConstraintSystem(constraintSystemWithRightTypeParameters)
// Solution
val hasContradiction = constraintSystem.getStatus().hasContradiction()
if (!hasContradiction) {
return INCOMPLETE_TYPE_INFERENCE
}
return OTHER_ERROR
}
fun addConstraintForValueArgument(
valueArgument: ValueArgument,
valueParameterDescriptor: ValueParameterDescriptor,
substitutor: TypeSubstitutor,
constraintSystem: ConstraintSystem,
context: CallCandidateResolutionContext<*>,
resolveFunctionArgumentBodies: CallResolverUtil.ResolveArgumentsMode
) {
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument)
val argumentExpression = valueArgument.getArgumentExpression()
val expectedType = substitutor.substitute(effectiveExpectedType, Variance.INVARIANT)
val dataFlowInfoForArgument = context.candidateCall.getDataFlowInfoForArguments().getInfo(valueArgument)
val newContext = context.replaceExpectedType(expectedType).replaceDataFlowInfo(dataFlowInfoForArgument)
val typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(argumentExpression, newContext, resolveFunctionArgumentBodies)
context.candidateCall.getDataFlowInfoForArguments().updateInfo(valueArgument, typeInfoForCall.dataFlowInfo)
val type = updateResultTypeForSmartCasts(typeInfoForCall.type, argumentExpression, context.replaceDataFlowInfo(dataFlowInfoForArgument))
constraintSystem.addSubtypeConstraint(type, effectiveExpectedType, VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.getIndex()))
}
private fun updateResultTypeForSmartCasts(type: JetType?, argumentExpression: JetExpression?, context: ResolutionContext<*>): JetType? {
val deparenthesizedArgument = getLastElementDeparenthesized(argumentExpression, context)
if (deparenthesizedArgument == null || type == null) return type
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(deparenthesizedArgument, type, context)
if (!dataFlowValue.isPredictable()) return type
val possibleTypes = context.dataFlowInfo.getPossibleTypes(dataFlowValue)
if (possibleTypes.isEmpty()) return type
return TypeUtils.intersect(JetTypeChecker.DEFAULT, possibleTypes)
}
public fun <D : CallableDescriptor> completeTypeInferenceDependentOnFunctionLiteralsForCall(
context: CallCandidateResolutionContext<D>
) {
val resolvedCall = context.candidateCall
val constraintSystem = resolvedCall.getConstraintSystem() ?: return
// constraints for function literals
// Value parameters
for (entry in resolvedCall.getValueArguments().entrySet()) {
val resolvedValueArgument = entry.getValue()
val valueParameterDescriptor = entry.getKey()
for (valueArgument in resolvedValueArgument.getArguments()) {
addConstraintForFunctionLiteral<D>(valueArgument, valueParameterDescriptor, constraintSystem, context)
}
}
resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor())
}
private fun <D : CallableDescriptor> addConstraintForFunctionLiteral(
valueArgument: ValueArgument,
valueParameterDescriptor: ValueParameterDescriptor,
constraintSystem: ConstraintSystem,
context: CallCandidateResolutionContext<D>
) {
val argumentExpression = valueArgument.getArgumentExpression() ?: return
if (!ArgumentTypeResolver.isFunctionLiteralArgument(argumentExpression, context)) return
val functionLiteral = ArgumentTypeResolver.getFunctionLiteralArgument(argumentExpression, context)
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument)
var expectedType = constraintSystem.getCurrentSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT)
if (expectedType == null || TypeUtils.isDontCarePlaceholder(expectedType)) {
expectedType = argumentTypeResolver.getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, false)
}
if (expectedType == null || !KotlinBuiltIns.isFunctionOrExtensionFunctionType(expectedType)
|| CallResolverUtil.hasUnknownFunctionParameter(expectedType)) {
return
}
val dataFlowInfoForArguments = context.candidateCall.getDataFlowInfoForArguments()
val dataFlowInfoForArgument = dataFlowInfoForArguments.getInfo(valueArgument)
//todo analyze function literal body once in 'dependent' mode, then complete it with respect to expected type
val hasExpectedReturnType = !CallResolverUtil.hasUnknownReturnType(expectedType)
val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.getIndex())
if (hasExpectedReturnType) {
val temporaryToResolveFunctionLiteral = TemporaryTraceAndCache.create(
context, "trace to resolve function literal with expected return type", argumentExpression)
val statementExpression = JetPsiUtil.getExpressionOrLastStatementInBlock(functionLiteral.getBodyExpression()) ?: return
val mismatch = BooleanArray(1)
val errorInterceptingTrace = ExpressionTypingUtils.makeTraceInterceptingTypeMismatch(
temporaryToResolveFunctionLiteral.trace, statementExpression, mismatch)
val newContext = context.replaceBindingTrace(errorInterceptingTrace).replaceExpectedType(expectedType)
.replaceDataFlowInfo(dataFlowInfoForArgument).replaceResolutionResultsCache(temporaryToResolveFunctionLiteral.cache)
.replaceContextDependency(INDEPENDENT)
val type = argumentTypeResolver.getFunctionLiteralTypeInfo(
argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS).type
if (!mismatch[0]) {
constraintSystem.addSubtypeConstraint(type, effectiveExpectedType, position)
temporaryToResolveFunctionLiteral.commit()
return
}
}
val expectedTypeWithoutReturnType = if (hasExpectedReturnType) CallResolverUtil.replaceReturnTypeByUnknown(expectedType) else expectedType
val newContext = context.replaceExpectedType(expectedTypeWithoutReturnType).replaceDataFlowInfo(dataFlowInfoForArgument)
.replaceContextDependency(INDEPENDENT)
val type = argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS).type
constraintSystem.addSubtypeConstraint(type, effectiveExpectedType, position)
}
}