From 39450dd95424d2c330339b51259fdbedd720decd Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Tue, 20 Nov 2012 17:35:48 +0400 Subject: [PATCH] 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) --- .../resolve/calls/ArgumentTypeResolver.java | 148 +++++++++++++++++- .../jet/lang/resolve/calls/CallResolver.java | 24 ++- .../lang/resolve/calls/CallResolverUtil.java | 11 ++ .../lang/resolve/calls/CandidateResolver.java | 70 +++++---- .../testData/diagnostics/tests/Varargs.kt | 2 +- .../resolve/resolveWithFunctionLiterals.kt | 30 ++++ .../resolveWithFunctionLiteralsOverload.kt | 30 ++++ .../checkers/JetDiagnosticsTestGenerated.java | 10 ++ 8 files changed, 280 insertions(+), 45 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/resolve/resolveWithFunctionLiterals.kt create mode 100644 compiler/testData/diagnostics/tests/resolve/resolveWithFunctionLiteralsOverload.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java index 3a20d3002fa..2bf3abb07ce 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java @@ -16,22 +16,43 @@ package org.jetbrains.jet.lang.resolve.calls; +import com.google.common.collect.Lists; 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.psi.JetExpression; -import org.jetbrains.jet.lang.psi.JetTypeProjection; -import org.jetbrains.jet.lang.psi.JetTypeReference; -import org.jetbrains.jet.lang.psi.ValueArgument; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; 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.lang.KotlinBuiltIns; import javax.inject.Inject; - +import java.util.Collections; +import java.util.List; +import java.util.Map; 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; public class ArgumentTypeResolver { + @NotNull + private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE; + @NotNull private TypeResolver typeResolver; @NotNull @@ -47,16 +68,34 @@ public class ArgumentTypeResolver { 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) { + checkTypesWithNoCallee(context, SKIP_FUNCTION_ARGUMENTS); + } + + public void checkTypesWithNoCallee(@NotNull ResolutionContext context, @NotNull ResolveMode resolveFunctionArgumentBodies) { for (ValueArgument valueArgument : context.call.getValueArguments()) { 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); } } - for (JetExpression expression : context.call.getFunctionLiteralArguments()) { - expressionTypingServices.getType(context.scope, expression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace); + if (resolveFunctionArgumentBodies == RESOLVE_FUNCTION_ARGUMENTS) { + checkTypesForFunctionArgumentsWithNoCallee(context); } 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 unmappedArguments) { for (ValueArgument valueArgument : unmappedArguments) { JetExpression argumentExpression = valueArgument.getArgumentExpression(); @@ -78,4 +130,84 @@ public class ArgumentTypeResolver { } } } + + public void checkTypesForFunctionArguments(ResolutionContext context, ResolvedCallImpl resolvedCall) { + Map arguments = resolvedCall.getValueArguments(); + for (Map.Entry 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 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 valueParameters = expression.getValueParameters(); + if (valueParameters.isEmpty()) { + return PLACEHOLDER_FUNCTION_TYPE; + } + TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create( + trace, "trace to resolve function literal parameter types"); + List 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.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; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 49eb5b9043c..fd2aff4e7a1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -50,6 +50,8 @@ import java.util.*; 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.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.types.TypeUtils.NO_EXPECTED_TYPE; @@ -343,7 +345,7 @@ public class CallResolver { OverloadResolutionResultsImpl results = ResolutionResultsHandler.INSTANCE.computeResultAndReportErrors( context.trace, tracing, candidates); if (!results.isSingleResult()) { - argumentTypeResolver.checkTypesWithNoCallee(context); + argumentTypeResolver.checkTypesWithNoCallee(context, RESOLVE_FUNCTION_ARGUMENTS); } return results; } @@ -405,6 +407,7 @@ public class CallResolver { debugInfo.set(ResolutionDebugInfo.RESULT, results.getResultingCall()); } + resolveFunctionArguments(context, results); return results; } if (results.getResultCode() == OverloadResolutionResults.Code.INCOMPLETE_TYPE_INFERENCE) { @@ -422,14 +425,31 @@ public class CallResolver { debugInfo.set(ResolutionDebugInfo.RESULT, resultsForFirstNonemptyCandidateSet.getResultingCall()); } + resolveFunctionArguments(context, resultsForFirstNonemptyCandidateSet); } else { context.trace.report(UNRESOLVED_REFERENCE.on(reference)); - argumentTypeResolver.checkTypesWithNoCallee(context); + argumentTypeResolver.checkTypesWithNoCallee(context, RESOLVE_FUNCTION_ARGUMENTS); } return resultsForFirstNonemptyCandidateSet != null ? resultsForFirstNonemptyCandidateSet : OverloadResolutionResultsImpl.nameNotFound(); } + private OverloadResolutionResults resolveFunctionArguments( + @NotNull final BasicResolutionContext context, + @NotNull OverloadResolutionResults results + ) { + if (results.isSingleResult()) { + ResolvedCall resolvedCall = results.getResultingCall(); + if (resolvedCall instanceof ResolvedCallImpl) { + argumentTypeResolver.checkTypesForFunctionArguments(context, (ResolvedCallImpl) resolvedCall); + } + } + else { + argumentTypeResolver.checkTypesForFunctionArgumentsWithNoCallee(context); + } + return results; + } + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java index ad19ac7a113..18efbc29373 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java @@ -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.ResolvedValueArgument; import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate; +import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lang.types.JetType; import java.util.Map; 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 ResolvedCallImpl copy(@NotNull ResolvedCallImpl call, @NotNull ResolutionContext context) { ResolutionCandidate candidate = ResolutionCandidate.create(call.getCandidateDescriptor(), call.getThisObject(), call.getReceiverArgument(), call.getExplicitReceiverKind(), diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java index c4d9923ff52..ba66604bb15 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java @@ -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.ReceiverValue; 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 java.util.ArrayList; @@ -48,13 +46,16 @@ import java.util.List; import java.util.Map; 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.types.TypeUtils.NO_EXPECTED_TYPE; public class CandidateResolver { - @NotNull - private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE; @NotNull private ArgumentTypeResolver argumentTypeResolver; @NotNull @@ -124,7 +125,7 @@ public class CandidateResolver { candidateCall.addStatus(status); } else { - candidateCall.addStatus(checkAllValueArguments(context).status); + candidateCall.addStatus(checkAllValueArguments(context, SKIP_FUNCTION_ARGUMENTS).status); } } else { @@ -157,7 +158,7 @@ public class CandidateResolver { TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i); candidateCall.recordTypeArgument(typeParameterDescriptor, typeArguments.get(i)); } - candidateCall.addStatus(checkAllValueArguments(context).status); + candidateCall.addStatus(checkAllValueArguments(context, SKIP_FUNCTION_ARGUMENTS).status); } else { candidateCall.addStatus(OTHER_ERROR); @@ -198,13 +199,14 @@ public class CandidateResolver { ValueParameterDescriptor valueParameterDescriptor = entry.getKey(); for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) { - if (!JetPsiUtil.isFunctionLiteralWithoutDeclaredParameterTypes(valueArgument.getArgumentExpression())) continue; + if (!(valueArgument.getArgumentExpression() instanceof JetFunctionLiteralExpression)) continue; ConstraintSystem systemWithCurrentSubstitution = constraintSystem.copy(); addConstraintForValueArgument(valueArgument, valueParameterDescriptor, constraintSystem.getCurrentSubstitutor(), - systemWithCurrentSubstitution, context, null); + systemWithCurrentSubstitution, context, null, RESOLVE_FUNCTION_ARGUMENTS); if (systemWithCurrentSubstitution.hasContradiction() || systemWithCurrentSubstitution.hasErrorInConstrainingTypes()) { - addConstraintForValueArgument(valueArgument, valueParameterDescriptor, substituteDontCare, constraintSystem, context, null); + addConstraintForValueArgument(valueArgument, valueParameterDescriptor, substituteDontCare, constraintSystem, context, + null, RESOLVE_FUNCTION_ARGUMENTS); } else { constraintSystem = systemWithCurrentSubstitution; @@ -219,7 +221,8 @@ public class CandidateResolver { if (!constraintSystem.isSuccessful()) { resolvedCall.setResultingSubstitutor(constraintSystemWithoutExpectedTypeConstraint.getResultingSubstitutor()); - List argumentTypes = checkValueArgumentTypes(context, resolvedCall, resolvedCall.getTrace()).argumentTypes; + List argumentTypes = checkValueArgumentTypes(context, resolvedCall, resolvedCall.getTrace(), + RESOLVE_FUNCTION_ARGUMENTS).argumentTypes; JetType receiverType = resolvedCall.getReceiverArgument().exists() ? resolvedCall.getReceiverArgument().getType() : null; context.tracing.typeInferenceFailed(resolvedCall.getTrace(), InferenceErrorData @@ -232,7 +235,7 @@ public class CandidateResolver { resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor()); // Here we type check the arguments with inferred types expected - checkAllValueArguments(context); + checkAllValueArguments(context, RESOLVE_FUNCTION_ARGUMENTS); checkBounds(resolvedCall, constraintSystem, resolvedCall.getTrace(), context.tracing); resolvedCall.setHasUnknownTypeParameters(false); @@ -280,7 +283,7 @@ public class CandidateResolver { // We'll type check the arguments later, with the inferred types expected boolean[] isErrorType = new boolean[1]; addConstraintForValueArgument(valueArgument, valueParameterDescriptor, substituteDontCare, constraintsSystem, - context, isErrorType); + context, isErrorType, SKIP_FUNCTION_ARGUMENTS); if (isErrorType[0]) { candidateCall.argumentHasNoType(); } @@ -314,7 +317,7 @@ public class CandidateResolver { candidateCall.setHasUnknownTypeParameters(true); return SUCCESS; } - ValueArgumentsCheckingResult checkingResult = checkAllValueArguments(context); + ValueArgumentsCheckingResult checkingResult = checkAllValueArguments(context, SKIP_FUNCTION_ARGUMENTS); ResolutionStatus argumentsStatus = checkingResult.status; List argumentTypes = checkingResult.argumentTypes; JetType receiverType = candidateCall.getReceiverArgument().exists() ? candidateCall.getReceiverArgument().getType() : null; @@ -335,31 +338,28 @@ public class CandidateResolver { @NotNull TypeSubstitutor substitutor, @NotNull ConstraintSystem constraintSystem, @NotNull ResolutionContext context, - @Nullable boolean[] isErrorType) { + @Nullable boolean[] isErrorType, + @NotNull ResolveMode resolveFunctionArgumentBodies) { JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument); JetExpression argumentExpression = valueArgument.getArgumentExpression(); - JetType type; - if (argumentExpression != null) { - TemporaryBindingTrace traceForUnknown = TemporaryBindingTrace.create( - context.trace, "transient trace to resolve argument", argumentExpression); - type = expressionTypingServices.getType(context.scope, argumentExpression, - substitutor.substitute(effectiveExpectedType, Variance.INVARIANT), context.dataFlowInfo, traceForUnknown); - } - else { - type = null; - } + TemporaryBindingTrace traceForUnknown = TemporaryBindingTrace.create( + context.trace, "transient trace to resolve argument", argumentExpression); + JetType expectedType = substitutor.substitute(effectiveExpectedType, Variance.INVARIANT); + JetType type = argumentTypeResolver.getArgumentTypeInfo(argumentExpression, traceForUnknown, context.scope, context.dataFlowInfo, + expectedType != null ? expectedType : NO_EXPECTED_TYPE, resolveFunctionArgumentBodies).getType(); constraintSystem.addSubtypeConstraint(effectiveExpectedType, type, ConstraintPosition.getValueParameterPosition( valueParameterDescriptor.getIndex())); - //todo no return if (isErrorType != null) { isErrorType[0] = type == null || ErrorUtils.isErrorType(type); } } - private ValueArgumentsCheckingResult checkAllValueArguments(CallResolutionContext context) { + private ValueArgumentsCheckingResult checkAllValueArguments( + @NotNull CallResolutionContext context, + @NotNull ResolveMode resolveFunctionArgumentBodies) { ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes(context, context.candidateCall, - context.candidateCall.getTrace()); + context.candidateCall.getTrace(), resolveFunctionArgumentBodies); ResolutionStatus resultStatus = checkingResult.status; ResolvedCall candidateCall = context.candidateCall; @@ -381,7 +381,8 @@ public class CandidateResolver { private ValueArgumentsCheckingResult checkValueArgumentTypes( @NotNull ResolutionContext context, @NotNull ResolvedCallImpl candidateCall, - @NotNull BindingTrace trace) { + @NotNull BindingTrace trace, + @NotNull ResolveMode resolveFunctionArgumentBodies) { ResolutionStatus resultStatus = SUCCESS; DataFlowInfo dataFlowInfo = context.dataFlowInfo; List argumentTypes = Lists.newArrayList(); @@ -398,17 +399,18 @@ public class CandidateResolver { if (TypeUtils.dependsOnTypeParameters(expectedType, candidateCall.getCandidateDescriptor().getTypeParameters())) { 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(); dataFlowInfo = dataFlowInfo.and(typeInfo.getDataFlowInfo()); - if (type == null || ErrorUtils.isErrorType(type)) { + if (type == null || (ErrorUtils.isErrorType(type) && type != PLACEHOLDER_FUNCTION_TYPE)) { candidateCall.argumentHasNoType(); argumentTypes.add(type); } else { JetType resultingType; - if (expectedType == NO_EXPECTED_TYPE || typeChecker.isSubtypeOf(type, expectedType)) { + if (expectedType == NO_EXPECTED_TYPE || argumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) { resultingType = type; } else { @@ -438,7 +440,7 @@ public class CandidateResolver { List variants = AutoCastUtils.getAutoCastVariants(trace.getBindingContext(), dataFlowInfo, receiverToCast); for (ReceiverValue receiverValue : variants) { JetType possibleType = receiverValue.getType(); - if (typeChecker.isSubtypeOf(possibleType, expectedType)) { + if (argumentTypeResolver.isSubtypeOfForArgumentType(possibleType, expectedType)) { return possibleType; } } @@ -467,7 +469,7 @@ public class CandidateResolver { : receiverArgumentType; if (!TypeUtils.dependsOnTypeParameters(receiverParameter.getType(), candidateCall.getCandidateDescriptor().getTypeParameters()) && - !typeChecker.isSubtypeOf(effectiveReceiverArgumentType, receiverParameter.getType())) { + !argumentTypeResolver.isSubtypeOfForArgumentType(effectiveReceiverArgumentType, receiverParameter.getType())) { context.tracing.wrongReceiverType(context.candidateCall.getTrace(), receiverParameter, receiverArgument); result = OTHER_ERROR; } diff --git a/compiler/testData/diagnostics/tests/Varargs.kt b/compiler/testData/diagnostics/tests/Varargs.kt index 8a00695b93c..bbc7b0d12c7 100644 --- a/compiler/testData/diagnostics/tests/Varargs.kt +++ b/compiler/testData/diagnostics/tests/Varargs.kt @@ -12,6 +12,6 @@ fun test() { v1({}, {}) v1({}, 1, {}) v1({}, {}, {it}) - v1({}) {} + v1({}) {} v1 {} } diff --git a/compiler/testData/diagnostics/tests/resolve/resolveWithFunctionLiterals.kt b/compiler/testData/diagnostics/tests/resolve/resolveWithFunctionLiterals.kt new file mode 100644 index 00000000000..31e257faed9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/resolveWithFunctionLiterals.kt @@ -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 + } + } + } + } + } +} diff --git a/compiler/testData/diagnostics/tests/resolve/resolveWithFunctionLiteralsOverload.kt b/compiler/testData/diagnostics/tests/resolve/resolveWithFunctionLiteralsOverload.kt new file mode 100644 index 00000000000..c1f67d471c5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/resolveWithFunctionLiteralsOverload.kt @@ -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 + } + } + } + } + } +} diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 086434a3b1b..b46713445c5 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -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); } + @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") public void testResolveWithGenerics() throws Exception { doTest("compiler/testData/diagnostics/tests/resolve/resolveWithGenerics.kt");