Added GenericCandidateResolver
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user