resolve function literal expression (as parameter) after resolve call
(therefore only once) while resolve use FAKE_FUNCTION_TYPE as type for function literal (which is a subtype/supertype for any function type)
This commit is contained in:
+140
-8
@@ -16,22 +16,43 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.lang.resolve.calls;
|
package org.jetbrains.jet.lang.resolve.calls;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.psi.JetTypeProjection;
|
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||||
import org.jetbrains.jet.lang.psi.JetTypeReference;
|
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
|
||||||
import org.jetbrains.jet.lang.psi.ValueArgument;
|
|
||||||
import org.jetbrains.jet.lang.resolve.TypeResolver;
|
import org.jetbrains.jet.lang.resolve.TypeResolver;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
|
||||||
|
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||||
|
import org.jetbrains.jet.lang.types.ErrorUtils;
|
||||||
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
import org.jetbrains.jet.lang.types.JetTypeInfo;
|
||||||
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
||||||
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.*;
|
||||||
|
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveMode.RESOLVE_FUNCTION_ARGUMENTS;
|
||||||
|
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveMode.SKIP_FUNCTION_ARGUMENTS;
|
||||||
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
||||||
|
|
||||||
public class ArgumentTypeResolver {
|
public class ArgumentTypeResolver {
|
||||||
|
@NotNull
|
||||||
|
private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private TypeResolver typeResolver;
|
private TypeResolver typeResolver;
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -47,16 +68,34 @@ public class ArgumentTypeResolver {
|
|||||||
this.expressionTypingServices = expressionTypingServices;
|
this.expressionTypingServices = expressionTypingServices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSubtypeOfForArgumentType(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
|
if (subtype == PLACEHOLDER_FUNCTION_TYPE) {
|
||||||
|
return isFunctionOrErrorType(supertype) || KotlinBuiltIns.getInstance().isAny(supertype); //todo function type extends
|
||||||
|
}
|
||||||
|
if (supertype == PLACEHOLDER_FUNCTION_TYPE) {
|
||||||
|
return isFunctionOrErrorType(subtype); //todo extends function type
|
||||||
|
}
|
||||||
|
return typeChecker.isSubtypeOf(subtype, supertype);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isFunctionOrErrorType(@NotNull JetType supertype) {
|
||||||
|
return KotlinBuiltIns.getInstance().isFunctionType(supertype) || ErrorUtils.isErrorType(supertype);
|
||||||
|
}
|
||||||
|
|
||||||
public void checkTypesWithNoCallee(@NotNull ResolutionContext context) {
|
public void checkTypesWithNoCallee(@NotNull ResolutionContext context) {
|
||||||
|
checkTypesWithNoCallee(context, SKIP_FUNCTION_ARGUMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkTypesWithNoCallee(@NotNull ResolutionContext context, @NotNull ResolveMode resolveFunctionArgumentBodies) {
|
||||||
for (ValueArgument valueArgument : context.call.getValueArguments()) {
|
for (ValueArgument valueArgument : context.call.getValueArguments()) {
|
||||||
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||||
if (argumentExpression != null) {
|
if (argumentExpression != null && !(argumentExpression instanceof JetFunctionLiteralExpression)) {
|
||||||
expressionTypingServices.getType(context.scope, argumentExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
|
expressionTypingServices.getType(context.scope, argumentExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (JetExpression expression : context.call.getFunctionLiteralArguments()) {
|
if (resolveFunctionArgumentBodies == RESOLVE_FUNCTION_ARGUMENTS) {
|
||||||
expressionTypingServices.getType(context.scope, expression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
|
checkTypesForFunctionArgumentsWithNoCallee(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (JetTypeProjection typeProjection : context.call.getTypeArguments()) {
|
for (JetTypeProjection typeProjection : context.call.getTypeArguments()) {
|
||||||
@@ -70,6 +109,19 @@ public class ArgumentTypeResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void checkTypesForFunctionArgumentsWithNoCallee(@NotNull ResolutionContext context) {
|
||||||
|
for (ValueArgument valueArgument : context.call.getValueArguments()) {
|
||||||
|
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||||
|
if (argumentExpression != null && (argumentExpression instanceof JetFunctionLiteralExpression)) {
|
||||||
|
expressionTypingServices.getType(context.scope, argumentExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (JetExpression expression : context.call.getFunctionLiteralArguments()) {
|
||||||
|
expressionTypingServices.getType(context.scope, expression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void checkUnmappedArgumentTypes(ResolutionContext context, Set<ValueArgument> unmappedArguments) {
|
public void checkUnmappedArgumentTypes(ResolutionContext context, Set<ValueArgument> unmappedArguments) {
|
||||||
for (ValueArgument valueArgument : unmappedArguments) {
|
for (ValueArgument valueArgument : unmappedArguments) {
|
||||||
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||||
@@ -78,4 +130,84 @@ public class ArgumentTypeResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <D extends CallableDescriptor> void checkTypesForFunctionArguments(ResolutionContext context, ResolvedCallImpl<D> resolvedCall) {
|
||||||
|
Map<ValueParameterDescriptor, ResolvedValueArgument> arguments = resolvedCall.getValueArguments();
|
||||||
|
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : arguments.entrySet()) {
|
||||||
|
ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
|
||||||
|
JetType varargElementType = valueParameterDescriptor.getVarargElementType();
|
||||||
|
JetType functionType;
|
||||||
|
if (varargElementType != null) {
|
||||||
|
functionType = varargElementType;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
functionType = valueParameterDescriptor.getType();
|
||||||
|
}
|
||||||
|
ResolvedValueArgument valueArgument = entry.getValue();
|
||||||
|
List<ValueArgument> valueArguments = valueArgument.getArguments();
|
||||||
|
for (ValueArgument argument : valueArguments) {
|
||||||
|
JetExpression expression = argument.getArgumentExpression();
|
||||||
|
if (expression instanceof JetFunctionLiteralExpression) {
|
||||||
|
expressionTypingServices.getType(context.scope, expression, functionType, context.dataFlowInfo, context.trace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JetTypeInfo getArgumentTypeInfo(
|
||||||
|
@Nullable JetExpression expression,
|
||||||
|
@NotNull BindingTrace trace,
|
||||||
|
@NotNull JetScope scope,
|
||||||
|
@NotNull DataFlowInfo dataFlowInfo,
|
||||||
|
@NotNull JetType expectedType,
|
||||||
|
@NotNull ResolveMode resolveFunctionArgumentBodies
|
||||||
|
) {
|
||||||
|
if (expression == null) {
|
||||||
|
return JetTypeInfo.create(null, dataFlowInfo);
|
||||||
|
}
|
||||||
|
if (expression instanceof JetFunctionLiteralExpression && resolveFunctionArgumentBodies == SKIP_FUNCTION_ARGUMENTS) {
|
||||||
|
JetType type = getFunctionLiteralType((JetFunctionLiteralExpression) expression, scope, trace);
|
||||||
|
return JetTypeInfo.create(type, dataFlowInfo);
|
||||||
|
}
|
||||||
|
return expressionTypingServices.getTypeInfo(scope, expression, expectedType, dataFlowInfo, trace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private JetType getFunctionLiteralType(
|
||||||
|
@NotNull JetFunctionLiteralExpression expression,
|
||||||
|
@NotNull JetScope scope,
|
||||||
|
@NotNull BindingTrace trace
|
||||||
|
) {
|
||||||
|
List<JetParameter> valueParameters = expression.getValueParameters();
|
||||||
|
if (valueParameters.isEmpty()) {
|
||||||
|
return PLACEHOLDER_FUNCTION_TYPE;
|
||||||
|
}
|
||||||
|
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(
|
||||||
|
trace, "trace to resolve function literal parameter types");
|
||||||
|
List<JetType> parameterTypes = Lists.newArrayList();
|
||||||
|
for (JetParameter parameter : valueParameters) {
|
||||||
|
parameterTypes.add(resolveTypeRefWithDefault(parameter.getTypeReference(), scope, temporaryTrace,
|
||||||
|
PLACEHOLDER_FUNCTION_PARAMETER_TYPE));
|
||||||
|
}
|
||||||
|
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
|
||||||
|
JetType returnType = resolveTypeRefWithDefault(functionLiteral.getReturnTypeRef(), scope, temporaryTrace,
|
||||||
|
PLACEHOLDER_FUNCTION_PARAMETER_TYPE);
|
||||||
|
assert returnType != null;
|
||||||
|
JetType receiverType = resolveTypeRefWithDefault(functionLiteral.getReceiverTypeRef(), scope, temporaryTrace, null);
|
||||||
|
return KotlinBuiltIns.getInstance().getFunctionType(Collections.<AnnotationDescriptor>emptyList(), receiverType, parameterTypes, returnType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private JetType resolveTypeRefWithDefault(
|
||||||
|
@Nullable JetTypeReference returnTypeRef,
|
||||||
|
@NotNull JetScope scope,
|
||||||
|
@NotNull BindingTrace trace,
|
||||||
|
@Nullable JetType defaultValue
|
||||||
|
) {
|
||||||
|
if (returnTypeRef != null) {
|
||||||
|
return expressionTypingServices.getTypeResolver().resolveType(scope, returnTypeRef, trace, true);
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ import java.util.*;
|
|||||||
import static org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER;
|
import static org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER;
|
||||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||||
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
||||||
|
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveMode;
|
||||||
|
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveMode.RESOLVE_FUNCTION_ARGUMENTS;
|
||||||
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER;
|
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER;
|
||||||
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
||||||
|
|
||||||
@@ -343,7 +345,7 @@ public class CallResolver {
|
|||||||
OverloadResolutionResultsImpl<D> results = ResolutionResultsHandler.INSTANCE.computeResultAndReportErrors(
|
OverloadResolutionResultsImpl<D> results = ResolutionResultsHandler.INSTANCE.computeResultAndReportErrors(
|
||||||
context.trace, tracing, candidates);
|
context.trace, tracing, candidates);
|
||||||
if (!results.isSingleResult()) {
|
if (!results.isSingleResult()) {
|
||||||
argumentTypeResolver.checkTypesWithNoCallee(context);
|
argumentTypeResolver.checkTypesWithNoCallee(context, RESOLVE_FUNCTION_ARGUMENTS);
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
@@ -405,6 +407,7 @@ public class CallResolver {
|
|||||||
debugInfo.set(ResolutionDebugInfo.RESULT, results.getResultingCall());
|
debugInfo.set(ResolutionDebugInfo.RESULT, results.getResultingCall());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolveFunctionArguments(context, results);
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
if (results.getResultCode() == OverloadResolutionResults.Code.INCOMPLETE_TYPE_INFERENCE) {
|
if (results.getResultCode() == OverloadResolutionResults.Code.INCOMPLETE_TYPE_INFERENCE) {
|
||||||
@@ -422,14 +425,31 @@ public class CallResolver {
|
|||||||
|
|
||||||
debugInfo.set(ResolutionDebugInfo.RESULT, resultsForFirstNonemptyCandidateSet.getResultingCall());
|
debugInfo.set(ResolutionDebugInfo.RESULT, resultsForFirstNonemptyCandidateSet.getResultingCall());
|
||||||
}
|
}
|
||||||
|
resolveFunctionArguments(context, resultsForFirstNonemptyCandidateSet);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
context.trace.report(UNRESOLVED_REFERENCE.on(reference));
|
context.trace.report(UNRESOLVED_REFERENCE.on(reference));
|
||||||
argumentTypeResolver.checkTypesWithNoCallee(context);
|
argumentTypeResolver.checkTypesWithNoCallee(context, RESOLVE_FUNCTION_ARGUMENTS);
|
||||||
}
|
}
|
||||||
return resultsForFirstNonemptyCandidateSet != null ? resultsForFirstNonemptyCandidateSet : OverloadResolutionResultsImpl.<F>nameNotFound();
|
return resultsForFirstNonemptyCandidateSet != null ? resultsForFirstNonemptyCandidateSet : OverloadResolutionResultsImpl.<F>nameNotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <D extends CallableDescriptor> OverloadResolutionResults<D> resolveFunctionArguments(
|
||||||
|
@NotNull final BasicResolutionContext context,
|
||||||
|
@NotNull OverloadResolutionResults<D> results
|
||||||
|
) {
|
||||||
|
if (results.isSingleResult()) {
|
||||||
|
ResolvedCall<D> resolvedCall = results.getResultingCall();
|
||||||
|
if (resolvedCall instanceof ResolvedCallImpl) {
|
||||||
|
argumentTypeResolver.checkTypesForFunctionArguments(context, (ResolvedCallImpl<D>) resolvedCall);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
argumentTypeResolver.checkTypesForFunctionArgumentsWithNoCallee(context);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -26,12 +26,23 @@ import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
|
|||||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl;
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
|
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
|
||||||
|
import org.jetbrains.jet.lang.types.ErrorUtils;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class CallResolverUtil {
|
public class CallResolverUtil {
|
||||||
|
|
||||||
|
public static final JetType PLACEHOLDER_FUNCTION_TYPE = ErrorUtils.createErrorType("Function type");
|
||||||
|
public static final JetType PLACEHOLDER_FUNCTION_PARAMETER_TYPE = ErrorUtils.createErrorType("Function parameter type");
|
||||||
|
|
||||||
|
public enum ResolveMode {
|
||||||
|
RESOLVE_FUNCTION_ARGUMENTS,
|
||||||
|
SKIP_FUNCTION_ARGUMENTS
|
||||||
|
}
|
||||||
|
|
||||||
|
private CallResolverUtil() {}
|
||||||
|
|
||||||
public static <D extends CallableDescriptor> ResolvedCallImpl<D> copy(@NotNull ResolvedCallImpl<D> call, @NotNull ResolutionContext context) {
|
public static <D extends CallableDescriptor> ResolvedCallImpl<D> copy(@NotNull ResolvedCallImpl<D> call, @NotNull ResolutionContext context) {
|
||||||
ResolutionCandidate<D> candidate = ResolutionCandidate.create(call.getCandidateDescriptor(), call.getThisObject(),
|
ResolutionCandidate<D> candidate = ResolutionCandidate.create(call.getCandidateDescriptor(), call.getThisObject(),
|
||||||
call.getReceiverArgument(), call.getExplicitReceiverKind(),
|
call.getReceiverArgument(), call.getExplicitReceiverKind(),
|
||||||
|
|||||||
@@ -39,8 +39,6 @@ import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategy;
|
|||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
|
||||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -48,13 +46,16 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
import static org.jetbrains.jet.lang.diagnostics.Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT;
|
||||||
|
import static org.jetbrains.jet.lang.diagnostics.Errors.SUPER_IS_NOT_AN_EXPRESSION;
|
||||||
|
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.PLACEHOLDER_FUNCTION_TYPE;
|
||||||
|
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveMode;
|
||||||
|
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveMode.RESOLVE_FUNCTION_ARGUMENTS;
|
||||||
|
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveMode.SKIP_FUNCTION_ARGUMENTS;
|
||||||
import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.*;
|
import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.*;
|
||||||
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
||||||
|
|
||||||
public class CandidateResolver {
|
public class CandidateResolver {
|
||||||
@NotNull
|
|
||||||
private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private ArgumentTypeResolver argumentTypeResolver;
|
private ArgumentTypeResolver argumentTypeResolver;
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -124,7 +125,7 @@ public class CandidateResolver {
|
|||||||
candidateCall.addStatus(status);
|
candidateCall.addStatus(status);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
candidateCall.addStatus(checkAllValueArguments(context).status);
|
candidateCall.addStatus(checkAllValueArguments(context, SKIP_FUNCTION_ARGUMENTS).status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -157,7 +158,7 @@ public class CandidateResolver {
|
|||||||
TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i);
|
TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i);
|
||||||
candidateCall.recordTypeArgument(typeParameterDescriptor, typeArguments.get(i));
|
candidateCall.recordTypeArgument(typeParameterDescriptor, typeArguments.get(i));
|
||||||
}
|
}
|
||||||
candidateCall.addStatus(checkAllValueArguments(context).status);
|
candidateCall.addStatus(checkAllValueArguments(context, SKIP_FUNCTION_ARGUMENTS).status);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
candidateCall.addStatus(OTHER_ERROR);
|
candidateCall.addStatus(OTHER_ERROR);
|
||||||
@@ -198,13 +199,14 @@ public class CandidateResolver {
|
|||||||
ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
|
ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
|
||||||
|
|
||||||
for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) {
|
for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) {
|
||||||
if (!JetPsiUtil.isFunctionLiteralWithoutDeclaredParameterTypes(valueArgument.getArgumentExpression())) continue;
|
if (!(valueArgument.getArgumentExpression() instanceof JetFunctionLiteralExpression)) continue;
|
||||||
|
|
||||||
ConstraintSystem systemWithCurrentSubstitution = constraintSystem.copy();
|
ConstraintSystem systemWithCurrentSubstitution = constraintSystem.copy();
|
||||||
addConstraintForValueArgument(valueArgument, valueParameterDescriptor, constraintSystem.getCurrentSubstitutor(),
|
addConstraintForValueArgument(valueArgument, valueParameterDescriptor, constraintSystem.getCurrentSubstitutor(),
|
||||||
systemWithCurrentSubstitution, context, null);
|
systemWithCurrentSubstitution, context, null, RESOLVE_FUNCTION_ARGUMENTS);
|
||||||
if (systemWithCurrentSubstitution.hasContradiction() || systemWithCurrentSubstitution.hasErrorInConstrainingTypes()) {
|
if (systemWithCurrentSubstitution.hasContradiction() || systemWithCurrentSubstitution.hasErrorInConstrainingTypes()) {
|
||||||
addConstraintForValueArgument(valueArgument, valueParameterDescriptor, substituteDontCare, constraintSystem, context, null);
|
addConstraintForValueArgument(valueArgument, valueParameterDescriptor, substituteDontCare, constraintSystem, context,
|
||||||
|
null, RESOLVE_FUNCTION_ARGUMENTS);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
constraintSystem = systemWithCurrentSubstitution;
|
constraintSystem = systemWithCurrentSubstitution;
|
||||||
@@ -219,7 +221,8 @@ public class CandidateResolver {
|
|||||||
|
|
||||||
if (!constraintSystem.isSuccessful()) {
|
if (!constraintSystem.isSuccessful()) {
|
||||||
resolvedCall.setResultingSubstitutor(constraintSystemWithoutExpectedTypeConstraint.getResultingSubstitutor());
|
resolvedCall.setResultingSubstitutor(constraintSystemWithoutExpectedTypeConstraint.getResultingSubstitutor());
|
||||||
List<JetType> argumentTypes = checkValueArgumentTypes(context, resolvedCall, resolvedCall.getTrace()).argumentTypes;
|
List<JetType> argumentTypes = checkValueArgumentTypes(context, resolvedCall, resolvedCall.getTrace(),
|
||||||
|
RESOLVE_FUNCTION_ARGUMENTS).argumentTypes;
|
||||||
JetType receiverType = resolvedCall.getReceiverArgument().exists() ? resolvedCall.getReceiverArgument().getType() : null;
|
JetType receiverType = resolvedCall.getReceiverArgument().exists() ? resolvedCall.getReceiverArgument().getType() : null;
|
||||||
context.tracing.typeInferenceFailed(resolvedCall.getTrace(),
|
context.tracing.typeInferenceFailed(resolvedCall.getTrace(),
|
||||||
InferenceErrorData
|
InferenceErrorData
|
||||||
@@ -232,7 +235,7 @@ public class CandidateResolver {
|
|||||||
|
|
||||||
resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
|
resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
|
||||||
// Here we type check the arguments with inferred types expected
|
// Here we type check the arguments with inferred types expected
|
||||||
checkAllValueArguments(context);
|
checkAllValueArguments(context, RESOLVE_FUNCTION_ARGUMENTS);
|
||||||
|
|
||||||
checkBounds(resolvedCall, constraintSystem, resolvedCall.getTrace(), context.tracing);
|
checkBounds(resolvedCall, constraintSystem, resolvedCall.getTrace(), context.tracing);
|
||||||
resolvedCall.setHasUnknownTypeParameters(false);
|
resolvedCall.setHasUnknownTypeParameters(false);
|
||||||
@@ -280,7 +283,7 @@ public class CandidateResolver {
|
|||||||
// We'll type check the arguments later, with the inferred types expected
|
// We'll type check the arguments later, with the inferred types expected
|
||||||
boolean[] isErrorType = new boolean[1];
|
boolean[] isErrorType = new boolean[1];
|
||||||
addConstraintForValueArgument(valueArgument, valueParameterDescriptor, substituteDontCare, constraintsSystem,
|
addConstraintForValueArgument(valueArgument, valueParameterDescriptor, substituteDontCare, constraintsSystem,
|
||||||
context, isErrorType);
|
context, isErrorType, SKIP_FUNCTION_ARGUMENTS);
|
||||||
if (isErrorType[0]) {
|
if (isErrorType[0]) {
|
||||||
candidateCall.argumentHasNoType();
|
candidateCall.argumentHasNoType();
|
||||||
}
|
}
|
||||||
@@ -314,7 +317,7 @@ public class CandidateResolver {
|
|||||||
candidateCall.setHasUnknownTypeParameters(true);
|
candidateCall.setHasUnknownTypeParameters(true);
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
ValueArgumentsCheckingResult checkingResult = checkAllValueArguments(context);
|
ValueArgumentsCheckingResult checkingResult = checkAllValueArguments(context, SKIP_FUNCTION_ARGUMENTS);
|
||||||
ResolutionStatus argumentsStatus = checkingResult.status;
|
ResolutionStatus argumentsStatus = checkingResult.status;
|
||||||
List<JetType> argumentTypes = checkingResult.argumentTypes;
|
List<JetType> argumentTypes = checkingResult.argumentTypes;
|
||||||
JetType receiverType = candidateCall.getReceiverArgument().exists() ? candidateCall.getReceiverArgument().getType() : null;
|
JetType receiverType = candidateCall.getReceiverArgument().exists() ? candidateCall.getReceiverArgument().getType() : null;
|
||||||
@@ -335,31 +338,28 @@ public class CandidateResolver {
|
|||||||
@NotNull TypeSubstitutor substitutor,
|
@NotNull TypeSubstitutor substitutor,
|
||||||
@NotNull ConstraintSystem constraintSystem,
|
@NotNull ConstraintSystem constraintSystem,
|
||||||
@NotNull ResolutionContext context,
|
@NotNull ResolutionContext context,
|
||||||
@Nullable boolean[] isErrorType) {
|
@Nullable boolean[] isErrorType,
|
||||||
|
@NotNull ResolveMode resolveFunctionArgumentBodies) {
|
||||||
|
|
||||||
JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument);
|
JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument);
|
||||||
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||||
JetType type;
|
TemporaryBindingTrace traceForUnknown = TemporaryBindingTrace.create(
|
||||||
if (argumentExpression != null) {
|
context.trace, "transient trace to resolve argument", argumentExpression);
|
||||||
TemporaryBindingTrace traceForUnknown = TemporaryBindingTrace.create(
|
JetType expectedType = substitutor.substitute(effectiveExpectedType, Variance.INVARIANT);
|
||||||
context.trace, "transient trace to resolve argument", argumentExpression);
|
JetType type = argumentTypeResolver.getArgumentTypeInfo(argumentExpression, traceForUnknown, context.scope, context.dataFlowInfo,
|
||||||
type = expressionTypingServices.getType(context.scope, argumentExpression,
|
expectedType != null ? expectedType : NO_EXPECTED_TYPE, resolveFunctionArgumentBodies).getType();
|
||||||
substitutor.substitute(effectiveExpectedType, Variance.INVARIANT), context.dataFlowInfo, traceForUnknown);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
type = null;
|
|
||||||
}
|
|
||||||
constraintSystem.addSubtypeConstraint(effectiveExpectedType, type, ConstraintPosition.getValueParameterPosition(
|
constraintSystem.addSubtypeConstraint(effectiveExpectedType, type, ConstraintPosition.getValueParameterPosition(
|
||||||
valueParameterDescriptor.getIndex()));
|
valueParameterDescriptor.getIndex()));
|
||||||
//todo no return
|
|
||||||
if (isErrorType != null) {
|
if (isErrorType != null) {
|
||||||
isErrorType[0] = type == null || ErrorUtils.isErrorType(type);
|
isErrorType[0] = type == null || ErrorUtils.isErrorType(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private <D extends CallableDescriptor, F extends D> ValueArgumentsCheckingResult checkAllValueArguments(CallResolutionContext<D, F> context) {
|
private <D extends CallableDescriptor, F extends D> ValueArgumentsCheckingResult checkAllValueArguments(
|
||||||
|
@NotNull CallResolutionContext<D, F> context,
|
||||||
|
@NotNull ResolveMode resolveFunctionArgumentBodies) {
|
||||||
ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes(context, context.candidateCall,
|
ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes(context, context.candidateCall,
|
||||||
context.candidateCall.getTrace());
|
context.candidateCall.getTrace(), resolveFunctionArgumentBodies);
|
||||||
ResolutionStatus resultStatus = checkingResult.status;
|
ResolutionStatus resultStatus = checkingResult.status;
|
||||||
ResolvedCall<D> candidateCall = context.candidateCall;
|
ResolvedCall<D> candidateCall = context.candidateCall;
|
||||||
|
|
||||||
@@ -381,7 +381,8 @@ public class CandidateResolver {
|
|||||||
private <D extends CallableDescriptor> ValueArgumentsCheckingResult checkValueArgumentTypes(
|
private <D extends CallableDescriptor> ValueArgumentsCheckingResult checkValueArgumentTypes(
|
||||||
@NotNull ResolutionContext context,
|
@NotNull ResolutionContext context,
|
||||||
@NotNull ResolvedCallImpl<D> candidateCall,
|
@NotNull ResolvedCallImpl<D> candidateCall,
|
||||||
@NotNull BindingTrace trace) {
|
@NotNull BindingTrace trace,
|
||||||
|
@NotNull ResolveMode resolveFunctionArgumentBodies) {
|
||||||
ResolutionStatus resultStatus = SUCCESS;
|
ResolutionStatus resultStatus = SUCCESS;
|
||||||
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
|
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
|
||||||
List<JetType> argumentTypes = Lists.newArrayList();
|
List<JetType> argumentTypes = Lists.newArrayList();
|
||||||
@@ -398,17 +399,18 @@ public class CandidateResolver {
|
|||||||
if (TypeUtils.dependsOnTypeParameters(expectedType, candidateCall.getCandidateDescriptor().getTypeParameters())) {
|
if (TypeUtils.dependsOnTypeParameters(expectedType, candidateCall.getCandidateDescriptor().getTypeParameters())) {
|
||||||
expectedType = NO_EXPECTED_TYPE;
|
expectedType = NO_EXPECTED_TYPE;
|
||||||
}
|
}
|
||||||
JetTypeInfo typeInfo = expressionTypingServices.getTypeInfo(context.scope, expression, expectedType, dataFlowInfo, trace);
|
JetTypeInfo typeInfo = argumentTypeResolver.getArgumentTypeInfo(expression, trace, context.scope, dataFlowInfo,
|
||||||
|
expectedType, resolveFunctionArgumentBodies);
|
||||||
JetType type = typeInfo.getType();
|
JetType type = typeInfo.getType();
|
||||||
dataFlowInfo = dataFlowInfo.and(typeInfo.getDataFlowInfo());
|
dataFlowInfo = dataFlowInfo.and(typeInfo.getDataFlowInfo());
|
||||||
|
|
||||||
if (type == null || ErrorUtils.isErrorType(type)) {
|
if (type == null || (ErrorUtils.isErrorType(type) && type != PLACEHOLDER_FUNCTION_TYPE)) {
|
||||||
candidateCall.argumentHasNoType();
|
candidateCall.argumentHasNoType();
|
||||||
argumentTypes.add(type);
|
argumentTypes.add(type);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
JetType resultingType;
|
JetType resultingType;
|
||||||
if (expectedType == NO_EXPECTED_TYPE || typeChecker.isSubtypeOf(type, expectedType)) {
|
if (expectedType == NO_EXPECTED_TYPE || argumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) {
|
||||||
resultingType = type;
|
resultingType = type;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -438,7 +440,7 @@ public class CandidateResolver {
|
|||||||
List<ReceiverValue> variants = AutoCastUtils.getAutoCastVariants(trace.getBindingContext(), dataFlowInfo, receiverToCast);
|
List<ReceiverValue> variants = AutoCastUtils.getAutoCastVariants(trace.getBindingContext(), dataFlowInfo, receiverToCast);
|
||||||
for (ReceiverValue receiverValue : variants) {
|
for (ReceiverValue receiverValue : variants) {
|
||||||
JetType possibleType = receiverValue.getType();
|
JetType possibleType = receiverValue.getType();
|
||||||
if (typeChecker.isSubtypeOf(possibleType, expectedType)) {
|
if (argumentTypeResolver.isSubtypeOfForArgumentType(possibleType, expectedType)) {
|
||||||
return possibleType;
|
return possibleType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -467,7 +469,7 @@ public class CandidateResolver {
|
|||||||
: receiverArgumentType;
|
: receiverArgumentType;
|
||||||
if (!TypeUtils.dependsOnTypeParameters(receiverParameter.getType(),
|
if (!TypeUtils.dependsOnTypeParameters(receiverParameter.getType(),
|
||||||
candidateCall.getCandidateDescriptor().getTypeParameters()) &&
|
candidateCall.getCandidateDescriptor().getTypeParameters()) &&
|
||||||
!typeChecker.isSubtypeOf(effectiveReceiverArgumentType, receiverParameter.getType())) {
|
!argumentTypeResolver.isSubtypeOfForArgumentType(effectiveReceiverArgumentType, receiverParameter.getType())) {
|
||||||
context.tracing.wrongReceiverType(context.candidateCall.getTrace(), receiverParameter, receiverArgument);
|
context.tracing.wrongReceiverType(context.candidateCall.getTrace(), receiverParameter, receiverArgument);
|
||||||
result = OTHER_ERROR;
|
result = OTHER_ERROR;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ fun test() {
|
|||||||
v1({}, {})
|
v1({}, {})
|
||||||
v1({}, <!ERROR_COMPILE_TIME_VALUE!>1<!>, {})
|
v1({}, <!ERROR_COMPILE_TIME_VALUE!>1<!>, {})
|
||||||
v1({}, {}, {it})
|
v1({}, {}, {it})
|
||||||
v1({}) <!VARARG_OUTSIDE_PARENTHESES!>{}<!>
|
v1({}) <!VARARG_OUTSIDE_PARENTHESES, DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED!>{}<!>
|
||||||
v1 <!VARARG_OUTSIDE_PARENTHESES, DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED!>{}<!>
|
v1 <!VARARG_OUTSIDE_PARENTHESES, DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED!>{}<!>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
object A {
|
||||||
|
val iii = 42
|
||||||
|
}
|
||||||
|
|
||||||
|
//inappropriate but participating in resolve functions
|
||||||
|
//fun foo(s: String, a: Any) = s + a
|
||||||
|
//fun foo(a: Any, s: String) = s + a
|
||||||
|
//fun foo(i: Int, j: Int) = i + j
|
||||||
|
//fun foo(a: Any, i: Int) = "$a$i"
|
||||||
|
//fun foo(f: (Int)->Int, i: Int) = f(i)
|
||||||
|
//fun foo(f: (String)->Int, s: String) = f(s)
|
||||||
|
//fun foo(f: (Any)->Int, a: Any) = f(a)
|
||||||
|
//fun foo(s: String, f: (String)->Int) = f(s)
|
||||||
|
//fun foo(a: Any, f: (Any)->Int) = f(a)
|
||||||
|
//appropriate function
|
||||||
|
fun foo(i: Int, f: (Int)->Int) = f(i)
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(1) { (x1: Int):Int ->
|
||||||
|
foo(2) { (x2: Int): Int ->
|
||||||
|
foo(3) { (x3: Int): Int ->
|
||||||
|
foo(4) { (x4: Int): Int ->
|
||||||
|
foo(5) { (x5: Int): Int ->
|
||||||
|
x1 + x2 + x3 + x4 + x5 + A.iii
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
object A {
|
||||||
|
val iii = 42
|
||||||
|
}
|
||||||
|
|
||||||
|
//inappropriate but participating in resolve functions
|
||||||
|
fun foo(s: String, a: Any) = s + a
|
||||||
|
fun foo(a: Any, s: String) = s + a
|
||||||
|
fun foo(i: Int, j: Int) = i + j
|
||||||
|
fun foo(a: Any, i: Int) = "$a$i"
|
||||||
|
fun foo(f: (Int)->Int, i: Int) = f(i)
|
||||||
|
fun foo(f: (String)->Int, s: String) = f(s)
|
||||||
|
fun foo(f: (Any)->Int, a: Any) = f(a)
|
||||||
|
fun foo(s: String, f: (String)->Int) = f(s)
|
||||||
|
fun foo(a: Any, f: (Any)->Int) = f(a)
|
||||||
|
//appropriate function
|
||||||
|
fun foo(i: Int, f: (Int)->Int) = f(i)
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(1) { (x1: Int):Int ->
|
||||||
|
foo(2) { (x2: Int): Int ->
|
||||||
|
foo(3) { (x3: Int): Int ->
|
||||||
|
foo(4) { (x4: Int): Int ->
|
||||||
|
foo(5) { (x5: Int): Int ->
|
||||||
|
x1 + x2 + x3 + x4 + x5 + A.iii
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3378,6 +3378,16 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
|||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/resolve"), "kt", true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/resolve"), "kt", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("resolveWithFunctionLiterals.kt")
|
||||||
|
public void testResolveWithFunctionLiterals() throws Exception {
|
||||||
|
doTest("compiler/testData/diagnostics/tests/resolve/resolveWithFunctionLiterals.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("resolveWithFunctionLiteralsOverload.kt")
|
||||||
|
public void testResolveWithFunctionLiteralsOverload() throws Exception {
|
||||||
|
doTest("compiler/testData/diagnostics/tests/resolve/resolveWithFunctionLiteralsOverload.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("resolveWithGenerics.kt")
|
@TestMetadata("resolveWithGenerics.kt")
|
||||||
public void testResolveWithGenerics() throws Exception {
|
public void testResolveWithGenerics() throws Exception {
|
||||||
doTest("compiler/testData/diagnostics/tests/resolve/resolveWithGenerics.kt");
|
doTest("compiler/testData/diagnostics/tests/resolve/resolveWithGenerics.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user